From aeb429c066fec555512e23abb04d5cfd962863bc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 05:45:38 -0500 Subject: [PATCH 01/45] Type empty array literals by their slots, and report package diagnostics accurately - An empty `[]` whose own type is `never[]` (a `return []` in an async function, whose contextual type is `T[] | PromiseLike`, or an object literal's `files: []` field) builds as the unit-only element array, like the empty tuple, so typed array slots receive it through the checked empty-array lift. It was `number[]`, so `string[]` slots refused it with SC1090 or SC2002. - The refusal "instanceof against this native constructor" names its site, and coverage lists the sites whose right-hand side is `Object` or `Function`, which always reach it. An arrow function or method on the right of an untyped `instanceof` throws Node's "Function has non-object prototype" TypeError for an object. - Coverage lists the diagnostics of a function whose signature did not compile. A use of a parameter whose type did not compile reports SC2004. - Coverage lists deferred fences in a module's top-level code under "runs at startup", and the diagnostics envelope marks them `startup: true`. --- docs/content/docs/coverage.mdx | 8 +- docs/content/docs/dependencies.mdx | 2 +- .../compiler/src/backend/llvm/lib-shared.ts | 2 +- packages/compiler/src/coverage/report.ts | 17 ++++- .../compiler/src/diagnostics/diagnostic.ts | 4 + packages/compiler/src/diagnostics/envelope.ts | 4 + .../frontend/lowering/class-construction.ts | 19 ++++- .../lowering/expressions/array-literals.ts | 21 ++++++ .../lowering/expressions/relational.ts | 31 +++++++- .../src/frontend/lowering/lower-functions.ts | 75 +++++++++++++++++++ .../src/frontend/lowering/lower-modules.ts | 34 +++++++++ .../compiler/src/frontend/lowering/lowerer.ts | 20 ++++- packages/compiler/src/frontend/type-mapper.ts | 21 ++++++ .../compiler/src/ir/builtin-signatures.ts | 2 +- .../main.ts.json | 6 ++ .../main.ts.json | 6 ++ packages/runtime/src/scr_dyn.h | 1 + packages/runtime/src/scr_json.c | 22 +++++- .../7002-empty-array-contextual-slots/main.ts | 58 ++++++++++++++ .../7005-dyn-constructor-instanceof/main.ts | 11 +++ .../node_modules/tag-types/index.d.ts | 4 + .../node_modules/tag-types/index.js | 61 +++++++++++++++ .../node_modules/tag-types/package.json | 1 + .../blocked-signature-body.ts | 15 ++++ tests/coverage-fixtures/startup-fences.js | 9 +++ .../coverage-js-builtin-callable-alias.txt | 2 +- .../main.ts.json | 1 + .../main.ts.json | 1 + tests/harness/coverage.test.ts | 47 ++++++++++++ 29 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7002-empty-array-contextual-slots/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7005-dyn-constructor-instanceof/main.ts.json create mode 100644 tests/corpus/7002-empty-array-contextual-slots/main.ts create mode 100644 tests/corpus/7005-dyn-constructor-instanceof/main.ts create mode 100644 tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts create mode 100644 tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js create mode 100644 tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/package.json create mode 100644 tests/coverage-fixtures/blocked-signature-body.ts create mode 100644 tests/coverage-fixtures/startup-fences.js create mode 100644 tests/harness/corpus-costs/7002-empty-array-contextual-slots/main.ts.json create mode 100644 tests/harness/corpus-costs/7005-dyn-constructor-instanceof/main.ts.json diff --git a/docs/content/docs/coverage.mdx b/docs/content/docs/coverage.mdx index ae36f736d..954b040db 100644 --- a/docs/content/docs/coverage.mdx +++ b/docs/content/docs/coverage.mdx @@ -38,6 +38,8 @@ When a program has unsupported operations, the report adds a group for each root compile staticallyStatements that compile to native instructions. in dynamic tierOf those, the statements in functions that operate on values typed only at runtime, such as any values and untyped JavaScript. Shown when there are any. See Dynamic tier. blockersUnsupported operations with counts, diagnostic codes, reasons, locations, and hints. + runs at startupDeferred operations in a JavaScript module's top-level code, which runs when the module loads: at startup for a module the program imports. + deferred to runtimeOther deferred operations in JavaScript code. Each throws only if it runs. in unreached codeBlockers in code the entry never reaches. A build never compiles that code, so these cannot fail it. differs from NodeSites that compile but can behave differently from Node.js. See Node divergences. npm package compilationNative package compilation outcomes and refusal reasons. @@ -46,7 +48,7 @@ When a program has unsupported operations, the report adds a group for each root Blockers in unreached code and deferred operations in JavaScript packages are listed separately because they don't fail a build. A deferred operation throws a runtime error if it runs, so a successful build doesn't mean every API of a package works; see [unsupported code inside a package](/docs/dependencies#unsupported-code-inside-a-package). -If a function's signature can't compile, the statements in its body count as not compiling, so the percentage reflects how much of the program compiles. +If a function's signature can't compile, the statements in its body count as not compiling, so the percentage reflects how much of the program compiles. The report still lists the diagnostics of those statements; a use of a parameter whose type can't compile reports `SC2004` back to the signature. @@ -211,6 +213,10 @@ For editors, CI annotations, and other tools, `scriptc coverage --print=diagnost group The id of the root-cause group the diagnostic belongs to. A group's primary site is its first in source order. + + startup + true on a deferred diagnostic in a module's top-level code, which runs when the module loads. Absent otherwise. + diff --git a/docs/content/docs/dependencies.mdx b/docs/content/docs/dependencies.mdx index 85a232bb2..409b9cb30 100644 --- a/docs/content/docs/dependencies.mdx +++ b/docs/content/docs/dependencies.mdx @@ -132,7 +132,7 @@ CommonJS packages compile with Node.js's module semantics. Each `require()` eval ## Unsupported code inside a package -A JavaScript package can contain operations scriptc can't compile, often in functions your program never calls. These don't fail the build: each one compiles to code that throws a runtime error if it ever runs. Coverage reports list them as deferred sites, so review the list and test the parts of the package your program uses. +A JavaScript package can contain operations scriptc can't compile, often in functions your program never calls. These don't fail the build: each one compiles to code that throws a runtime error if it ever runs. Coverage reports list them as deferred sites, so review the list and test the parts of the package your program uses. Sites in a module's top-level code are listed under `runs at startup`: that code runs when the module loads, at startup for a module the program imports. ## Provenance sources (experimental) diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index c08d7b720..453392243 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -47,7 +47,7 @@ export const LIB_FN_SYMS: Record = { "dyn.fromEntries": "scr_dyn_from_entries", "bytes.constructor": "scr_bytes_constructor", "bytes.construct": "scr_bytes_construct", - "bytes.instanceOf": "scr_bytes_instanceof", + "bytes.instanceOf": "scr_bytes_instanceof_at", "arrayBuffer.constructor": "scr_array_buffer_constructor", "sharedArrayBuffer.new": "scr_shared_array_buffer_new", "sharedArrayBuffer.is": "scr_shared_array_buffer_is", diff --git a/packages/compiler/src/coverage/report.ts b/packages/compiler/src/coverage/report.ts index 37f77f4c6..79017c97a 100644 --- a/packages/compiler/src/coverage/report.ts +++ b/packages/compiler/src/coverage/report.ts @@ -318,12 +318,23 @@ export function renderCoverage(input: CoverageInput, opts: CoverageRenderOptions // statements the module carries): they compile, but executing one // throws its SC-coded error — the report lists them so a "compiling" // JS program never hides its dynamic gaps. + // Fences in a module's top-level code run when the module initializes: + // they are listed first, as sites that run at startup. const fences = input.runtimeFences ?? []; - if (fences.length > 0) { + const startup = fences.filter((d) => d.startup === true); + const later = fences.filter((d) => d.startup !== true); + if (startup.length > 0) { out.push( - ` ${c(YELLOW, "deferred to runtime")} ${fences.length} site${fences.length === 1 ? "" : "s"} ${c(DIM, "(JS statements that throw their fence if executed)")}`, + ` ${c(YELLOW, "runs at startup")} ${startup.length} site${startup.length === 1 ? "" : "s"} ${c(DIM, "(JS statements in module top-level code, which runs when the module loads)")}`, ); - renderRows(groupBlockers(fences, "deferred"), YELLOW); + renderRows(groupBlockers(startup, "deferred"), YELLOW); + out.push(""); + } + if (later.length > 0) { + out.push( + ` ${c(YELLOW, "deferred to runtime")} ${later.length} site${later.length === 1 ? "" : "s"} ${c(DIM, "(JS statements that throw their fence if executed)")}`, + ); + renderRows(groupBlockers(later, "deferred"), YELLOW); out.push(""); } diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index 17cb2efc0..625ee93af 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -92,6 +92,10 @@ export interface ScrDiagnostic { * the error may not reproduce under the project's tsc. Machine-readable * output reports these under the "environment" category. */ typeWorld?: boolean; + /** A runtime fence in a module's top-level code, outside every function + * and class member body: it throws when the module initializes, which is + * program startup for a module the entry imports. */ + startup?: true; } /** SC3002–SC3004 — native-helper target, installation, and execution diff --git a/packages/compiler/src/diagnostics/envelope.ts b/packages/compiler/src/diagnostics/envelope.ts index 59c285ead..b4de8db77 100644 --- a/packages/compiler/src/diagnostics/envelope.ts +++ b/packages/compiler/src/diagnostics/envelope.ts @@ -67,6 +67,9 @@ export interface LocatedDiagnostic extends SourcePosition { hint: string; /** The id of the root-cause group this site belongs to. */ group: string; + /** Deferred scope only: the statement is module top-level code, so it + * runs when its module loads. */ + startup?: true; } export interface DiagnosticGroup { @@ -290,6 +293,7 @@ export function locateDiagnostic( message: diag.message, hint: hintOf(diag), group: groupId(diag, scope), + ...(scope === "deferred" && diag.startup === true ? { startup: true as const } : {}), }; } diff --git a/packages/compiler/src/frontend/lowering/class-construction.ts b/packages/compiler/src/frontend/lowering/class-construction.ts index 30f504b4a..398029474 100644 --- a/packages/compiler/src/frontend/lowering/class-construction.ts +++ b/packages/compiler/src/frontend/lowering/class-construction.ts @@ -24,16 +24,21 @@ const PREFIX = "%class.construct:"; const PACKED = `${PREFIX}packed`; const INSTANCEOF = "%class.instanceof:dynamic"; +/** `value instanceof callee` for an untyped constructor value, through one + * shared helper. `refusal` is the site's message for a runtime + * constructor with no instance test. */ export function checkedClassInstanceOf( lowerer: Lowerer, value: IrExpr, callee: IrExpr, + refusal: string, loc: SrcLoc, ): IrExpr { if (!lowerer.liftedFns.some((fn) => fn.name === INSTANCEOF)) { const params = [ { localId: "value", name: "value", type: DYN }, { localId: "callee", name: "callee", type: DYN }, + { localId: "refusal", name: "refusal", type: STRING }, ]; lowerer.liftedFns.push({ name: INSTANCEOF, @@ -46,7 +51,11 @@ export function checkedClassInstanceOf( value: { kind: "libCall", fn: "bytes.instanceOf", - args: [varRef("value", DYN, loc), varRef("callee", DYN, loc)], + args: [ + varRef("value", DYN, loc), + varRef("callee", DYN, loc), + varRef("refusal", STRING, loc), + ], type: BOOL, loc, }, @@ -56,7 +65,13 @@ export function checkedClassInstanceOf( loc, }); } - return { kind: "call", callee: INSTANCEOF, args: [value, callee], type: BOOL, loc }; + return { + kind: "call", + callee: INSTANCEOF, + args: [value, callee, { kind: "strLit", value: refusal, type: STRING, loc }], + type: BOOL, + loc, + }; } /** Checked construction dispatches to emitted native constructor thunks. */ diff --git a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts index 8f119504c..cb2d86804 100644 --- a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts @@ -58,6 +58,22 @@ export function jsHoldsDynObject(lowerer: Lowerer, expr: ts.Expression): boolean return false; } +/** An empty TypeScript literal whose own type is `never[]`: tsc's type for + * `[]` with no contextual array type (`return []` in an async function, + * whose contextual type is `string[] | PromiseLike`; `{ files: [] }`). + * It holds no element, as the empty tuple does, so it builds as the + * unit-only element array, and an array slot receives it through the + * checked empty-array lift. never's f64 element mapping would make it a + * `number[]`, which no `string[]` slot accepts. */ +function emptyNeverLiteral(lowerer: Lowerer, expr: ts.ArrayLiteralExpression): boolean { + if (expr.elements.nodes.length > 0 || isJsSourceFile(ts.getSourceFileOfNode(expr))) return false; + const own = lowerer.typeOf(expr); + return ( + lowerer.checker.isArrayType(own) && + (lowerer.checker.getTypeArguments(own as ts.TypeReference)[0]!.flags & ts.TypeFlags.Never) !== 0 + ); +} + /** `[a, b, c]`. The element type comes from the contextual type when tsc * has one (`const a: number[] = []`, arguments, nested literals) and from * the literal's own inferred type otherwise. A bare `[]` with no context @@ -80,6 +96,8 @@ export function lowerArrayLiteral( ? lowerer.typeOf(expr) : (ctxType ?? lowerer.typeOf(expr)); let mapped = expected ?? lowerer.mapTypeOf(tsType); + if (expected === undefined && ctxType === undefined && emptyNeverLiteral(lowerer, expr)) + mapped = arrayOf(unitOnlyUnion(lowerer.unions)); // Inferred JavaScript arrays can contain unrelated constructors with // structurally equal checker types. Their native class ABIs still differ. if ( @@ -131,11 +149,14 @@ export function lowerArrayLiteral( // the literal's own inferred type is the real tuple. if (!mapped || mapped.kind === "union" || mapped.kind === "dyn") { const ctxUnion = mapped?.kind === "union" ? mapped : null; + const ctxUnmapped = mapped === null; mapped = lowerer.mapTypeOf(lowerer.typeOf(expr)); // The never-tainted own type carries no element information here // either (the JS story above) — only a contextual union's single // array arm below may still supply a static home. if (neverTaintedOwnJs) mapped = null; + if (ctxUnmapped && emptyNeverLiteral(lowerer, expr)) + mapped = arrayOf(unitOnlyUnion(lowerer.unions)); // An EMPTY literal in a union slot (`const t: string[] | undefined = // []`, the `[]` default argument against `string[] | undefined`) has // no useful own type — tsc infers `never[]`, whose f64-element diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 61558f008..759687ff0 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -49,6 +49,7 @@ import { InternalCompilerError } from "../../../errors.js"; import { tryLowerExpression } from "./try-lower-expression.js"; import { isJsSourceFile, locOf } from "../../program.js"; import { checkedClassInstanceOf } from "../class-construction.js"; +import { unsupportedDiag } from "../../../diagnostics/diagnostic.js"; import { globalSymbolKey } from "./global-symbols.js"; import { foldedStringKeyOf } from "./object-literals.js"; import { NARROW_FIRST, sideEffectFreeOptionValue } from "../surfaces.js"; @@ -490,7 +491,13 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc const constructor = tryLowerExpression(lowerer, expr.right); if (constructor?.type.kind === "dyn" && isJsSourceFile(ts.getSourceFileOfNode(expr))) { const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); - return checkedClassInstanceOf(lowerer, value, constructor, loc); + return checkedClassInstanceOf( + lowerer, + value, + constructor, + dynInstanceOfRefusal(lowerer, expr), + loc, + ); } // `this instanceof Glob` in a JavaScript constructor function: the // function's prototype against the value's prototype chain. @@ -2000,3 +2007,25 @@ 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. */ +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-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index 653c0d837..ea7d7957b 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -1,3 +1,4 @@ +import type { ScrDiagnostic } from "../../diagnostics/diagnostic.js"; import { declareTypedArguments } from "./typed-arguments.js"; import { dynUndefinedExpr, varRef } from "../../ir/build.js"; import { everyStmtList, transformStmtList } from "../../ir/traverse.js"; @@ -17,6 +18,7 @@ import { type IrLocal, type IrParam, type IrStmt, + type IrType, type SrcLoc, VOID, canBoxFuncIntoDyn, @@ -858,3 +860,76 @@ function isBufferCheckOf(e: IrExpr, slotId: string): boolean { e.type.elem === "u8" ); } + +/** The diagnostics of a TypeScript function whose signature did not + * compile, for the coverage remainder: its statements lower for their + * diagnostics only (the remainder's output is discarded), so the report + * lists them with the signature's blocker instead of hiding them behind it. + * Each parameter whose type maps is declared, and a use of any other + * parameter reports SC2004 back to the declaration. The statements already + * count as failed (countSkippedBody), so the pass leaves the stats alone. + * The pass adds diagnostics only: an internal error while it lowers drops + * what it found, and the signature's blocker stands alone as before. */ +export function blockedBodyDiagnostics( + lowerer: Lowerer, + decl: ts.FunctionDeclaration, +): ScrDiagnostic[] { + const body = decl.body; + if (!body || decl.typeParameters || decl.asteriskToken) return []; + if (isJsSourceFile(ts.getSourceFileOfNode(decl))) return []; + const symbol = declSymbolOf(lowerer, decl); + if (!symbol || lowerer.fnSigsBySymbol.has(symbol)) return []; + const diagsBefore = lowerer.diags.length; + const fencesBefore = lowerer.runtimeFences.length; + const suppressStats = lowerer.suppressStats; + lowerer.suppressStats = true; + let declared: IrType = DYN; + lowersCleanly(lowerer, () => { + declared = lowerer.declaredReturnType(decl, decl); + }); + const isAsync = decl.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false; + const ctx = newFnCtx(false, null, null, lowerer.bodyReturnType(isAsync, declared)); + ctx.isAsync = isAsync; + lowerer.fnStack.push(ctx); + let internal = false; + try { + for (const param of decl.parameters.nodes) { + if (isThisParameter(param)) continue; + const declaredParam = lowersCleanly(lowerer, () => { + lowerer.declareParams([param], lowerer.paramShapes([param])); + }); + if (declaredParam) continue; + const symbol = ts.isIdentifier(param.name) + ? lowerer.checker.getSymbolAtLocation(param.name) + : undefined; + if (symbol) lowerer.blockedBindings.add(symbol); + } + lowersCleanly(lowerer, () => { + lowerer.lowerStmts(body.statements.nodes); + }); + } catch (error) { + if (!(error instanceof InternalCompilerError)) throw error; + internal = true; + } finally { + lowerer.fnStack.pop(); + lowerer.suppressStats = suppressStats; + } + lowerer.runtimeFences.splice(fencesBefore); + const diags = lowerer.diags.splice(diagsBefore); + return internal || diags.some((d) => d.code === "SC9001") ? [] : diags; +} + +/** Runs `lower`, for blockedBodyDiagnostics: false when it poisons, with the + * diagnostics it recorded dropped (a failed mapping reports what the + * signature's blocker already reports). */ +function lowersCleanly(lowerer: Lowerer, lower: () => void): boolean { + const before = lowerer.diags.length; + try { + lower(); + return true; + } catch (error) { + if (!(error instanceof PoisonError)) throw error; + lowerer.diags.splice(before); + return false; + } +} diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 5b78c7278..5238333ad 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -2929,6 +2929,38 @@ export function lowerDefaultExport(lowerer: Lowerer, stmt: ts.ExportAssignment): return { kind: "assign", localId: g.id, value, loc: locOf(stmt) }; } +/** Marks the runtime fences recorded since `fencesBefore` that lie in + * `sf`'s top-level code: they run when the module initializes. A fence + * inside a function, or inside a class member that runs later (a method, + * accessor, constructor or instance field initializer), runs when that + * code is called. */ +function markModuleInitFences(lowerer: Lowerer, sf: ts.SourceFile, fencesBefore: number): void { + for (let i = fencesBefore; i < lowerer.runtimeFences.length; i++) { + const fence = lowerer.runtimeFences[i]!; + if (fence.loc.file !== sf.fileName || runsAfterModuleInit(sf, fence.loc.start)) continue; + lowerer.runtimeFences[i] = { ...fence, startup: true }; + } +} + +/** Whether the code at `pos` sits in a function or a later-running class + * member body. */ +function runsAfterModuleInit(sf: ts.SourceFile, pos: number): boolean { + let later = false; + ts.walkPreorder(sf, (node) => { + if (node.pos > pos || node.end <= pos) return "skip"; + if ( + ts.isFunctionLike(node) || + (ts.isPropertyDeclaration(node) && + !node.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.StaticKeyword)) + ) { + later = true; + return "stop"; + } + return undefined; + }); + return later; +} + export function lowerFileInit( lowerer: Lowerer, sf: ts.SourceFile, @@ -2938,6 +2970,7 @@ export function lowerFileInit( const isAsync = lowerer.asyncInitFiles.has(sf); const ctx = newFnCtx(false, null, null, VOID); ctx.isAsync = isAsync; + const fencesBefore = lowerer.runtimeFences.length; lowerer.fnStack.push(ctx); try { const loc0: SrcLoc = { file: sf.fileName, start: 0, end: 0 }; @@ -3288,6 +3321,7 @@ export function lowerFileInit( }; } finally { lowerer.fnStack.pop(); + markModuleInitFences(lowerer, sf, fencesBefore); } } diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index edf0a694b..7838213b2 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -444,6 +444,7 @@ import { lowerNestedFunctionDecl, lowerLambda, lowerFunction, + blockedBodyDiagnostics, } from "./lower-functions.js"; import { lowerArrayMethodCall } from "./containers/array-methods.js"; import { type ArrayHofInfo, fuseArrayPipelines } from "./containers/array-pipelines.js"; @@ -1346,6 +1347,7 @@ export function lowerToIr( // travel with them: a failed statement is never left unexplained. const covered: LowerResult = { ...result, + diagnostics: [...result.diagnostics, ...remainder.reachedBlockedBodyDiagnostics], stats: { ...result.stats, statementsDynamic }, unreached: { diagnostics: rem.diagnostics, @@ -7437,7 +7439,10 @@ export class Lowerer { if (sig && !this.wantBody(sig.name)) continue; const fn = this.lowerFunction(decl); if (fn) functions.push(fn); - else if (this.countsSkips()) this.countSkippedBody(decl); + else if (this.countsSkips()) { + this.countSkippedBody(decl); + if (this.remainder) this.reportBlockedBody(decl); + } } for (const decl of fp.classDecls) { const info = this.classes.get(this.classNamer(decl)); @@ -7768,6 +7773,19 @@ export class Lowerer { } } + /** Coverage remainder: the body diagnostics of a function whose + * signature blocked (blockedBodyDiagnostics). A function reachable emit + * reached (its signature's diagnostics flushed there) reports them with + * the reached diagnostics; any other reports them as unreached. */ + readonly reachedBlockedBodyDiagnostics: ScrDiagnostic[] = []; + private reportBlockedBody(decl: ts.FunctionDeclaration): void { + const diags = blockedBodyDiagnostics(this, decl); + const symbol = declSymbolOf(this, decl); + if (symbol && this.alreadyFlushed.has(symbol)) + this.reachedBlockedBodyDiagnostics.push(...diags); + else for (const d of diags) this.pushDiag(d); + } + /** Whether run() counts a signature-blocked declaration in * stats.functionsSkipped: whole-program passes and the coverage * remainder do; an externally-gated emit pass leaves the counting to the diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 9abd5a0b0..93349054a 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -5731,6 +5731,19 @@ function constAssertedEmptyArrayProp(p: ts.Symbol): boolean { return underConstAssertion(d); } +/** A TypeScript property assignment `name: []` whose type is `never[]`. */ +function emptyNeverArrayProp(p: ts.Symbol, fieldTs: ts.Type, checker: ts.TypeChecker): boolean { + const d = p.valueDeclaration; + if (d === undefined || !ts.isPropertyAssignment(d)) return false; + if (isJsSourceFile(ts.getSourceFileOfNode(d))) return false; + if (!ts.isArrayLiteralExpression(d.initializer) || d.initializer.elements.nodes.length > 0) + return false; + return ( + checker.isArrayType(fieldTs) && + (checker.getTypeArguments(fieldTs as ts.TypeReference)[0]!.flags & ts.TypeFlags.Never) !== 0 + ); +} + function mapGenericAwaitedAlias(type: ts.Type, ctx: TypeMapperCtx): IrType | null { const { resolveTypeParam } = ctx; if (!resolveTypeParam) return null; @@ -7767,6 +7780,14 @@ function mapRecordTypeInner( ) { pt = arrayOf(unitOnlyUnion(ctx.unions)); } + // A TypeScript property initialized with an empty literal and typed + // `never[]` (`const out = { files: [] }`) holds no element, so it maps + // like the empty tuple: the unit-only element array, which a + // destination's typed array field (`files: string[]`) receives through + // the checked empty-array lift. never's f64 element would make it a + // `number[]` field. + if (pt?.kind === "array" && emptyNeverArrayProp(p, fieldTs, checker)) + pt = arrayOf(unitOnlyUnion(ctx.unions)); if (pt === null && (fieldTs.flags & ts.TypeFlags.Any) !== 0) pt = DYN; // An `any[]` field (`list: any[]` in an SDK's message type, also // optional or nullable) is the checked-dynamic array, exactly as diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 8f5928d12..70ec7d502 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3570,7 +3570,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "weakSet.new": { argTypes: [DYN], result: DYN }, "dyn.fromEntries": { argTypes: [DYN], result: DYN }, "bytes.constructor": { argTypes: [STRING], result: DYN }, - "bytes.instanceOf": { argTypes: [DYN, DYN], result: BOOL }, + "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 diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7002-empty-array-contextual-slots/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7002-empty-array-contextual-slots/main.ts.json new file mode 100644 index 000000000..d22715215 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7002-empty-array-contextual-slots/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7002-empty-array-contextual-slots/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7005-dyn-constructor-instanceof/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7005-dyn-constructor-instanceof/main.ts.json new file mode 100644 index 000000000..313888b49 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7005-dyn-constructor-instanceof/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7005-dyn-constructor-instanceof/main.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index a427fc9a1..95f251bd4 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -868,6 +868,7 @@ void scr_dyn_proxy_unsupported(const char *operation); ScrDyn *scr_dyn_new_bytes(const ScrBytes *b); ScrDyn *scr_bytes_constructor(const ScrStr *name); bool scr_bytes_instanceof(const ScrDyn *value, const ScrDyn *callee); +bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const ScrStr *refusal); bool scr_dyn_data_view_is(const ScrDyn *value); ScrDyn *scr_dyn_construct(const ScrDyn *callee, const ScrDyn *args, const ScrStr *what); ScrDyn *scr_bytes_construct(const ScrDyn *callee, const ScrDyn *args, const ScrStr *what); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 4e21fa397..906be0ccd 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3920,7 +3920,10 @@ static int scr_dyn_global_constructor_instanceof(const ScrDyn *value, const ScrD return -1; } -bool scr_bytes_instanceof(const ScrDyn *value, const ScrDyn *callee) { +/* `value instanceof callee` for an untyped constructor value. `refusal`, when + * given, is the site's SC1090 message for a runtime constructor with no + * instance test. */ +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"; scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); @@ -3962,12 +3965,29 @@ bool scr_bytes_instanceof(const ScrDyn *value, const ScrDyn *callee) { scr_dyn_release(prototype); return found; } + bool undefined_prototype = prototype->kind == SCR_DYN_UNDEF; scr_dyn_release(prototype); + /* A function the program compiled with no prototype (an arrow function + * or a method): Node's TypeError for an object, false for a primitive. + * The runtime's own constructors carry "native:" signatures. */ + if (undefined_prototype && (!callee->v.fn.sig || strncmp(callee->v.fn.sig, "native:", 7) != 0)) { + if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_ARR && value->kind != SCR_DYN_FUNC) return false; + static const char message[] = "Function has non-object prototype 'undefined' in instanceof check"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + return false; + } + } + if (refusal) { + scr_throw_error_msg_code(SCR_ERR_ERROR, refusal->data, refusal->len, "SC1090"); + return false; } static const char message[] = "instanceof against this native constructor is not supported yet"; scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC1090"); return false; } +bool scr_bytes_instanceof(const ScrDyn *value, const ScrDyn *callee) { + return scr_bytes_instanceof_at(value, callee, NULL); +} ScrDyn *scr_bytes_construct(const ScrDyn *callee, const ScrDyn *args, const ScrStr *what) { if (callee->kind == SCR_DYN_FUNC && scr_array_ctor && callee->v.fn.clo == scr_array_ctor->v.fn.clo) return scr_array_ctor_call(callee->v.fn.clo, args->v.arr.items, args->v.arr.len); diff --git a/tests/corpus/7002-empty-array-contextual-slots/main.ts b/tests/corpus/7002-empty-array-contextual-slots/main.ts new file mode 100644 index 000000000..ec08a297a --- /dev/null +++ b/tests/corpus/7002-empty-array-contextual-slots/main.ts @@ -0,0 +1,58 @@ +// Empty array literals whose own type is `never[]`: `return []` in an async +// function (its contextual type is `string[] | PromiseLike`) and +// an object literal's `files: []` field returned or passed where typed +// arrays are declared. Each value holds the declared element type. +interface Listing { + files: string[]; + sizes: number[]; +} + +async function readNames(text: string): Promise { + try { + return JSON.parse(text) as string[]; + } catch { + return []; + } +} + +const loadIds = async (fail: boolean): Promise => { + if (fail) return []; + return [1, 2]; +}; + +function emptyListing(): Listing { + const listing = { files: [], sizes: [] }; + return listing; +} + +function index(): Record<"files" | "dirs", string[]> { + const out = { files: [], dirs: [] }; + return out; +} + +function total(listing: Listing): number { + return listing.sizes.reduce((sum, size) => sum + size, 0); +} + +async function main(): Promise { + const names = await readNames("not json"); + names.push("fallback"); + console.log(names, (await readNames('["a","b"]')).join("+")); + const ids = await loadIds(true); + ids.push(7); + console.log(ids, await loadIds(false)); + + const listing = emptyListing(); + listing.files.push("a.txt"); + listing.sizes.push(3, 4); + console.log(listing, total(listing)); + + const dirs = index(); + dirs.dirs.push("src"); + console.log(JSON.stringify(dirs), dirs.files.length); + + const blank = { files: [], sizes: [] }; + console.log(total(blank), JSON.stringify(blank)); +} + +main(); diff --git a/tests/corpus/7005-dyn-constructor-instanceof/main.ts b/tests/corpus/7005-dyn-constructor-instanceof/main.ts new file mode 100644 index 000000000..c32a820c2 --- /dev/null +++ b/tests/corpus/7005-dyn-constructor-instanceof/main.ts @@ -0,0 +1,11 @@ +// A package's own functions, read off an object the checker cannot type, +// on the right of `instanceof`: Node walks the value's prototype chain for +// an ES5 constructor's prototype, at module load and in calls, and throws a +// TypeError for an arrow function, which has no prototype, when the value +// is an object. +import { arrowCheck, describe, rejects, tags } from "tag-types"; + +console.log(tags()); +console.log(describe("{}"), describe("[1]"), describe("null"), describe('"s"')); +console.log(rejects('{"tag":"!x"}')); +console.log(arrowCheck("{}"), arrowCheck("1")); diff --git a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts new file mode 100644 index 000000000..adeea728e --- /dev/null +++ b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts @@ -0,0 +1,4 @@ +export declare function describe(json: string): string; +export declare function tags(): string; +export declare function rejects(json: string): string; +export declare function arrowCheck(json: string): string; diff --git a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js new file mode 100644 index 000000000..20eee362f --- /dev/null +++ b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js @@ -0,0 +1,61 @@ +"use strict"; +// A bundler's lazy module object holding an ES5 constructor: the checker +// cannot type the object, so the constructor is an untyped value where +// `instanceof` tests it. +var types = {}; +var hasTypes; +function requireTypes() { + if (hasTypes) return types; + hasTypes = 1; + function Type(tag, options) { + this.tag = tag; + this.kind = (options && options.kind) || "scalar"; + } + function Schema(list) { + this.list = list; + } + types.Type = Type; + types.Schema = Schema; + types.make = (tag) => new Type(tag); + return types; +} +var loaded = requireTypes(); +var Type = loaded.Type; +var Schema = loaded.Schema; +var make = loaded.make; + +function compileList(list) { + var tags = []; + list.forEach(function (item) { + if (!(item instanceof Type)) throw new Error("not a Type: " + JSON.stringify(item)); + tags.push(item.tag + ":" + item.kind); + }); + return tags; +} +// Runs when the module loads, as js-yaml's default schema does. +var defaults = new Schema(compileList([new Type("!str"), new Type("!seq", { kind: "sequence" })])); + +module.exports.describe = function (json) { + var value = JSON.parse(json); + return [value instanceof Type, value instanceof Schema, defaults instanceof Schema, defaults instanceof Type].join(","); +}; +module.exports.tags = function () { + return defaults.list.join(" "); +}; +function rejects(json) { + try { + compileList([JSON.parse(json)]); + return "accepted"; + } catch (error) { + return error.message; + } +} +module.exports.rejects = rejects; +// An arrow function has no prototype: Node throws a TypeError for an object. +module.exports.arrowCheck = function (json) { + try { + return String(JSON.parse(json) instanceof make); + } catch (error) { + return error.name + ": " + error.message; + } +}; diff --git a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/package.json b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/package.json new file mode 100644 index 000000000..a469a45f3 --- /dev/null +++ b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/package.json @@ -0,0 +1 @@ +{ "name": "tag-types", "version": "1.0.0", "main": "./index.js", "types": "./index.d.ts" } diff --git a/tests/coverage-fixtures/blocked-signature-body.ts b/tests/coverage-fixtures/blocked-signature-body.ts new file mode 100644 index 000000000..7f8db4eb8 --- /dev/null +++ b/tests/coverage-fixtures/blocked-signature-body.ts @@ -0,0 +1,15 @@ +// Functions whose signatures cannot compile: the report still lists what +// their bodies would report. A use of the blocked parameter names the +// declaration; the body's own unsupported statement reports itself, with +// the reached diagnostics for a function the entry calls and as unreached +// for one nothing calls. +function measure(target: WeakRef, label: string): number { + const extra = new WeakRef({ label }); + console.log(target); + return label.length + (extra === undefined ? 0 : 1); +} +function unused(target: WeakRef): number { + const extra = new WeakRef({ target }); + return extra === undefined ? 0 : 1; +} +console.log(measure(new WeakRef({}), "abc")); diff --git a/tests/coverage-fixtures/startup-fences.js b/tests/coverage-fixtures/startup-fences.js new file mode 100644 index 000000000..22aad4e0a --- /dev/null +++ b/tests/coverage-fixtures/startup-fences.js @@ -0,0 +1,9 @@ +// Deferred fences in a module's top-level code run when the module loads; +// a fence inside a function runs when the function is called. +"use strict"; +var value = JSON.parse("{}"); +console.log(value instanceof Object); +function check(other) { + return other instanceof Object; +} +console.log(check([])); diff --git a/tests/harness/__snapshots__/coverage-js-builtin-callable-alias.txt b/tests/harness/__snapshots__/coverage-js-builtin-callable-alias.txt index 53eac6c3c..6291c291f 100644 --- a/tests/harness/__snapshots__/coverage-js-builtin-callable-alias.txt +++ b/tests/harness/__snapshots__/coverage-js-builtin-callable-alias.txt @@ -3,7 +3,7 @@ scriptc coverage tests/coverage-fixtures/js-builtin-callable-alias.js statements analyzed 3 compile statically 2 (66%) - deferred to runtime 1 site (JS statements that throw their fence if executed) + runs at startup 1 site (JS statements in module top-level code, which runs when the module loads) ×1 SC1090 a builtin function alias as an escaping value (call 'ext' directly) at tests/coverage-fixtures/js-builtin-callable-alias.js:8:13 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) diff --git a/tests/harness/corpus-costs/7002-empty-array-contextual-slots/main.ts.json b/tests/harness/corpus-costs/7002-empty-array-contextual-slots/main.ts.json new file mode 100644 index 000000000..9495bb65c --- /dev/null +++ b/tests/harness/corpus-costs/7002-empty-array-contextual-slots/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2282, "san": 1173 } diff --git a/tests/harness/corpus-costs/7005-dyn-constructor-instanceof/main.ts.json b/tests/harness/corpus-costs/7005-dyn-constructor-instanceof/main.ts.json new file mode 100644 index 000000000..f84e21437 --- /dev/null +++ b/tests/harness/corpus-costs/7005-dyn-constructor-instanceof/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2308, "san": 955 } diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index 86d202b46..40b55b078 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -182,6 +182,53 @@ test("statements of a signature-blocked function count as not static", () => { expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(5); }); +test("the body of a signature-blocked function reports its diagnostics", () => { + const { coverage } = analyze(fixture("blocked-signature-body.ts")); + const sites = (diags: readonly { code: string; message: string }[]) => + diags.map((d) => `${d.code} ${d.message}`).sort(); + // measure is called: its body's diagnostics join the reached ones. + expect(sites(coverage.diagnostics)).toEqual([ + "SC2004 uses of 'extra' inherit the blocker on its declaration", + "SC2004 uses of 'measure' inherit the blocker on its declaration", + "SC2004 uses of 'target' inherit the blocker on its declaration", + "SC2020 'WeakRef' is part of the standard library types but has no scriptc lowering yet", + "SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet", + ]); + // Nothing calls unused: its signature and body report as unreached. + expect(sites(coverage.unreached?.diagnostics ?? [])).toEqual([ + "SC2004 uses of 'extra' inherit the blocker on its declaration", + "SC2020 'WeakRef' is part of the standard library types but has no scriptc lowering yet", + "SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet", + ]); + // The bodies' statements still count once each, as not static. + const un = coverage.unreached?.stats; + expect(coverage.stats.functionsSkipped + (un?.functionsSkipped ?? 0)).toBe(2); + expect(coverage.stats.statementsTotal + (un?.statementsTotal ?? 0)).toBe(6); + expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(6); +}); + +test("deferred fences in a module's top-level code report as running at startup", () => { + const { coverage, sourceTexts } = analyze(fixture("startup-fences.js")); + expect( + (coverage.runtimeFences ?? []).map((d) => [d.code, d.loc.start, d.startup === true]), + ).toEqual([ + ["SC1090", expect.any(Number), true], + ["SC1090", expect.any(Number), false], + ]); + 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/, + ); + 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/, + ); + const envelope = coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts }); + expect(envelope.diagnostics.map((d) => [d.scope, d.line, d.startup])).toEqual([ + ["deferred", 5, true], + ["deferred", 7, undefined], + ]); +}); + test("a failed unreached JavaScript statement is always explained", () => { const { coverage } = analyze(fixture("unreached-js-fence.js")); const failed = From e07f1be5c297a17769d7a2b69dcea17b6f78c2f5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 07:07:34 -0500 Subject: [PATCH 02/45] Keep aliases of evolving empty arrays on the array they alias An unannotated `const xs = []` inside a function takes the element type its reads agree on, and is checked-dynamic when they disagree. An alias taken between two writes of different element types (`const alias = xs` after `xs.push(1)`, before `xs.push("two")`) took the element type the checker gives it at that point, so it held a copy and missed the later writes: Node prints `1,two 2` for `xs.join(","), alias.length`, the compiled program printed `1,two 1`. An unannotated alias of such a binding, and an alias of that alias, now takes the binding's checked-dynamic type, so every name holds the one array. A write that stores a value the agreed element type does not hold (`xs.push("t")` after reads typed `boolean[]`, or `xs[1] = "one"`) now makes the binding checked-dynamic too. Those programs were refused with SC1090 "'string' values where 'boolean' is expected". Fixes #1641. --- .../src/frontend/lowering/lower-stmts.ts | 59 ++++++++++++++-- .../7006-evolving-array-aliases.ts.json | 6 ++ tests/corpus/7006-evolving-array-aliases.ts | 70 +++++++++++++++++++ .../7006-evolving-array-aliases.ts.json | 1 + 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7006-evolving-array-aliases.ts.json create mode 100644 tests/corpus/7006-evolving-array-aliases.ts create mode 100644 tests/harness/corpus-costs/7006-evolving-array-aliases.ts.json diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 213abfec6..29086d326 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -4799,9 +4799,10 @@ export function lowerVarDeclList( * `never[]` or `any[]` and each later read by the elements written before * it, and reads inside closures as the unsettled array. When every read * with a settled element type maps to the same array type, the binding has - * that type. When reads disagree or the binding is reassigned, it is - * checked-dynamic, as the same binding is at module scope. Null for other - * bindings. */ + * that type. When reads disagree, a write (`xs.push(v)`, `xs.unshift(v)`, + * `xs[i] = v`) stores a value that type's element does not hold, or the + * binding is reassigned, it is checked-dynamic, as the same binding is at + * module scope. Null for other bindings. */ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrType | null { if (!ts.isIdentifier(decl.name) || decl.initializer === undefined) return null; let initializer: ts.Expression = decl.initializer; @@ -4823,6 +4824,9 @@ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrTy }; const scope = owner(decl); let result: IrType | null = null; + // The values the binding's writes store, checked against the element + // type once the reads settle it. + const written: ts.Expression[] = []; // The file's identifiers are indexed by name once (identifiersNamed), so // each binding resolves only the uses spelled like it. for (const node of identifiersNamed(lowerer, ts.getSourceFileOfNode(decl), decl.name.text)) { @@ -4842,6 +4846,22 @@ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrTy parent.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && parent.operatorToken.kind <= ts.SyntaxKind.LastAssignment; if (reassigned) return DYN; + if ( + ts.isPropertyAccessExpression(parent) && + parent.expression === target && + (parent.name.text === "push" || parent.name.text === "unshift") && + ts.isCallExpression(parent.parent) && + parent.parent.expression === parent + ) + written.push(...parent.parent.arguments.nodes); + else if ( + ts.isElementAccessExpression(parent) && + parent.expression === target && + ts.isBinaryExpression(parent.parent) && + parent.parent.left === parent && + parent.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) + written.push(parent.parent.right); const t = lowerer.typeOf(node); if (unsettled(t)) continue; const mapped = lowerer.mapTypeOf(t); @@ -4849,7 +4869,36 @@ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrTy return DYN; result = mapped; } - return result ?? DYN; + if (result === null || result.kind !== "array") return DYN; + for (const value of written) { + if (ts.isSpreadElement(value)) return DYN; + const t = lowerer.mapTypeOf(lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(value))); + if (!t || (!typeEquals(t, result.elem) && lowerer.widthLiftPlan(t, result.elem) === null)) + return DYN; + } + return result; +} + +/** An unannotated alias of an evolving array binding whose reads disagree + * (`const alias = xs` between `xs.push(1)` and `xs.push("two")`): the + * checker types the alias by the elements written before it, but both names + * hold one array, so the alias takes the binding's checked-dynamic type and + * sees the later writes. Aliases of such an alias follow it. Null for other + * bindings. */ +function evolvingArrayAliasType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrType | null { + let current = decl; + for (let depth = 0; depth < 8; depth++) { + let initializer = current.initializer; + while (initializer !== undefined && ts.isParenthesizedExpression(initializer)) + initializer = initializer.expression; + if (initializer === undefined || !ts.isIdentifier(initializer)) return null; + const source = lowerer.checker.getSymbolAtLocation(initializer)?.valueDeclaration; + if (source === undefined || !ts.isVariableDeclaration(source) || source.type) return null; + const evolved = evolvingArrayType(lowerer, source); + if (evolved !== null) return evolved.kind === "dyn" ? evolved : null; + current = source; + } + return null; } /** A single static type for an initializer-less JavaScript `let` whose @@ -5565,7 +5614,7 @@ export function lowerVarDecl( !decl.type && !isJsSourceFile(ts.getSourceFileOfNode(decl)) ) { - const evolved = evolvingArrayType(lowerer, decl); + const evolved = evolvingArrayType(lowerer, decl) ?? evolvingArrayAliasType(lowerer, decl); if (evolved !== null) { type = evolved; init = lowerer.lowerExprExpecting(decl.initializer, evolved); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7006-evolving-array-aliases.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7006-evolving-array-aliases.ts.json new file mode 100644 index 000000000..cb3d36498 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7006-evolving-array-aliases.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7006-evolving-array-aliases.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7006-evolving-array-aliases.ts b/tests/corpus/7006-evolving-array-aliases.ts new file mode 100644 index 000000000..4810c440e --- /dev/null +++ b/tests/corpus/7006-evolving-array-aliases.ts @@ -0,0 +1,70 @@ +// An unannotated `const xs = []` inside a function whose writes store values +// of more than one element type: an alias taken between the writes +// (`const alias = xs`) and an alias of that alias name the same array, so +// they see every later write, as in Node. A write of another element type +// after reads that agree on one type also keeps the array untyped. +function chain(): string { + const xs = []; + xs.push(1); + const a = xs; + const b = a; + xs.push("two"); + b.push(3); + return `${xs.join(",")} ${a.length} ${b.length} ${a === xs} ${b === xs}`; +} +function viaAlias(): string { + const xs = []; + xs.push("a"); + const alias = xs; + alias.push("b"); + xs.push(2); + return `${xs.join(",")} ${alias.join(",")}`; +} +function letAlias(): string { + const xs = []; + xs.push(true); + let alias = xs; + xs.push("t"); + const seen = alias.length; + alias = []; + return `${seen} ${alias.length} ${xs.length}`; +} +function nested(flag: boolean): string { + const xs = []; + xs.push(1); + if (flag) { + const inner = xs; + xs.push("n"); + return `${inner.length} ${inner.join(":")}`; + } + return `${xs.length}`; +} +function elementWrite(): string { + const xs = []; + xs.push(1); + const alias = xs; + xs[1] = "one"; + return `${alias.length} ${alias.join("+")}`; +} +function agreeing(): string { + const xs = []; + xs.push(1); + const alias = xs; + xs.push(2); + return `${alias.length} ${alias === xs} ${alias.reduce((sum, v) => sum + v, 0)}`; +} +function total(values: number[]): number { + return values.length; +} +function passed(): string { + const xs = []; + xs.push(1); + const alias = xs; + const n = total(alias); + xs.push("z"); + return `${n} ${alias.length}`; +} +console.log(chain()); +console.log(viaAlias(), "|", letAlias()); +console.log(nested(true), "|", nested(false), "|", elementWrite()); +console.log(agreeing(), "|", passed()); diff --git a/tests/harness/corpus-costs/7006-evolving-array-aliases.ts.json b/tests/harness/corpus-costs/7006-evolving-array-aliases.ts.json new file mode 100644 index 000000000..f34efd332 --- /dev/null +++ b/tests/harness/corpus-costs/7006-evolving-array-aliases.ts.json @@ -0,0 +1 @@ +{ "plain": 2292, "san": 3445 } From 51b9bdca11d21e7ee2b670df375c636c2020b286 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 21:39:25 -0700 Subject: [PATCH 03/45] Compile chalk 5 from a built-in shim with a callable builder class A class whose merged interface carries a call signature stores its call behavior in a '%call' field; calls and function-slot coercions read it. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/chalk/v5.ts | 573 ++++++++++++++++++ packages/compiler/shims/hot-shots/v8.ts | 2 + .../src/frontend/lowering/lower-calls.ts | 25 +- .../compiler/src/frontend/lowering/lowerer.ts | 17 +- .../compiler/src/frontend/package-shims.ts | 49 +- 5 files changed, 657 insertions(+), 9 deletions(-) create mode 100644 packages/compiler/shims/chalk/v5.ts create mode 100644 packages/compiler/shims/hot-shots/v8.ts diff --git a/packages/compiler/shims/chalk/v5.ts b/packages/compiler/shims/chalk/v5.ts new file mode 100644 index 000000000..6599e35f9 --- /dev/null +++ b/packages/compiler/shims/chalk/v5.ts @@ -0,0 +1,573 @@ +// scriptc's built-in implementation of the `chalk` package, 5.x API. +// +// Programs whose installed chalk is 5.x compile this module in its place +// (packages/compiler/src/frontend/package-shims.ts). chalk builds its +// styles as functions whose prototypes it swaps at run time; here a style +// chain is an instance of one class whose style members are cached +// getters, and the instance is callable through its `%call` field (the +// merged interface below gives it chalk's call signature; the lowerer calls +// the field). The output, color-level detection (supports-color 10: +// FORCE_COLOR, the --color/--no-color flags, TTY, TERM, CI variables) and +// the shared, settable `level` follow chalk 5.6 byte for byte. +import * as os from "node:os"; +import * as tty from "node:tty"; + +export type ColorSupportLevel = 0 | 1 | 2 | 3; + +export interface ColorSupport { + level: ColorSupportLevel; + hasBasic: boolean; + has256: boolean; + has16m: boolean; +} + +export type ColorInfo = ColorSupport | false; + +export interface Options { + readonly level?: ColorSupportLevel; +} + +export type ModifierName = + | "reset" + | "bold" + | "dim" + | "italic" + | "underline" + | "overline" + | "inverse" + | "hidden" + | "strikethrough"; + +export type ForegroundColorName = + | "black" + | "red" + | "green" + | "yellow" + | "blue" + | "cyan" + | "magenta" + | "white" + | "gray" + | "grey" + | "blackBright" + | "redBright" + | "greenBright" + | "yellowBright" + | "blueBright" + | "cyanBright" + | "magentaBright" + | "whiteBright"; + +export type BackgroundColorName = + | "bgBlack" + | "bgRed" + | "bgGreen" + | "bgYellow" + | "bgBlue" + | "bgCyan" + | "bgMagenta" + | "bgWhite" + | "bgGray" + | "bgGrey" + | "bgBlackBright" + | "bgRedBright" + | "bgGreenBright" + | "bgYellowBright" + | "bgBlueBright" + | "bgCyanBright" + | "bgMagentaBright" + | "bgWhiteBright"; + +export type ColorName = ForegroundColorName | BackgroundColorName; + +export type Modifiers = ModifierName; +export type ForegroundColor = ForegroundColorName; +export type BackgroundColor = BackgroundColorName; +export type Color = ColorName; + +// ── ansi-styles ────────────────────────────────────────────────────────── + +export const modifierNames: ModifierName[] = [ + "reset", + "bold", + "dim", + "italic", + "underline", + "overline", + "inverse", + "hidden", + "strikethrough", +]; +export const foregroundColorNames: ForegroundColorName[] = [ + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + "blackBright", + "gray", + "grey", + "redBright", + "greenBright", + "yellowBright", + "blueBright", + "magentaBright", + "cyanBright", + "whiteBright", +]; +export const backgroundColorNames: BackgroundColorName[] = [ + "bgBlack", + "bgRed", + "bgGreen", + "bgYellow", + "bgBlue", + "bgMagenta", + "bgCyan", + "bgWhite", + "bgBlackBright", + "bgGray", + "bgGrey", + "bgRedBright", + "bgGreenBright", + "bgYellowBright", + "bgBlueBright", + "bgMagentaBright", + "bgCyanBright", + "bgWhiteBright", +]; +export const colorNames: ColorName[] = [ + ...foregroundColorNames, + ...backgroundColorNames, +]; +export const modifiers: Modifiers[] = modifierNames; +export const foregroundColors: ForegroundColor[] = foregroundColorNames; +export const backgroundColors: BackgroundColor[] = backgroundColorNames; +export const colors: Color[] = colorNames; + +const ESC = "\u001B["; + +/** Open and close codes, indexed by style id (the order of the getters). */ +const OPEN_CODES: number[] = [ + 0, 1, 2, 3, 4, 53, 7, 8, 9, + 30, 31, 32, 33, 34, 35, 36, 37, 90, 90, 90, 91, 92, 93, 94, 95, 96, 97, + 40, 41, 42, 43, 44, 45, 46, 47, 100, 100, 100, 101, 102, 103, 104, 105, 106, 107, +]; +const CLOSE_CODES: number[] = [ + 0, 22, 22, 23, 24, 55, 27, 28, 29, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, +]; +const VISIBLE = 45; + +function rgbToAnsi256(red: number, green: number, blue: number): number { + if (red === green && green === blue) { + if (red < 8) return 16; + if (red > 248) return 231; + return Math.round(((red - 8) / 247) * 24) + 232; + } + return ( + 16 + + 36 * Math.round((red / 255) * 5) + + 6 * Math.round((green / 255) * 5) + + Math.round((blue / 255) * 5) + ); +} + +function hexToRgb(hex: string): number[] { + const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex); + if (matches === null) return [0, 0, 0]; + let colorString = matches[0]; + if (colorString.length === 3) { + let doubled = ""; + for (const character of colorString) doubled += character + character; + colorString = doubled; + } + const integer = Number.parseInt(colorString, 16); + return [(integer >> 16) & 0xff, (integer >> 8) & 0xff, integer & 0xff]; +} + +function ansi256ToAnsi(code: number): number { + if (code < 8) return 30 + code; + if (code < 16) return 90 + (code - 8); + let red: number; + let green: number; + let blue: number; + if (code >= 232) { + red = ((code - 232) * 10 + 8) / 255; + green = red; + blue = red; + } else { + code -= 16; + const remainder = code % 36; + red = Math.floor(code / 36) / 5; + green = Math.floor(remainder / 6) / 5; + blue = (remainder % 6) / 5; + } + const value = Math.max(red, green, blue) * 2; + if (value === 0) return 30; + let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red)); + if (value === 2) result += 60; + return result; +} + +/** The open code of a color model at a level: offset 0 is the foreground, + * 10 the background (ansi-styles' wrapAnsi16/256/16m). */ +function rgbOpen(level: number, offset: number, red: number, green: number, blue: number): string { + if (level === 3) return `${ESC}${38 + offset};2;${red};${green};${blue}m`; + if (level === 2) return `${ESC}${38 + offset};5;${rgbToAnsi256(red, green, blue)}m`; + return `${ESC}${ansi256ToAnsi(rgbToAnsi256(red, green, blue)) + offset}m`; +} + +/** chalk's ansi256 model emits the 256-color code at every level (only + * the rgb and hex models downsample). */ +function ansi256Open(offset: number, code: number): string { + return `${ESC}${38 + offset};5;${code}m`; +} + +// ── supports-color ─────────────────────────────────────────────────────── + +function hasFlag(flag: string): boolean { + const argv = process.argv; + const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf("--"); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); +} + +let flagForceColor: number | undefined = undefined; +if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { + flagForceColor = 0; +} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { + flagForceColor = 1; +} + +function envForceColor(): number | undefined { + const force = process.env["FORCE_COLOR"]; + if (force !== undefined) { + if (force === "true") return 1; + if (force === "false") return 0; + return force.length === 0 ? 1 : Math.min(Number.parseInt(force, 10), 3); + } + return undefined; +} + +function translateLevel(level: number): ColorInfo { + if (level === 0) return false; + return { + level: level as ColorSupportLevel, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, + }; +} + +function inEnv(name: string): boolean { + return process.env[name] !== undefined; +} + +function detectLevel(streamIsTTY: boolean): number { + const noFlagForceColor = envForceColor(); + if (noFlagForceColor !== undefined) flagForceColor = noFlagForceColor; + const forceColor = flagForceColor; + if (forceColor === 0) return 0; + if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3; + if (hasFlag("color=256")) return 2; + if (inEnv("TF_BUILD") && inEnv("AGENT_NAME")) return 1; + if (!streamIsTTY && forceColor === undefined) return 0; + const min = forceColor === undefined || forceColor === 0 || Number.isNaN(forceColor) ? 0 : forceColor; + const env = process.env; + const term = env["TERM"]; + if (term === "dumb") return min; + if (process.platform === "win32") { + const osRelease = os.release().split("."); + if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10_586) { + return Number(osRelease[2]) >= 14_931 ? 3 : 2; + } + return 1; + } + if (inEnv("CI")) { + if (inEnv("GITHUB_ACTIONS") || inEnv("GITEA_ACTIONS") || inEnv("CIRCLECI")) return 3; + if ( + inEnv("TRAVIS") || + inEnv("APPVEYOR") || + inEnv("GITLAB_CI") || + inEnv("BUILDKITE") || + inEnv("DRONE") || + env["CI_NAME"] === "codeship" + ) { + return 1; + } + return min; + } + const teamcity = env["TEAMCITY_VERSION"]; + if (teamcity !== undefined) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(teamcity) ? 1 : 0; + } + if (env["COLORTERM"] === "truecolor") return 3; + if (term === "xterm-kitty") return 3; + if (term === "xterm-ghostty") return 3; + if (term === "wezterm") return 3; + const termProgram = env["TERM_PROGRAM"]; + if (termProgram !== undefined) { + const version = Number.parseInt((env["TERM_PROGRAM_VERSION"] || "").split(".")[0]!, 10); + if (termProgram === "iTerm.app") return version >= 3 ? 3 : 2; + if (termProgram === "Apple_Terminal") return 2; + } + // supports-color tests these against `env.TERM`, which is the string + // "undefined" when TERM is unset. + const termText = term === undefined ? "undefined" : term; + if (/-256(color)?$/i.test(termText)) return 2; + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(termText)) return 1; + if (inEnv("COLORTERM")) return 1; + return min; +} + +const stdoutColor: ColorInfo = translateLevel(detectLevel(tty.isatty(1))); +const stderrColor: ColorInfo = translateLevel(detectLevel(tty.isatty(2))); + +export const supportsColor: ColorInfo = stdoutColor; +export const supportsColorStderr: ColorInfo = stderrColor; + +// ── the builder ────────────────────────────────────────────────────────── + +/** One link of a style chain (chalk's styler). */ +class Styler { + open: string; + close: string; + openAll: string; + closeAll: string; + parent: Styler | undefined; + constructor(open: string, close: string, parent: Styler | undefined) { + this.open = open; + this.close = close; + this.parent = parent; + if (parent === undefined) { + this.openAll = open; + this.closeAll = close; + } else { + this.openAll = parent.openAll + open; + this.closeAll = close + parent.closeAll; + } + } +} + +/** The level every builder of one chalk instance shares. */ +class LevelBox { + level: number; + constructor(level: number) { + this.level = level; + } +} + +function stringReplaceAll(string: string, substring: string, replacer: string): string { + let index = string.indexOf(substring); + if (index === -1) return string; + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ""; + do { + returnValue += string.slice(endIndex, index) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); + returnValue += string.slice(endIndex); + return returnValue; +} + +function stringEncaseCRLFWithFirstIndex( + string: string, + prefix: string, + postfix: string, + index: number, +): string { + let endIndex = 0; + let returnValue = ""; + do { + const gotCR = string[index - 1] === "\r"; + returnValue += + string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix; + endIndex = index + 1; + index = string.indexOf("\n", endIndex); + } while (index !== -1); + returnValue += string.slice(endIndex); + return returnValue; +} + +function applyStyle(self: ChalkInstance, string: string): string { + if (self.box.level <= 0 || !string) return self.isEmpty ? "" : string; + let styler = self.styler; + if (styler === undefined) return string; + const openAll = styler.openAll; + const closeAll = styler.closeAll; + if (string.includes("\u001B")) { + while (styler !== undefined) { + string = stringReplaceAll(string, styler.close, styler.open); + styler = styler.parent; + } + } + const lfIndex = string.indexOf("\n"); + if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); + return openAll + string + closeAll; +} + +function joinArguments(args: unknown[]): string { + let out = ""; + for (let i = 0; i < args.length; i++) { + if (i > 0) out += " "; + const value = args[i]; + if (value !== undefined && value !== null) out += String(value); + } + return out; +} + +/** A chalk instance or one of its style chains: callable (chalk's call + * signature merges in from the interface), with every style a cached + * getter. */ +export interface ChalkInstance { + (...text: unknown[]): string; +} + +export class ChalkInstance { + "%call": (...text: unknown[]) => string; + box: LevelBox; + styler: Styler | undefined; + isEmpty: boolean; + private readonly cache: (ChalkInstance | undefined)[] = []; + + constructor(box: LevelBox, styler: Styler | undefined, isEmpty: boolean, root: boolean) { + this.box = box; + this.styler = styler; + this.isEmpty = isEmpty; + // One unconditional store: the field's definite assignment. + this["%call"] = (...text: unknown[]): string => + root + ? joinArguments(text) + : applyStyle(this, text.length === 1 ? "" + String(text[0]) : joinArguments(text)); + } + + get level(): ColorSupportLevel { + return this.box.level as ColorSupportLevel; + } + + set level(level: ColorSupportLevel) { + this.box.level = level; + } + + private style(id: number): ChalkInstance { + const cached = this.cache[id]; + if (cached !== undefined) return cached; + let builder: ChalkInstance; + if (id === VISIBLE) { + builder = new ChalkInstance(this.box, this.styler, true, false); + } else { + const styler = new Styler( + `${ESC}${OPEN_CODES[id]!}m`, + `${ESC}${CLOSE_CODES[id]!}m`, + this.styler, + ); + builder = new ChalkInstance(this.box, styler, this.isEmpty, false); + } + while (this.cache.length <= id) this.cache.push(undefined); + this.cache[id] = builder; + return builder; + } + + private model(open: string, background: boolean): ChalkInstance { + const styler = new Styler(open, background ? `${ESC}49m` : `${ESC}39m`, this.styler); + return new ChalkInstance(this.box, styler, this.isEmpty, false); + } + + rgb(red: number, green: number, blue: number): ChalkInstance { + return this.model(rgbOpen(this.box.level, 0, red, green, blue), false); + } + hex(color: string): ChalkInstance { + const [red, green, blue] = hexToRgb(color); + return this.model(rgbOpen(this.box.level, 0, red!, green!, blue!), false); + } + ansi256(index: number): ChalkInstance { + return this.model(ansi256Open(0, index), false); + } + bgRgb(red: number, green: number, blue: number): ChalkInstance { + return this.model(rgbOpen(this.box.level, 10, red, green, blue), true); + } + bgHex(color: string): ChalkInstance { + const [red, green, blue] = hexToRgb(color); + return this.model(rgbOpen(this.box.level, 10, red!, green!, blue!), true); + } + bgAnsi256(index: number): ChalkInstance { + return this.model(ansi256Open(10, index), true); + } + + get reset(): ChalkInstance { return this.style(0); } + get bold(): ChalkInstance { return this.style(1); } + get dim(): ChalkInstance { return this.style(2); } + get italic(): ChalkInstance { return this.style(3); } + get underline(): ChalkInstance { return this.style(4); } + get overline(): ChalkInstance { return this.style(5); } + get inverse(): ChalkInstance { return this.style(6); } + get hidden(): ChalkInstance { return this.style(7); } + get strikethrough(): ChalkInstance { return this.style(8); } + get visible(): ChalkInstance { return this.style(VISIBLE); } + get black(): ChalkInstance { return this.style(9); } + get red(): ChalkInstance { return this.style(10); } + get green(): ChalkInstance { return this.style(11); } + get yellow(): ChalkInstance { return this.style(12); } + get blue(): ChalkInstance { return this.style(13); } + get magenta(): ChalkInstance { return this.style(14); } + get cyan(): ChalkInstance { return this.style(15); } + get white(): ChalkInstance { return this.style(16); } + get blackBright(): ChalkInstance { return this.style(17); } + get gray(): ChalkInstance { return this.style(18); } + get grey(): ChalkInstance { return this.style(19); } + get redBright(): ChalkInstance { return this.style(20); } + get greenBright(): ChalkInstance { return this.style(21); } + get yellowBright(): ChalkInstance { return this.style(22); } + get blueBright(): ChalkInstance { return this.style(23); } + get magentaBright(): ChalkInstance { return this.style(24); } + get cyanBright(): ChalkInstance { return this.style(25); } + get whiteBright(): ChalkInstance { return this.style(26); } + get bgBlack(): ChalkInstance { return this.style(27); } + get bgRed(): ChalkInstance { return this.style(28); } + get bgGreen(): ChalkInstance { return this.style(29); } + get bgYellow(): ChalkInstance { return this.style(30); } + get bgBlue(): ChalkInstance { return this.style(31); } + get bgMagenta(): ChalkInstance { return this.style(32); } + get bgCyan(): ChalkInstance { return this.style(33); } + get bgWhite(): ChalkInstance { return this.style(34); } + get bgBlackBright(): ChalkInstance { return this.style(35); } + get bgGray(): ChalkInstance { return this.style(36); } + get bgGrey(): ChalkInstance { return this.style(37); } + get bgRedBright(): ChalkInstance { return this.style(38); } + get bgGreenBright(): ChalkInstance { return this.style(39); } + get bgYellowBright(): ChalkInstance { return this.style(40); } + get bgBlueBright(): ChalkInstance { return this.style(41); } + get bgMagentaBright(): ChalkInstance { return this.style(42); } + get bgCyanBright(): ChalkInstance { return this.style(43); } + get bgWhiteBright(): ChalkInstance { return this.style(44); } +} + +function optionsLevel(options: Options | undefined): number { + const level = options === undefined ? undefined : options.level; + if (level !== undefined && level !== 0 && !(Number.isInteger(level) && level >= 0 && level <= 3)) { + throw new Error("The `level` option should be an integer from 0 to 3"); + } + if (level === undefined) return stdoutColor === false ? 0 : stdoutColor.level; + return level; +} + +/** `new Chalk(options)`: a fresh chalk instance with its own level. */ +export class Chalk extends ChalkInstance { + constructor(options?: Options) { + super(new LevelBox(optionsLevel(options)), undefined, false, true); + } +} + +const chalk: ChalkInstance = new Chalk(); +export const chalkStderr: ChalkInstance = new Chalk({ + level: stderrColor === false ? 0 : stderrColor.level, +}); + +export default chalk; diff --git a/packages/compiler/shims/hot-shots/v8.ts b/packages/compiler/shims/hot-shots/v8.ts new file mode 100644 index 000000000..2c036408e --- /dev/null +++ b/packages/compiler/shims/hot-shots/v8.ts @@ -0,0 +1,2 @@ +export class StatsD {} +export default StatsD; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 39b7207c0..53971c7b0 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1619,7 +1619,13 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { } const accessorTarget = lowerer.fieldTarget(expr.expression); if (accessorTarget?.container === "accessor") { - const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression); + let callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression); + // A getter returning a callable class instance (chalk's + // `chalk.red("x")`): call through its `%call` field. + if (callee.type.kind === "object") { + callee = lowerer.hybridCallUnwrap(callee); + if (callee.type.kind === "func") return lowerCallThroughValue(lowerer, expr, callee, locOf(expr)); + } if (callee.type.kind === "func") { const args = completeFuncValueArgs(lowerer, expr, callee.type, locOf(expr)); return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(expr) }; @@ -1871,7 +1877,19 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // a non-func IR type was already rejected while lowering the callee. // HYBRID (function-with-properties) values call through their %call slot. let callee = lowerer.lowerExpr(expr.expression); - if (callee.type.kind === "record") callee = lowerer.hybridCallUnwrap(callee); + if (callee.type.kind === "record" || callee.type.kind === "object") + callee = lowerer.hybridCallUnwrap(callee); + return lowerCallThroughValue(lowerer, expr, callee, loc); +} + +/** A call through an evaluated callee value: checked-dynamic callees, + * function unions, typed-rest and runtime-arity closures. */ +function lowerCallThroughValue( + lowerer: Lowerer, + expr: ts.CallExpression, + callee: IrExpr, + loc: SrcLoc, +): IrExpr { // A CHECKED-DYNAMIC callee — `fn(a, b)` where fn is an implicit-any // JS binding (the mustCall body's `fn(...args)`), a dyn capture, or a // keyed read off a dyn value: the dynCall boundary. Arguments convert @@ -9181,7 +9199,8 @@ export function lowerRecordFieldCall( // A HYBRID (function-with-properties) field is callable through its // reserved %call slot — `colors.blue("x")` where blue also carries // `.bold` (the chalk shape). - if (callee.type.kind === "record") callee = lowerer.hybridCallUnwrap(callee); + if (callee.type.kind === "record" || callee.type.kind === "object") + callee = lowerer.hybridCallUnwrap(callee); // Inferred JavaScript option records can retain checked callables in // fields even when the checker only describes those members as any. // TypeScript reaches here for callable library types that are checked diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b02a0a843..b1867be32 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9294,6 +9294,21 @@ export class Lowerer { * type-mapper.ts's chalk-shape mapping — call paths and func-slot coercions * share it. */ hybridCallUnwrap(expr: IrExpr): IrExpr { + // A callable CLASS instance: a class whose merged interface carries a + // call signature stores its call behavior in a `%call` field (the + // chalk package shim's builder). Calls read the field. + if (expr.type.kind === "object") { + const callType = this.classes.get(expr.type.className)?.fields.get("%call"); + if (callType === undefined || callType.kind !== "func") return expr; + return { + kind: "fieldGet", + obj: expr, + className: expr.type.className, + field: "%call", + type: callType, + loc: expr.loc, + }; + } if (expr.type.kind !== "record") return expr; const shape = this.shapes.get(expr.type.shapeId); const call = shape?.fields.find((f) => f.name === "%call"); @@ -9624,7 +9639,7 @@ export class Lowerer { // A HYBRID (function-with-properties) record flowing into a plain // func slot extracts its reserved %call field — the chalk shape's // "the value IS callable" half (type-mapper.ts's hybrid mapping). - if (expected.kind === "func" && expr.type.kind === "record") { + if (expected.kind === "func" && (expr.type.kind === "record" || expr.type.kind === "object")) { const un = this.hybridCallUnwrap(expr); if (un !== expr && typeEquals(un.type, expected)) return un; } diff --git a/packages/compiler/src/frontend/package-shims.ts b/packages/compiler/src/frontend/package-shims.ts index 86a41d3a6..f9cf1deb6 100644 --- a/packages/compiler/src/frontend/package-shims.ts +++ b/packages/compiler/src/frontend/package-shims.ts @@ -62,6 +62,9 @@ interface ImplementationShim { * of it (a __commonJS chunk whose key names the package, its version * and this file) is the package itself. */ mainFile: string; + /** The package's declaration entry relative to its directory, when it + * is not `index.d.ts`. */ + typesFile?: string; } const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ @@ -79,6 +82,26 @@ const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ ]), }, ], + [ + "chalk", + { + name: "chalk", + defaultExport: true, + mainFile: "source/index.js", + typesFile: "source/index.d.ts", + versions: new Map([[5, "chalk/v5.ts"]]), + }, + ], + [ + "hot-shots", + { + name: "hot-shots", + defaultExport: true, + mainFile: "index.js", + typesFile: "types.d.ts", + versions: new Map([[8, "hot-shots/v8.ts"]]), + }, + ], [ "undici", { @@ -280,16 +303,32 @@ export function isShimmedImport(fromFile: string, specifier: string): boolean { return isUnloadedPackage(specifier) || packageShimFor(fromFile, specifier) !== null; } +/** The shimmed package whose declaration entry `path` is, with the + * package directory: `/index.d.ts`, or the entry's own `typesFile`. */ +function shimOfDeclarationPath(path: string): { pkgDir: string; shim: ImplementationShim } | null { + if (!path.endsWith(".d.ts")) return null; + if (path.endsWith("/index.d.ts")) { + const pkgDir = dirname(path); + const shim = IMPLEMENTATION_SHIMS.get(pkgDir.slice(pkgDir.lastIndexOf("/") + 1)); + if (shim !== undefined && shim.typesFile === undefined) return { pkgDir, shim }; + } + for (const shim of IMPLEMENTATION_SHIMS.values()) { + if (shim.typesFile === undefined) continue; + const suffix = `/${shim.name}/${shim.typesFile}`; + if (path.endsWith(suffix)) return { pkgDir: path.slice(0, path.length - suffix.length + shim.name.length + 1), shim }; + } + return null; +} + /** The fs-shadow answer for a shimmed package's declaration entry: the * installed `index.d.ts` reads as a re-export of the version's shim module, * so the checker types each importer against its own version. Undefined * for every other path. */ export function packageShimDeclarationText(path: string): string | undefined { - if (!path.endsWith("/index.d.ts")) return undefined; - const pkgDir = dirname(path); - const name = pkgDir.slice(pkgDir.lastIndexOf("/") + 1); - const shim = IMPLEMENTATION_SHIMS.get(name); - if (shim === undefined) return undefined; + const located = shimOfDeclarationPath(path); + if (located === null) return undefined; + const { pkgDir, shim } = located; + const name = shim.name; // A DefinitelyTyped twin (`@types/fs-extra`) types a package that ships no // declarations. Nothing at its path names the installed runtime version, // so it reads as the shim only when every supported version shares one From 750c817649e01371c160e91ee5b5263c671440ef Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 21:45:50 -0700 Subject: [PATCH 04/45] Compile hot-shots 8 from a built-in typed StatsD shim udp over node:dgram (TypeScript may use the send completion-callback form), tcp over node:net, mock mode, child clients, tags, checks and events; uds reports the missing unix-dgram addon as hot-shots does. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/hot-shots/v8.ts | 952 +++++++++++++++++- .../src/frontend/lowering/lower-dgram.ts | 4 +- 2 files changed, 954 insertions(+), 2 deletions(-) diff --git a/packages/compiler/shims/hot-shots/v8.ts b/packages/compiler/shims/hot-shots/v8.ts index 2c036408e..a8af7a19e 100644 --- a/packages/compiler/shims/hot-shots/v8.ts +++ b/packages/compiler/shims/hot-shots/v8.ts @@ -1,2 +1,952 @@ -export class StatsD {} +// scriptc's built-in implementation of the `hot-shots` package, 8.x API. +// +// Programs whose installed hot-shots is 8.x compile this module in its +// place (packages/compiler/src/frontend/package-shims.ts). It is a typed +// port of hot-shots 8.5's StatsD client: the same datagrams, callbacks, +// error messages and child-client sharing, over node:dgram (udp) and +// node:net (tcp). The uds protocol needs the optional `unix-dgram` addon; +// this entry serves programs where it is not installed, so uds reports +// hot-shots' "not installed" error exactly as Node does. +import * as dgram from "node:dgram"; +import * as dns from "node:dns"; +import * as net from "node:net"; +import * as os from "node:os"; + +export type Tags = { [key: string]: string } | string[]; + +export interface ClientOptions { + bufferFlushInterval?: number; + bufferHolder?: { buffer: string }; + cacheDns?: boolean; + cacheDnsTtl?: number; + errorHandler?: (err: Error) => void; + globalTags?: Tags; + globalize?: boolean; + host?: string; + isChild?: boolean; + maxBufferSize?: number; + mock?: boolean; + path?: string; + port?: number; + prefix?: string; + protocol?: "tcp" | "udp" | "uds"; + sampleRate?: number; + suffix?: string; + telegraf?: boolean; + useDefaultRoute?: boolean; + tagPrefix?: string; + tagSeparator?: string; + udsGracefulErrorHandling?: boolean; + udsGracefulRestartRateLimit?: number; + closingFlushInterval?: number; +} + +export interface ChildClientOptions { + globalTags?: Tags; + prefix?: string; + suffix?: string; + errorHandler?: (err: Error) => void; +} + +export interface CheckOptions { + /** A Unix timestamp; hot-shots also takes a Date, which this shim's + * option records cannot hold yet. */ + date_happened?: number; + hostname?: string; + message?: string; +} + +export interface DatadogChecks { + OK: 0; + WARNING: 1; + CRITICAL: 2; + UNKNOWN: 3; +} + +export type DatadogChecksValues = 0 | 1 | 2 | 3; + +export interface EventOptions { + aggregation_key?: string; + alert_type?: "info" | "warning" | "success" | "error"; + /** A Unix timestamp; hot-shots also takes a Date, which this shim's + * option records cannot hold yet. */ + date_happened?: number; + hostname?: string; + priority?: "low" | "normal"; + source_type_name?: string; +} + +/** A send's completion: hot-shots passes `null` on success. */ +export type StatsCb = (error: Error | null | undefined, bytes?: any) => void; + +type SampleArg = number | Tags | StatsCb | undefined; +type TagsArg = Tags | StatsCb | undefined; + +const PROTOCOL_TCP = "tcp"; +const PROTOCOL_UDS = "uds"; +const PROTOCOL_UDP = "udp"; +const UDS_DEFAULT_GRACEFUL_RESTART_LIMIT = 1000; +const CACHE_DNS_TTL_DEFAULT = 60000; + +function udsErrorCodes(): number[] { + if (process.platform === "linux") { + return [os.constants.errno.ENOTCONN, os.constants.errno.ECONNREFUSED]; + } + if (process.platform === "darwin") { + return [os.constants.errno.EDESTADDRREQ, os.constants.errno.ECONNRESET]; + } + return []; +} +const UDS_ERROR_CODES = udsErrorCodes(); + +// ── helpers ────────────────────────────────────────────────────────────── + +function sanitizeTags(value: string, telegraf: boolean): string { + const blacklist = telegraf ? /:|\||,/g : /:|\||@|,/g; + return String(value).replace(blacklist, "_"); +} + +function formatTags(tags: Tags, telegraf: boolean): string[] { + if (Array.isArray(tags)) return tags; + const out: string[] = []; + for (const key of Object.keys(tags)) { + out.push(`${sanitizeTags(key, telegraf)}:${sanitizeTags(tags[key]!, telegraf)}`); + } + return out; +} + +function isArrayIndexKey(key: string): boolean { + return /^(0|[1-9]\d*)$/.test(key) && Number(key) < 4294967295; +} + +function overrideTags(parent: string[], child: Tags, telegraf: boolean): string[] { + const childKeys: string[] = []; + const childValues = new Map(); + const toAppend: string[] = []; + for (const tag of formatTags(child, telegraf)) { + const idx = tag.indexOf(":"); + if (idx < 1) { + toAppend.push(tag); + } else { + const key = tag.substring(0, idx); + const value = tag.substring(idx + 1); + let values = childValues.get(key); + if (values === undefined) { + values = []; + childValues.set(key, values); + childKeys.push(key); + } + values.push(value); + } + } + const result = parent.filter((tag) => { + const idx = tag.indexOf(":"); + if (idx < 1) return true; + return !childValues.has(tag.substring(0, idx)); + }); + // hot-shots walks an object's keys: array-index keys ascending first, + // then the rest in insertion order. + const indexKeys = childKeys.filter(isArrayIndexKey).sort((a, b) => Number(a) - Number(b)); + const ordered = indexKeys.concat(childKeys.filter((key) => !isArrayIndexKey(key))); + for (const key of ordered) { + for (const value of childValues.get(key)!) result.push(`${key}:${value}`); + } + return result.concat(toAppend); +} + +function formatDate(date: number): number { + return Math.round(date); +} + +function errorWithCode(message: string, code: string | undefined): Error { + const error: NodeJS.ErrnoException = new Error(message); + error.code = code; + return error; +} + +// ── transports ─────────────────────────────────────────────────────────── + +type SendCallback = (err: Error | null, bytes?: number) => void; + +/** The socket a client sends through (hot-shots' transport interface). */ +interface Transport { + createdAt: number; + send(buf: Buffer, callback: SendCallback): void; + close(): void; + onError(listener: (err: Error) => void): void; + offError(listener: (err: Error) => void): void; + onClose(listener: () => void): void; +} + +/** A socket's 'error' listeners, kept by the transport (the typed + * sockets have no removeListener): one socket listener dispatches to a + * snapshot, and an error nobody listens for throws, as an unhandled + * 'error' event does. */ +class ErrorListeners { + private listeners: ((err: Error) => void)[] = []; + add(listener: (err: Error) => void): void { + this.listeners.push(listener); + } + remove(listener: (err: Error) => void): void { + const index = this.listeners.indexOf(listener); + if (index !== -1) this.listeners.splice(index, 1); + } + emit(err: Error): void { + const snapshot = this.listeners.slice(); + if (snapshot.length === 0) throw err; + for (const listener of snapshot) listener(err); + } +} + +function addEol(buf: Buffer): string { + let msg = buf.toString(); + if (msg.length > 0 && msg[msg.length - 1] !== "\n") msg += "\n"; + return msg; +} + +class UdpTransport implements Transport { + createdAt = 0; + private readonly socket: dgram.Socket; + private readonly errors = new ErrorListeners(); + private resolvedAddress: string | undefined = undefined; + private resolvedAt = 0; + private readonly host: string | undefined; + private readonly port: number; + private readonly cacheDns: boolean; + private readonly cacheDnsTtl: number; + constructor(host: string | undefined, port: number, cacheDns: boolean, cacheDnsTtl: number) { + this.host = host; + this.port = port; + this.cacheDns = cacheDns; + this.cacheDnsTtl = cacheDnsTtl; + this.socket = dgram.createSocket("udp4"); + this.socket.unref(); + this.socket.on("error", (err) => this.errors.emit(err)); + } + send(buf: Buffer, callback: SendCallback): void { + if (!this.cacheDns) { + this.socket.send(buf, this.port, this.host || "127.0.0.1", callback); + return; + } + const now = Date.now(); + const cached = this.resolvedAddress; + if (cached === undefined || now - this.resolvedAt > this.cacheDnsTtl) { + dns.lookup(this.host ?? "localhost", (error, address) => { + if (error) { + callback(error); + return; + } + this.resolvedAddress = address; + this.resolvedAt = now; + this.socket.send(buf, this.port, address, callback); + }); + } else { + this.socket.send(buf, this.port, cached, callback); + } + } + close(): void { + this.socket.close(); + } + onError(listener: (err: Error) => void): void { + this.errors.add(listener); + } + offError(listener: (err: Error) => void): void { + this.errors.remove(listener); + } + onClose(listener: () => void): void { + this.socket.on("close", listener); + } +} + +class TcpTransport implements Transport { + createdAt = 0; + private readonly socket: net.Socket; + private readonly errors = new ErrorListeners(); + constructor(host: string | undefined, port: number) { + this.socket = net.connect(port, host ?? "localhost"); + this.socket.setKeepAlive(true); + this.socket.unref(); + this.socket.on("error", (err) => this.errors.emit(err)); + } + send(buf: Buffer, callback: SendCallback): void { + // The typed socket's write takes the data alone; the completion runs + // on the next tick. + this.socket.write(addEol(buf)); + process.nextTick(() => callback(null)); + } + close(): void { + this.socket.destroy(); + } + onError(listener: (err: Error) => void): void { + this.errors.add(listener); + } + offError(listener: (err: Error) => void): void { + this.errors.remove(listener); + } + onClose(listener: () => void): void { + this.socket.on("close", () => listener()); + } +} + +/** hot-shots reaches Unix datagram sockets through the optional + * `unix-dgram` addon; this entry serves programs without it. */ +function createUdsTransport(): Transport { + throw new Error( + "The library `unix_dgram`, needed for the uds protocol to work, is not installed. " + + "You need to pick another protocol to use hot-shots. " + + "See the hot-shots README for additional details.", + ); +} + +function createTransport(client: StatsD): Transport | null { + let transport: Transport | null = null; + const protocol = client.protocol; + try { + if (protocol === PROTOCOL_TCP) { + transport = new TcpTransport(client.host, client.port); + } else if (protocol === PROTOCOL_UDS) { + transport = createUdsTransport(); + } else if (protocol === PROTOCOL_UDP) { + transport = new UdpTransport(client.host, client.port, client.cacheDns, client.cacheDnsTtl); + } else { + throw new Error(`Unsupported protocol '${protocol}'`); + } + transport.createdAt = Date.now(); + } catch (e) { + const handler = client.errorHandler; + if (handler) { + handler(e as Error); + } else { + console.error(e); + } + } + return transport; +} + +// ── the client ─────────────────────────────────────────────────────────── + +class BufferHolder { + buffer = ""; +} + +/** What a child client inherits from its parent. */ +class ChildInit { + socket: Transport | null; + bufferHolder: BufferHolder; + dnsError: Error | undefined; + constructor(socket: Transport | null, bufferHolder: BufferHolder, dnsError: Error | undefined) { + this.socket = socket; + this.bufferHolder = bufferHolder; + this.dnsError = dnsError; + } +} + +export class StatsD { + protocol: string; + cacheDns: boolean; + cacheDnsTtl: number; + host: string | undefined; + port: number; + path: string | undefined; + prefix: string; + suffix: string; + tagPrefix: string; + tagSeparator: string; + mock: boolean; + globalTags: string[]; + telegraf: boolean; + maxBufferSize: number; + sampleRate: number; + bufferFlushInterval: number; + errorHandler: ((err: Error) => void) | undefined; + udsGracefulErrorHandling: boolean; + udsGracefulRestartRateLimit: number; + isChild: boolean; + closingFlushInterval: number; + mockBuffer: string[] | undefined = undefined; + messagesInFlight = 0; + CHECKS: DatadogChecks = { OK: 0, WARNING: 1, CRITICAL: 2, UNKNOWN: 3 }; + private bufferHolder: BufferHolder; + private transport: Transport | null = null; + private dnsError: Error | undefined = undefined; + private stopFlushInterval: (() => void) | undefined = undefined; + + constructor(options?: ClientOptions, child?: ChildInit) { + const o: ClientOptions = options ?? {}; + const protocol = o.protocol ? o.protocol.toLowerCase() : ""; + this.protocol = protocol ? protocol : PROTOCOL_UDP; + this.cacheDns = o.cacheDns === true; + this.cacheDnsTtl = o.cacheDnsTtl || CACHE_DNS_TTL_DEFAULT; + this.host = o.host || process.env["DD_AGENT_HOST"]; + this.port = o.port || parseInt(process.env["DD_DOGSTATSD_PORT"] ?? "", 10) || 8125; + this.path = o.path; + this.prefix = o.prefix || ""; + this.suffix = o.suffix || ""; + this.tagPrefix = o.tagPrefix || "#"; + this.tagSeparator = o.tagSeparator || ","; + this.mock = o.mock === true; + this.telegraf = o.telegraf || false; + const globalTags = o.globalTags; + this.globalTags = globalTags !== undefined ? formatTags(globalTags, this.telegraf) : []; + const entityId = process.env["DD_ENTITY_ID"]; + if (entityId) { + this.globalTags = this.globalTags.filter( + (item) => item.indexOf("dd.internal.entity_id:") !== 0, + ); + this.globalTags.push("dd.internal.entity_id:".concat(sanitizeTags(entityId, false))); + } + this.maxBufferSize = o.maxBufferSize || 0; + this.sampleRate = o.sampleRate || 1; + this.bufferFlushInterval = o.bufferFlushInterval || 1000; + this.bufferHolder = child !== undefined ? child.bufferHolder : new BufferHolder(); + this.errorHandler = o.errorHandler; + const graceful = o.udsGracefulErrorHandling; + this.udsGracefulErrorHandling = graceful === undefined ? true : graceful; + this.udsGracefulRestartRateLimit = + o.udsGracefulRestartRateLimit || UDS_DEFAULT_GRACEFUL_RESTART_LIMIT; + this.isChild = child !== undefined; + this.closingFlushInterval = o.closingFlushInterval || 50; + if (this.mock) this.mockBuffer = []; + if (child === undefined && this.maxBufferSize > 0) { + const handle = setInterval(() => this.onBufferFlushInterval(), this.bufferFlushInterval); + handle.unref(); + this.stopFlushInterval = () => clearInterval(handle); + } + if (child !== undefined) { + if (child.dnsError) this.dnsError = child.dnsError; + this.transport = child.socket; + } + if (!this.transport) this.transport = createTransport(this); + const handler = o.errorHandler; + const transport = this.transport; + if (transport !== null && child === undefined && handler) transport.onError(handler); + if (transport !== null && o.protocol === PROTOCOL_UDS) this.maybeAddUDSErrorHandler(); + } + + private maybeAddUDSErrorHandler(): void { + if (this.isChild || !this.udsGracefulErrorHandling) return; + const transport = this.transport; + if (transport !== null) transport.onError((err) => this.udsErrorHandler(err)); + } + + private udsErrorHandler(err: Error): void { + const code = Number((err as NodeJS.ErrnoException).code); + if (!UDS_ERROR_CODES.includes(-code)) return; + const socket = this.transport; + if (socket === null) return; + if (!socket.createdAt || Date.now() - socket.createdAt < this.udsGracefulRestartRateLimit) { + return; + } + const handler = this.errorHandler; + if (handler) socket.offError(handler); + const newSocket = createTransport(this); + if (newSocket === null) { + const errorMessage = "Could not replace UDS connection with new socket"; + if (handler) { + handler(new Error(errorMessage)); + } else { + console.error(errorMessage); + } + return; + } + socket.close(); + this.transport = newSocket; + this.maybeAddUDSErrorHandler(); + if (handler) { + newSocket.onError(handler); + } else { + newSocket.onError((error) => console.error(`hot-shots UDS error: ${String(error)}`)); + } + } + + // ── stats functions ── + + timing(stat: string | string[], time: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + timing(stat: string | string[], time: number, tags?: Tags, callback?: StatsCb): void; + timing(stat: string | string[], time: number, callback?: StatsCb): void; + timing(stat: string | string[], time: number, sampleRate?: number, callback?: StatsCb): void; + timing( + stat: string | string[], + time: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, time, "ms", sampleRate, tags, callback); + } + + increment(stat: string, tags?: Tags): void; + increment(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + increment(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + increment(stat: string | string[], value: number, callback?: StatsCb): void; + increment(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + increment( + stat: string | string[], + value?: number | Tags, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + // A non-number second argument of a two-argument call is the tags. + let amount = 1; + let tagArg: TagsArg = tags; + if (typeof value === "number") { + amount = value; + } else if (sampleRate === undefined && tags === undefined && callback === undefined) { + tagArg = value; + } + this.sendAll(stat, amount, "c", sampleRate, tagArg, callback); + } + + decrement(stat: string, tags?: Tags): void; + decrement(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + decrement( + stat: string | string[], + value?: number | Tags, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + let amount = 1; + let tagArg: TagsArg = tags; + if (typeof value === "number") { + amount = value; + } else if (sampleRate === undefined && tags === undefined && callback === undefined) { + tagArg = value; + } + this.sendAll(stat, -amount, "c", sampleRate, tagArg, callback); + } + + histogram(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + histogram( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "h", sampleRate, tags, callback); + } + + distribution(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + distribution( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "d", sampleRate, tags, callback); + } + + gauge(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + gauge( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "g", sampleRate, tags, callback); + } + + set(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + set( + stat: string | string[], + value: number | string, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "s", sampleRate, tags, callback); + } + + unique(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + unique( + stat: string | string[], + value: number | string, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "s", sampleRate, tags, callback); + } + + check( + name: string, + status: DatadogChecksValues, + options?: CheckOptions, + tags?: Tags | StatsCb, + callback?: StatsCb, + ): void { + if (this.telegraf) { + const err = new Error("Not supported by Telegraf / InfluxDB"); + if (callback) return callback(err); + const handler = this.errorHandler; + if (handler) return handler(err); + throw err; + } + const check: string[] = ["_sc", this.prefix + name + this.suffix, String(status)]; + const metadata: CheckOptions = options ?? {}; + const happened = metadata.date_happened; + if (happened) { + const timestamp = formatDate(happened); + if (timestamp) check.push(`d:${timestamp}`); + } + if (metadata.hostname) check.push(`h:${metadata.hostname}`); + let mergedTags = this.globalTags; + if (tags !== undefined && typeof tags !== "function") { + mergedTags = overrideTags(mergedTags, tags, this.telegraf); + } + if (mergedTags.length > 0) check.push(`#${mergedTags.join(",")}`); + if (metadata.message) check.push(`m:${metadata.message}`); + let cb = callback; + if (typeof tags === "function" && callback === undefined) cb = tags; + this.sendRaw(check.join("|"), cb); + } + + event( + title: string, + text?: string, + options?: EventOptions, + tags?: Tags | StatsCb, + callback?: StatsCb, + ): void { + if (this.telegraf) { + const err = new Error("Not supported by Telegraf / InfluxDB"); + if (callback) return callback(err); + const handler = this.errorHandler; + if (handler) return handler(err); + throw err; + } + const msgTitle = String(title ? title : ""); + let msgText = String(text ? text : msgTitle); + msgText = msgText.replace(/\n/g, "\\n"); + let message = `_e{${msgTitle.length},${msgText.length}}:${msgTitle}|${msgText}`; + if (options) { + const happened = options.date_happened; + if (happened) { + const timestamp = formatDate(happened); + if (timestamp) message += `|d:${timestamp}`; + } + if (options.hostname) message += `|h:${options.hostname}`; + if (options.aggregation_key) message += `|k:${options.aggregation_key}`; + if (options.priority) message += `|p:${options.priority}`; + if (options.source_type_name) message += `|s:${options.source_type_name}`; + if (options.alert_type) message += `|t:${options.alert_type}`; + } + let cb = callback; + let tagList: Tags | undefined = undefined; + if (typeof tags === "function") { + if (callback === undefined) cb = tags; + } else { + tagList = tags; + } + this.send(message, tagList, cb); + } + + // ── sending ── + + private sendAll( + stat: string | string[], + value: number | string, + type: string, + sampleRateArg: SampleArg, + tagsArg: TagsArg, + callbackArg: StatsCb | undefined, + ): void { + let sampleRate: number | undefined = undefined; + let tags: Tags | undefined = undefined; + let callback: StatsCb | undefined = callbackArg; + if (typeof sampleRateArg === "number") { + sampleRate = sampleRateArg; + if (typeof tagsArg === "function") { + callback = tagsArg; + } else { + tags = tagsArg; + } + } else if (sampleRateArg !== undefined) { + // A non-number sample rate shifts into the tags, and the tags + // argument into the callback. + if (typeof sampleRateArg === "function") { + callback = sampleRateArg; + } else { + tags = sampleRateArg; + callback = typeof tagsArg === "function" ? tagsArg : undefined; + } + } else if (typeof tagsArg === "function") { + callback = tagsArg; + } else { + tags = tagsArg; + } + + if (!Array.isArray(stat)) { + this.sendStat(stat, value, type, sampleRate, tags, callback); + return; + } + let completed = 0; + let calledback = false; + let sentBytes = 0; + const count = stat.length; + const onSend: StatsCb = (error, bytes) => { + completed += 1; + if (calledback) return; + if (error) { + if (callback !== undefined) { + calledback = true; + callback(error); + } else { + const handler = this.errorHandler; + if (handler) { + calledback = true; + handler(error); + } + } + return; + } + if (bytes) sentBytes += bytes as number; + if (completed === count && callback !== undefined) callback(null, sentBytes); + }; + for (const item of stat) this.sendStat(item, value, type, sampleRate, tags, onSend); + } + + private sendStat( + stat: string, + value: number | string, + type: string, + sampleRateArg: number | undefined, + tags: Tags | undefined, + callback: StatsCb | undefined, + ): void { + let message = `${this.prefix + stat + this.suffix}:${value}|${type}`; + const sampleRate = sampleRateArg || this.sampleRate; + if (sampleRate && sampleRate < 1) { + if (Math.random() < sampleRate) { + message += `|@${sampleRate}`; + } else { + if (callback) callback(undefined); + return; + } + } + this.send(message, tags, callback); + } + + private send(message: string, tags: Tags | undefined, callback: StatsCb | undefined): void { + let mergedTags = this.globalTags; + if (tags !== undefined) mergedTags = overrideTags(mergedTags, tags, this.telegraf); + if (mergedTags.length > 0) { + if (this.telegraf) { + const parts = message.split(":"); + message = `${parts[0]!},${mergedTags.join(",").replace(/:/g, "=")}:${parts.slice(1).join(":")}`; + } else { + message += `|${this.tagPrefix}${mergedTags.join(this.tagSeparator)}`; + } + } + this.sendRaw(message, callback); + } + + /** hot-shots' `_send`: the message with its tags. */ + private sendRaw(message: string, callback: StatsCb | undefined): void { + const dnsError = this.dnsError; + if (dnsError) { + if (callback) return callback(dnsError); + const handler = this.errorHandler; + if (handler) return handler(dnsError); + throw dnsError; + } + if (!this.mock) { + if (this.maxBufferSize === 0) { + this.sendMessage(message, callback); + } else { + this.enqueue(message, callback); + } + } else { + const buffer = this.mockBuffer; + if (buffer !== undefined) buffer.push(message); + if (callback) callback(null, 0); + } + } + + private enqueue(message: string, callback: StatsCb | undefined): void { + message += "\n"; + if (this.bufferHolder.buffer.length + message.length > this.maxBufferSize) { + this.flushQueue(callback); + this.bufferHolder.buffer += message; + } else { + this.bufferHolder.buffer += message; + if (callback) callback(null); + } + } + + private flushQueue(callback?: StatsCb): void { + this.sendMessage(this.bufferHolder.buffer, callback); + this.bufferHolder.buffer = ""; + } + + private sendMessage(message: string, callback: StatsCb | undefined): void { + if (message === "") { + if (callback) callback(null); + return; + } + const socketWasMissing = this.transport === null; + if (socketWasMissing && this.protocol === PROTOCOL_UDS) { + this.transport = createTransport(this); + if (this.transport !== null) this.maybeAddUDSErrorHandler(); + } + const socket = this.transport; + if (socketWasMissing || socket === null) { + const error = new Error("Socket not created properly. Check previous errors for details."); + if (callback) return callback(error); + const handler = this.errorHandler; + if (handler) return handler(error); + console.error(String(error)); + return; + } + const handleCallback = (err: Error | null, bytes?: number): void => { + this.messagesInFlight--; + let errFormatted: Error | null = null; + if (err) { + errFormatted = errorWithCode( + `Error sending hot-shots message: ${String(err)}`, + (err as NodeJS.ErrnoException).code, + ); + if (this.protocol === PROTOCOL_UDS && (callback || this.errorHandler)) { + this.udsErrorHandler(err); + } + } + if (callback) { + callback(errFormatted, bytes); + } else if (errFormatted) { + const handler = this.errorHandler; + if (handler) { + handler(errFormatted); + } else { + console.error(String(errFormatted)); + } + } + }; + try { + this.messagesInFlight++; + socket.send(Buffer.from(message), handleCallback); + } catch (err) { + handleCallback(err as Error); + } + } + + private onBufferFlushInterval(): void { + this.flushQueue(); + } + + close(callback?: (error?: Error) => void): void { + const stop = this.stopFlushInterval; + if (stop !== undefined) stop(); + this.flushQueue((err) => { + if (err) { + if (callback) return callback(err); + console.error(err); + return; + } + let intervalAttempts = 0; + const waitForMessages = setInterval(() => { + intervalAttempts++; + if (intervalAttempts > 10) { + console.log("hot-shots could not clear out messages in flight but closing anyways"); + this.messagesInFlight = 0; + } + if (this.messagesInFlight <= 0) { + clearInterval(waitForMessages); + this.closeSocket(callback); + } + }, this.closingFlushInterval); + }); + } + + private closeSocket(callback: ((error?: Error) => void) | undefined): void { + let handledError = false; + const handleErr = (err: unknown): void => { + const errMessage = `Error closing hot-shots socket: ${String(err)}`; + if (handledError) { + console.error(errMessage); + } else { + handledError = true; + if (callback) { + callback(new Error(errMessage)); + } else { + const handler = this.errorHandler; + if (handler) { + handler(new Error(errMessage)); + } else { + console.error(errMessage); + } + } + } + }; + const socket = this.transport; + if (socket === null) { + handleErr(new TypeError("Cannot read properties of null (reading 'removeListener')")); + return; + } + const handler = this.errorHandler; + if (handler) socket.offError(handler); + socket.onError(handleErr); + if (callback) { + socket.onClose(() => { + if (!handledError) callback(undefined); + }); + } + try { + socket.close(); + } catch (err) { + handleErr(err); + } + } + + childClient(options?: ChildClientOptions): StatsD { + const o: ChildClientOptions = options ?? {}; + const childTags = o.globalTags; + return new StatsD( + { + isChild: true, + errorHandler: o.errorHandler || this.errorHandler, + host: this.host, + port: this.port, + tagPrefix: this.tagPrefix, + tagSeparator: this.tagSeparator, + prefix: (o.prefix || "") + this.prefix, + suffix: this.suffix + (o.suffix || ""), + globalize: false, + mock: this.mock, + globalTags: + childTags !== undefined + ? overrideTags(this.globalTags, childTags, this.telegraf) + : this.globalTags, + maxBufferSize: this.maxBufferSize, + bufferFlushInterval: this.bufferFlushInterval, + telegraf: this.telegraf, + protocol: this.protocol === "tcp" ? "tcp" : this.protocol === "uds" ? "uds" : "udp", + closingFlushInterval: this.closingFlushInterval, + }, + new ChildInit(this.transport, this.bufferHolder, this.dnsError), + ); + } +} + export default StatsD; diff --git a/packages/compiler/src/frontend/lowering/lower-dgram.ts b/packages/compiler/src/frontend/lowering/lower-dgram.ts index aa90fc7c7..0e0ddf975 100644 --- a/packages/compiler/src/frontend/lowering/lower-dgram.ts +++ b/packages/compiler/src/frontend/lowering/lower-dgram.ts @@ -612,8 +612,10 @@ export function lowerDgramMethodCall( const fn: IrLibFn = data.type.kind === "string" ? "dgram.sendStr" : "dgram.sendBytes"; return { kind: "libCall", fn, args: [receiver, data, port, host], type: VOID, loc }; } + // TypeScript reaches the ladder for the completion-callback form + // send(msg, port, address, callback) (the hot-shots package shim). if ( - isJsSourceFile(ts.getSourceFileOfNode(call)) && + (isJsSourceFile(ts.getSourceFileOfNode(call)) || args.length === 4) && args.length <= 6 && !args.some(ts.isSpreadElement) ) { From cab61904fd43bfa9d4736e2c9a72b435fd9b9aef Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 21:55:38 -0700 Subject: [PATCH 05/45] Send hot-shots uds metrics through a native Unix datagram socket Where unix-dgram is installed beside hot-shots, the shim's entry sends through runtime AF_UNIX datagram calls with the addon's semantics; without it, uds reports the addon missing as hot-shots does. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/hot-shots/client.ts | 1033 +++++++++++++++++ .../compiler/shims/hot-shots/v8-unix-dgram.ts | 8 + packages/compiler/shims/hot-shots/v8.ts | 956 +-------------- .../compiler/src/backend/llvm/lib-datagram.ts | 4 + .../src/frontend/lowering/lower-calls.ts | 43 + .../src/frontend/lowering/lower-namespaces.ts | 8 +- .../compiler/src/frontend/package-shims.ts | 27 +- .../compiler/src/ir/builtin-signatures.ts | 7 + packages/runtime/src/scr_dgram.c | 70 ++ 9 files changed, 1202 insertions(+), 954 deletions(-) create mode 100644 packages/compiler/shims/hot-shots/client.ts create mode 100644 packages/compiler/shims/hot-shots/v8-unix-dgram.ts diff --git a/packages/compiler/shims/hot-shots/client.ts b/packages/compiler/shims/hot-shots/client.ts new file mode 100644 index 000000000..d0b5c8924 --- /dev/null +++ b/packages/compiler/shims/hot-shots/client.ts @@ -0,0 +1,1033 @@ +// scriptc's built-in implementation of the `hot-shots` package, 8.x API: +// a typed port of hot-shots 8.5's StatsD client with the same datagrams, +// callbacks, error messages and child-client sharing, over node:dgram +// (udp), node:net (tcp) and a native Unix datagram socket (uds). The +// entry modules (v8.ts, v8-unix-dgram.ts) say whether the optional +// unix-dgram addon that hot-shots' uds protocol loads is installed. +import * as dgram from "node:dgram"; +import * as dns from "node:dns"; +import * as net from "node:net"; +import * as os from "node:os"; + +export type Tags = { [key: string]: string } | string[]; + +export interface ClientOptions { + bufferFlushInterval?: number; + bufferHolder?: { buffer: string }; + cacheDns?: boolean; + cacheDnsTtl?: number; + errorHandler?: (err: Error) => void; + globalTags?: Tags; + globalize?: boolean; + host?: string; + isChild?: boolean; + maxBufferSize?: number; + mock?: boolean; + path?: string; + port?: number; + prefix?: string; + protocol?: "tcp" | "udp" | "uds"; + sampleRate?: number; + suffix?: string; + telegraf?: boolean; + useDefaultRoute?: boolean; + tagPrefix?: string; + tagSeparator?: string; + udsGracefulErrorHandling?: boolean; + udsGracefulRestartRateLimit?: number; + closingFlushInterval?: number; +} + +export interface ChildClientOptions { + globalTags?: Tags; + prefix?: string; + suffix?: string; + errorHandler?: (err: Error) => void; +} + +export interface CheckOptions { + /** A Unix timestamp; hot-shots also takes a Date, which this shim's + * option records cannot hold yet. */ + date_happened?: number; + hostname?: string; + message?: string; +} + +export interface DatadogChecks { + OK: 0; + WARNING: 1; + CRITICAL: 2; + UNKNOWN: 3; +} + +export type DatadogChecksValues = 0 | 1 | 2 | 3; + +export interface EventOptions { + aggregation_key?: string; + alert_type?: "info" | "warning" | "success" | "error"; + /** A Unix timestamp; hot-shots also takes a Date, which this shim's + * option records cannot hold yet. */ + date_happened?: number; + hostname?: string; + priority?: "low" | "normal"; + source_type_name?: string; +} + +/** A send's completion: hot-shots passes `null` on success. */ +export type StatsCb = (error: Error | null | undefined, bytes?: any) => void; + +type SampleArg = number | Tags | StatsCb | undefined; +type TagsArg = Tags | StatsCb | undefined; + +const PROTOCOL_TCP = "tcp"; +const PROTOCOL_UDS = "uds"; +const PROTOCOL_UDP = "udp"; +const UDS_DEFAULT_GRACEFUL_RESTART_LIMIT = 1000; +const CACHE_DNS_TTL_DEFAULT = 60000; + +function udsErrorCodes(): number[] { + if (process.platform === "linux") { + return [os.constants.errno.ENOTCONN, os.constants.errno.ECONNREFUSED]; + } + if (process.platform === "darwin") { + return [os.constants.errno.EDESTADDRREQ, os.constants.errno.ECONNRESET]; + } + return []; +} +const UDS_ERROR_CODES = udsErrorCodes(); + +// ── helpers ────────────────────────────────────────────────────────────── + +function sanitizeTags(value: string, telegraf: boolean): string { + const blacklist = telegraf ? /:|\||,/g : /:|\||@|,/g; + return String(value).replace(blacklist, "_"); +} + +function formatTags(tags: Tags, telegraf: boolean): string[] { + if (Array.isArray(tags)) return tags; + const out: string[] = []; + for (const key of Object.keys(tags)) { + out.push(`${sanitizeTags(key, telegraf)}:${sanitizeTags(tags[key]!, telegraf)}`); + } + return out; +} + +function isArrayIndexKey(key: string): boolean { + return /^(0|[1-9]\d*)$/.test(key) && Number(key) < 4294967295; +} + +function overrideTags(parent: string[], child: Tags, telegraf: boolean): string[] { + const childKeys: string[] = []; + const childValues = new Map(); + const toAppend: string[] = []; + for (const tag of formatTags(child, telegraf)) { + const idx = tag.indexOf(":"); + if (idx < 1) { + toAppend.push(tag); + } else { + const key = tag.substring(0, idx); + const value = tag.substring(idx + 1); + let values = childValues.get(key); + if (values === undefined) { + values = []; + childValues.set(key, values); + childKeys.push(key); + } + values.push(value); + } + } + const result = parent.filter((tag) => { + const idx = tag.indexOf(":"); + if (idx < 1) return true; + return !childValues.has(tag.substring(0, idx)); + }); + // hot-shots walks an object's keys: array-index keys ascending first, + // then the rest in insertion order. + const indexKeys = childKeys.filter(isArrayIndexKey).sort((a, b) => Number(a) - Number(b)); + const ordered = indexKeys.concat(childKeys.filter((key) => !isArrayIndexKey(key))); + for (const key of ordered) { + for (const value of childValues.get(key)!) result.push(`${key}:${value}`); + } + return result.concat(toAppend); +} + +function formatDate(date: number): number { + return Math.round(date); +} + +function errorWithCode(message: string, code: string | undefined): Error { + const error: NodeJS.ErrnoException = new Error(message); + error.code = code; + return error; +} + +// ── transports ─────────────────────────────────────────────────────────── + +type SendCallback = (err: Error | null, bytes?: number) => void; + +/** The socket a client sends through (hot-shots' transport interface). */ +interface Transport { + createdAt: number; + send(buf: Buffer, callback: SendCallback): void; + close(): void; + onError(listener: (err: Error) => void): void; + offError(listener: (err: Error) => void): void; + onClose(listener: () => void): void; +} + +/** A socket's 'error' listeners, kept by the transport (the typed + * sockets have no removeListener): one socket listener dispatches to a + * snapshot, and an error nobody listens for throws, as an unhandled + * 'error' event does. */ +class ErrorListeners { + private listeners: ((err: Error) => void)[] = []; + add(listener: (err: Error) => void): void { + this.listeners.push(listener); + } + remove(listener: (err: Error) => void): void { + const index = this.listeners.indexOf(listener); + if (index !== -1) this.listeners.splice(index, 1); + } + emit(err: Error): void { + const snapshot = this.listeners.slice(); + if (snapshot.length === 0) throw err; + for (const listener of snapshot) listener(err); + } +} + +function addEol(buf: Buffer): string { + let msg = buf.toString(); + if (msg.length > 0 && msg[msg.length - 1] !== "\n") msg += "\n"; + return msg; +} + +class UdpTransport implements Transport { + createdAt = 0; + private readonly socket: dgram.Socket; + private readonly errors = new ErrorListeners(); + private resolvedAddress: string | undefined = undefined; + private resolvedAt = 0; + private readonly host: string | undefined; + private readonly port: number; + private readonly cacheDns: boolean; + private readonly cacheDnsTtl: number; + constructor(host: string | undefined, port: number, cacheDns: boolean, cacheDnsTtl: number) { + this.host = host; + this.port = port; + this.cacheDns = cacheDns; + this.cacheDnsTtl = cacheDnsTtl; + this.socket = dgram.createSocket("udp4"); + this.socket.unref(); + this.socket.on("error", (err) => this.errors.emit(err)); + } + send(buf: Buffer, callback: SendCallback): void { + if (!this.cacheDns) { + this.socket.send(buf, this.port, this.host || "127.0.0.1", callback); + return; + } + const now = Date.now(); + const cached = this.resolvedAddress; + if (cached === undefined || now - this.resolvedAt > this.cacheDnsTtl) { + dns.lookup(this.host ?? "localhost", (error, address) => { + if (error) { + callback(error); + return; + } + this.resolvedAddress = address; + this.resolvedAt = now; + this.socket.send(buf, this.port, address, callback); + }); + } else { + this.socket.send(buf, this.port, cached, callback); + } + } + close(): void { + this.socket.close(); + } + onError(listener: (err: Error) => void): void { + this.errors.add(listener); + } + offError(listener: (err: Error) => void): void { + this.errors.remove(listener); + } + onClose(listener: () => void): void { + this.socket.on("close", listener); + } +} + +class TcpTransport implements Transport { + createdAt = 0; + private readonly socket: net.Socket; + private readonly errors = new ErrorListeners(); + constructor(host: string | undefined, port: number) { + this.socket = net.connect(port, host ?? "localhost"); + this.socket.setKeepAlive(true); + this.socket.unref(); + this.socket.on("error", (err) => this.errors.emit(err)); + } + send(buf: Buffer, callback: SendCallback): void { + // The typed socket's write takes the data alone; the completion runs + // on the next tick. + this.socket.write(addEol(buf)); + process.nextTick(() => callback(null)); + } + close(): void { + this.socket.destroy(); + } + onError(listener: (err: Error) => void): void { + this.errors.add(listener); + } + offError(listener: (err: Error) => void): void { + this.errors.remove(listener); + } + onClose(listener: () => void): void { + this.socket.on("close", () => listener()); + } +} + +// The runtime's AF_UNIX datagram calls (the unix-dgram addon's binding): +// results >= 0, or a negative errno; send answers 1 when it would block. +declare function scriptcUnixDgramSocket(): number; +declare function scriptcUnixDgramConnect(fd: number, path: string): number; +declare function scriptcUnixDgramSend(fd: number, data: Buffer): number; +declare function scriptcUnixDgramClose(fd: number): number; + +let unixDgramInstalled = false; + +/** Whether the unix-dgram addon is installed beside hot-shots (set by the + * entry module). */ +export function configureUnixDgram(installed: boolean): void { + unixDgramInstalled = installed; +} + +const UDS_PATH_DEFAULT = "/var/run/datadog/dsd.socket"; + +/** unix-dgram's errnoException: " " (the code is the + * negative errno; this Error's code field holds its decimal string). */ +function errnoException(errorno: number, syscall: string): Error { + const error: NodeJS.ErrnoException = new Error(`${syscall} ${errorno}`); + error.errno = errorno; + error.code = String(errorno); + error.syscall = syscall; + return error; +} + +/** hot-shots' uds transport over unix-dgram: a connected, non-blocking + * AF_UNIX datagram socket. Sends complete synchronously, as the addon's + * do. The addon polls the socket for reads, which holds the event loop + * until close; a ref'd timer stands in for that poll. */ +class UdsTransport implements Transport { + createdAt = 0; + private fd: number; + private readonly errors = new ErrorListeners(); + private readonly closeListeners: (() => void)[] = []; + private readonly stopHold: () => void; + constructor(path: string) { + const fd = scriptcUnixDgramSocket(); + if (fd < 0) throw errnoException(fd, "socket"); + this.fd = fd; + const hold = setInterval(() => {}, 2147483647); + this.stopHold = () => clearInterval(hold); + const err = scriptcUnixDgramConnect(fd, path); + if (err < 0) { + // The addon emits the connect failure as 'error' before anyone + // listens, which throws; hot-shots closes the socket and rethrows. + this.close(); + throw errnoException(err, "connect"); + } + } + send(buf: Buffer, callback: SendCallback): void { + const result = scriptcUnixDgramSend(this.fd, buf); + if (result < 0) { + callback(errnoException(result, "send")); + } else if (result === 1) { + const congestion: NodeJS.ErrnoException = new Error("congestion"); + congestion.code = "1"; + callback(congestion); + } else { + callback(null); + } + } + close(): void { + const result = scriptcUnixDgramClose(this.fd); + if (result < 0) throw errnoException(result, "close"); + this.fd = -1; + this.stopHold(); + for (const listener of this.closeListeners.slice()) listener(); + } + onError(listener: (err: Error) => void): void { + this.errors.add(listener); + } + offError(listener: (err: Error) => void): void { + this.errors.remove(listener); + } + onClose(listener: () => void): void { + this.closeListeners.push(listener); + } +} + +/** hot-shots' createUdsTransport: without the unix-dgram addon the + * protocol reports it missing. */ +function createUdsTransport(path: string | undefined): Transport { + if (!unixDgramInstalled) { + throw new Error( + "The library `unix_dgram`, needed for the uds protocol to work, is not installed. " + + "You need to pick another protocol to use hot-shots. " + + "See the hot-shots README for additional details.", + ); + } + return new UdsTransport(path ? path : UDS_PATH_DEFAULT); +} + +function createTransport(client: StatsD): Transport | null { + let transport: Transport | null = null; + const protocol = client.protocol; + try { + if (protocol === PROTOCOL_TCP) { + transport = new TcpTransport(client.host, client.port); + } else if (protocol === PROTOCOL_UDS) { + transport = createUdsTransport(client.path); + } else if (protocol === PROTOCOL_UDP) { + transport = new UdpTransport(client.host, client.port, client.cacheDns, client.cacheDnsTtl); + } else { + throw new Error(`Unsupported protocol '${protocol}'`); + } + transport.createdAt = Date.now(); + } catch (e) { + const handler = client.errorHandler; + if (handler) { + handler(e as Error); + } else { + console.error(e); + } + } + return transport; +} + +// ── the client ─────────────────────────────────────────────────────────── + +class BufferHolder { + buffer = ""; +} + +/** What a child client inherits from its parent. */ +class ChildInit { + socket: Transport | null; + bufferHolder: BufferHolder; + dnsError: Error | undefined; + constructor(socket: Transport | null, bufferHolder: BufferHolder, dnsError: Error | undefined) { + this.socket = socket; + this.bufferHolder = bufferHolder; + this.dnsError = dnsError; + } +} + +export class StatsD { + protocol: string; + cacheDns: boolean; + cacheDnsTtl: number; + host: string | undefined; + port: number; + path: string | undefined; + prefix: string; + suffix: string; + tagPrefix: string; + tagSeparator: string; + mock: boolean; + globalTags: string[]; + telegraf: boolean; + maxBufferSize: number; + sampleRate: number; + bufferFlushInterval: number; + errorHandler: ((err: Error) => void) | undefined; + udsGracefulErrorHandling: boolean; + udsGracefulRestartRateLimit: number; + isChild: boolean; + closingFlushInterval: number; + mockBuffer: string[] | undefined = undefined; + messagesInFlight = 0; + CHECKS: DatadogChecks = { OK: 0, WARNING: 1, CRITICAL: 2, UNKNOWN: 3 }; + private bufferHolder: BufferHolder; + private transport: Transport | null = null; + private dnsError: Error | undefined = undefined; + private stopFlushInterval: (() => void) | undefined = undefined; + + constructor(options?: ClientOptions, child?: ChildInit) { + const o: ClientOptions = options ?? {}; + const protocol = o.protocol ? o.protocol.toLowerCase() : ""; + this.protocol = protocol ? protocol : PROTOCOL_UDP; + this.cacheDns = o.cacheDns === true; + this.cacheDnsTtl = o.cacheDnsTtl || CACHE_DNS_TTL_DEFAULT; + this.host = o.host || process.env["DD_AGENT_HOST"]; + this.port = o.port || parseInt(process.env["DD_DOGSTATSD_PORT"] ?? "", 10) || 8125; + this.path = o.path; + this.prefix = o.prefix || ""; + this.suffix = o.suffix || ""; + this.tagPrefix = o.tagPrefix || "#"; + this.tagSeparator = o.tagSeparator || ","; + this.mock = o.mock === true; + this.telegraf = o.telegraf || false; + const globalTags = o.globalTags; + this.globalTags = globalTags !== undefined ? formatTags(globalTags, this.telegraf) : []; + const entityId = process.env["DD_ENTITY_ID"]; + if (entityId) { + this.globalTags = this.globalTags.filter( + (item) => item.indexOf("dd.internal.entity_id:") !== 0, + ); + this.globalTags.push("dd.internal.entity_id:".concat(sanitizeTags(entityId, false))); + } + this.maxBufferSize = o.maxBufferSize || 0; + this.sampleRate = o.sampleRate || 1; + this.bufferFlushInterval = o.bufferFlushInterval || 1000; + this.bufferHolder = child !== undefined ? child.bufferHolder : new BufferHolder(); + this.errorHandler = o.errorHandler; + const graceful = o.udsGracefulErrorHandling; + this.udsGracefulErrorHandling = graceful === undefined ? true : graceful; + this.udsGracefulRestartRateLimit = + o.udsGracefulRestartRateLimit || UDS_DEFAULT_GRACEFUL_RESTART_LIMIT; + this.isChild = child !== undefined; + this.closingFlushInterval = o.closingFlushInterval || 50; + if (this.mock) this.mockBuffer = []; + if (child === undefined && this.maxBufferSize > 0) { + const handle = setInterval(() => this.onBufferFlushInterval(), this.bufferFlushInterval); + handle.unref(); + this.stopFlushInterval = () => clearInterval(handle); + } + if (child !== undefined) { + if (child.dnsError) this.dnsError = child.dnsError; + this.transport = child.socket; + } + if (!this.transport) this.transport = createTransport(this); + const handler = o.errorHandler; + const transport = this.transport; + if (transport !== null && child === undefined && handler) transport.onError(handler); + if (transport !== null && o.protocol === PROTOCOL_UDS) this.maybeAddUDSErrorHandler(); + } + + private maybeAddUDSErrorHandler(): void { + if (this.isChild || !this.udsGracefulErrorHandling) return; + const transport = this.transport; + if (transport !== null) transport.onError((err) => this.udsErrorHandler(err)); + } + + private udsErrorHandler(err: Error): void { + const code = Number((err as NodeJS.ErrnoException).code); + if (!UDS_ERROR_CODES.includes(-code)) return; + const socket = this.transport; + if (socket === null) return; + if (!socket.createdAt || Date.now() - socket.createdAt < this.udsGracefulRestartRateLimit) { + return; + } + const handler = this.errorHandler; + if (handler) socket.offError(handler); + const newSocket = createTransport(this); + if (newSocket === null) { + const errorMessage = "Could not replace UDS connection with new socket"; + if (handler) { + handler(new Error(errorMessage)); + } else { + console.error(errorMessage); + } + return; + } + socket.close(); + this.transport = newSocket; + this.maybeAddUDSErrorHandler(); + if (handler) { + newSocket.onError(handler); + } else { + newSocket.onError((error) => console.error(`hot-shots UDS error: ${String(error)}`)); + } + } + + // ── stats functions ── + + timing(stat: string | string[], time: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + timing(stat: string | string[], time: number, tags?: Tags, callback?: StatsCb): void; + timing(stat: string | string[], time: number, callback?: StatsCb): void; + timing(stat: string | string[], time: number, sampleRate?: number, callback?: StatsCb): void; + timing( + stat: string | string[], + time: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, time, "ms", sampleRate, tags, callback); + } + + increment(stat: string, tags?: Tags): void; + increment(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + increment(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + increment(stat: string | string[], value: number, callback?: StatsCb): void; + increment(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + increment( + stat: string | string[], + value?: number | Tags, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + // A non-number second argument of a two-argument call is the tags. + let amount = 1; + let tagArg: TagsArg = tags; + if (typeof value === "number") { + amount = value; + } else if (sampleRate === undefined && tags === undefined && callback === undefined) { + tagArg = value; + } + this.sendAll(stat, amount, "c", sampleRate, tagArg, callback); + } + + decrement(stat: string, tags?: Tags): void; + decrement(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, callback?: StatsCb): void; + decrement(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + decrement( + stat: string | string[], + value?: number | Tags, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + let amount = 1; + let tagArg: TagsArg = tags; + if (typeof value === "number") { + amount = value; + } else if (sampleRate === undefined && tags === undefined && callback === undefined) { + tagArg = value; + } + this.sendAll(stat, -amount, "c", sampleRate, tagArg, callback); + } + + histogram(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, callback?: StatsCb): void; + histogram(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + histogram( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "h", sampleRate, tags, callback); + } + + distribution(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, callback?: StatsCb): void; + distribution(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + distribution( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "d", sampleRate, tags, callback); + } + + gauge(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, callback?: StatsCb): void; + gauge(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + gauge( + stat: string | string[], + value: number, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "g", sampleRate, tags, callback); + } + + set(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, callback?: StatsCb): void; + set(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + set( + stat: string | string[], + value: number | string, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "s", sampleRate, tags, callback); + } + + unique(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, callback?: StatsCb): void; + unique(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + unique( + stat: string | string[], + value: number | string, + sampleRate?: SampleArg, + tags?: TagsArg, + callback?: StatsCb, + ): void { + this.sendAll(stat, value, "s", sampleRate, tags, callback); + } + + check( + name: string, + status: DatadogChecksValues, + options?: CheckOptions, + tags?: Tags | StatsCb, + callback?: StatsCb, + ): void { + if (this.telegraf) { + const err = new Error("Not supported by Telegraf / InfluxDB"); + if (callback) return callback(err); + const handler = this.errorHandler; + if (handler) return handler(err); + throw err; + } + const check: string[] = ["_sc", this.prefix + name + this.suffix, String(status)]; + const metadata: CheckOptions = options ?? {}; + const happened = metadata.date_happened; + if (happened) { + const timestamp = formatDate(happened); + if (timestamp) check.push(`d:${timestamp}`); + } + if (metadata.hostname) check.push(`h:${metadata.hostname}`); + let mergedTags = this.globalTags; + if (tags !== undefined && typeof tags !== "function") { + mergedTags = overrideTags(mergedTags, tags, this.telegraf); + } + if (mergedTags.length > 0) check.push(`#${mergedTags.join(",")}`); + if (metadata.message) check.push(`m:${metadata.message}`); + let cb = callback; + if (typeof tags === "function" && callback === undefined) cb = tags; + this.sendRaw(check.join("|"), cb); + } + + event( + title: string, + text?: string, + options?: EventOptions, + tags?: Tags | StatsCb, + callback?: StatsCb, + ): void { + if (this.telegraf) { + const err = new Error("Not supported by Telegraf / InfluxDB"); + if (callback) return callback(err); + const handler = this.errorHandler; + if (handler) return handler(err); + throw err; + } + const msgTitle = String(title ? title : ""); + let msgText = String(text ? text : msgTitle); + msgText = msgText.replace(/\n/g, "\\n"); + let message = `_e{${msgTitle.length},${msgText.length}}:${msgTitle}|${msgText}`; + if (options) { + const happened = options.date_happened; + if (happened) { + const timestamp = formatDate(happened); + if (timestamp) message += `|d:${timestamp}`; + } + if (options.hostname) message += `|h:${options.hostname}`; + if (options.aggregation_key) message += `|k:${options.aggregation_key}`; + if (options.priority) message += `|p:${options.priority}`; + if (options.source_type_name) message += `|s:${options.source_type_name}`; + if (options.alert_type) message += `|t:${options.alert_type}`; + } + let cb = callback; + let tagList: Tags | undefined = undefined; + if (typeof tags === "function") { + if (callback === undefined) cb = tags; + } else { + tagList = tags; + } + this.send(message, tagList, cb); + } + + // ── sending ── + + private sendAll( + stat: string | string[], + value: number | string, + type: string, + sampleRateArg: SampleArg, + tagsArg: TagsArg, + callbackArg: StatsCb | undefined, + ): void { + let sampleRate: number | undefined = undefined; + let tags: Tags | undefined = undefined; + let callback: StatsCb | undefined = callbackArg; + if (typeof sampleRateArg === "number") { + sampleRate = sampleRateArg; + if (typeof tagsArg === "function") { + callback = tagsArg; + } else { + tags = tagsArg; + } + } else if (sampleRateArg !== undefined) { + // A non-number sample rate shifts into the tags, and the tags + // argument into the callback. + if (typeof sampleRateArg === "function") { + callback = sampleRateArg; + } else { + tags = sampleRateArg; + callback = typeof tagsArg === "function" ? tagsArg : undefined; + } + } else if (typeof tagsArg === "function") { + callback = tagsArg; + } else { + tags = tagsArg; + } + + if (!Array.isArray(stat)) { + this.sendStat(stat, value, type, sampleRate, tags, callback); + return; + } + let completed = 0; + let calledback = false; + let sentBytes = 0; + const count = stat.length; + const onSend: StatsCb = (error, bytes) => { + completed += 1; + if (calledback) return; + if (error) { + if (callback !== undefined) { + calledback = true; + callback(error); + } else { + const handler = this.errorHandler; + if (handler) { + calledback = true; + handler(error); + } + } + return; + } + if (bytes) sentBytes += bytes as number; + if (completed === count && callback !== undefined) callback(null, sentBytes); + }; + for (const item of stat) this.sendStat(item, value, type, sampleRate, tags, onSend); + } + + private sendStat( + stat: string, + value: number | string, + type: string, + sampleRateArg: number | undefined, + tags: Tags | undefined, + callback: StatsCb | undefined, + ): void { + let message = `${this.prefix + stat + this.suffix}:${value}|${type}`; + const sampleRate = sampleRateArg || this.sampleRate; + if (sampleRate && sampleRate < 1) { + if (Math.random() < sampleRate) { + message += `|@${sampleRate}`; + } else { + if (callback) callback(undefined); + return; + } + } + this.send(message, tags, callback); + } + + private send(message: string, tags: Tags | undefined, callback: StatsCb | undefined): void { + let mergedTags = this.globalTags; + if (tags !== undefined) mergedTags = overrideTags(mergedTags, tags, this.telegraf); + if (mergedTags.length > 0) { + if (this.telegraf) { + const parts = message.split(":"); + message = `${parts[0]!},${mergedTags.join(",").replace(/:/g, "=")}:${parts.slice(1).join(":")}`; + } else { + message += `|${this.tagPrefix}${mergedTags.join(this.tagSeparator)}`; + } + } + this.sendRaw(message, callback); + } + + /** hot-shots' `_send`: the message with its tags. */ + private sendRaw(message: string, callback: StatsCb | undefined): void { + const dnsError = this.dnsError; + if (dnsError) { + if (callback) return callback(dnsError); + const handler = this.errorHandler; + if (handler) return handler(dnsError); + throw dnsError; + } + if (!this.mock) { + if (this.maxBufferSize === 0) { + this.sendMessage(message, callback); + } else { + this.enqueue(message, callback); + } + } else { + const buffer = this.mockBuffer; + if (buffer !== undefined) buffer.push(message); + if (callback) callback(null, 0); + } + } + + private enqueue(message: string, callback: StatsCb | undefined): void { + message += "\n"; + if (this.bufferHolder.buffer.length + message.length > this.maxBufferSize) { + this.flushQueue(callback); + this.bufferHolder.buffer += message; + } else { + this.bufferHolder.buffer += message; + if (callback) callback(null); + } + } + + private flushQueue(callback?: StatsCb): void { + this.sendMessage(this.bufferHolder.buffer, callback); + this.bufferHolder.buffer = ""; + } + + private sendMessage(message: string, callback: StatsCb | undefined): void { + if (message === "") { + if (callback) callback(null); + return; + } + const socketWasMissing = this.transport === null; + if (socketWasMissing && this.protocol === PROTOCOL_UDS) { + this.transport = createTransport(this); + if (this.transport !== null) this.maybeAddUDSErrorHandler(); + } + const socket = this.transport; + if (socketWasMissing || socket === null) { + const error = new Error("Socket not created properly. Check previous errors for details."); + if (callback) return callback(error); + const handler = this.errorHandler; + if (handler) return handler(error); + console.error(String(error)); + return; + } + const handleCallback = (err: Error | null, bytes?: number): void => { + this.messagesInFlight--; + let errFormatted: Error | null = null; + if (err) { + errFormatted = errorWithCode( + `Error sending hot-shots message: ${String(err)}`, + (err as NodeJS.ErrnoException).code, + ); + if (this.protocol === PROTOCOL_UDS && (callback || this.errorHandler)) { + this.udsErrorHandler(err); + } + } + if (callback) { + callback(errFormatted, bytes); + } else if (errFormatted) { + const handler = this.errorHandler; + if (handler) { + handler(errFormatted); + } else { + console.error(String(errFormatted)); + } + } + }; + try { + this.messagesInFlight++; + socket.send(Buffer.from(message), handleCallback); + } catch (err) { + handleCallback(err as Error); + } + } + + private onBufferFlushInterval(): void { + this.flushQueue(); + } + + close(callback?: (error?: Error) => void): void { + const stop = this.stopFlushInterval; + if (stop !== undefined) stop(); + this.flushQueue((err) => { + if (err) { + if (callback) return callback(err); + console.error(err); + return; + } + let intervalAttempts = 0; + const waitForMessages = setInterval(() => { + intervalAttempts++; + if (intervalAttempts > 10) { + console.log("hot-shots could not clear out messages in flight but closing anyways"); + this.messagesInFlight = 0; + } + if (this.messagesInFlight <= 0) { + clearInterval(waitForMessages); + this.closeSocket(callback); + } + }, this.closingFlushInterval); + }); + } + + private closeSocket(callback: ((error?: Error) => void) | undefined): void { + let handledError = false; + const handleErr = (err: unknown): void => { + const errMessage = `Error closing hot-shots socket: ${String(err)}`; + if (handledError) { + console.error(errMessage); + } else { + handledError = true; + if (callback) { + callback(new Error(errMessage)); + } else { + const handler = this.errorHandler; + if (handler) { + handler(new Error(errMessage)); + } else { + console.error(errMessage); + } + } + } + }; + const socket = this.transport; + if (socket === null) { + handleErr(new TypeError("Cannot read properties of null (reading 'removeListener')")); + return; + } + const handler = this.errorHandler; + if (handler) socket.offError(handler); + socket.onError(handleErr); + if (callback) { + socket.onClose(() => { + if (!handledError) callback(undefined); + }); + } + try { + socket.close(); + } catch (err) { + handleErr(err); + } + } + + childClient(options?: ChildClientOptions): StatsD { + const o: ChildClientOptions = options ?? {}; + const childTags = o.globalTags; + return new StatsD( + { + isChild: true, + errorHandler: o.errorHandler || this.errorHandler, + host: this.host, + port: this.port, + tagPrefix: this.tagPrefix, + tagSeparator: this.tagSeparator, + prefix: (o.prefix || "") + this.prefix, + suffix: this.suffix + (o.suffix || ""), + globalize: false, + mock: this.mock, + globalTags: + childTags !== undefined + ? overrideTags(this.globalTags, childTags, this.telegraf) + : this.globalTags, + maxBufferSize: this.maxBufferSize, + bufferFlushInterval: this.bufferFlushInterval, + telegraf: this.telegraf, + protocol: this.protocol === "tcp" ? "tcp" : this.protocol === "uds" ? "uds" : "udp", + closingFlushInterval: this.closingFlushInterval, + }, + new ChildInit(this.transport, this.bufferHolder, this.dnsError), + ); + } +} + +export default StatsD; diff --git a/packages/compiler/shims/hot-shots/v8-unix-dgram.ts b/packages/compiler/shims/hot-shots/v8-unix-dgram.ts new file mode 100644 index 000000000..f4bfb180e --- /dev/null +++ b/packages/compiler/shims/hot-shots/v8-unix-dgram.ts @@ -0,0 +1,8 @@ +// The hot-shots 8.x shim for installations with the optional unix-dgram +// addon: the uds protocol sends through a native Unix datagram socket. +import { configureUnixDgram } from "./client.ts"; + +configureUnixDgram(true); + +export * from "./client.ts"; +export { default } from "./client.ts"; diff --git a/packages/compiler/shims/hot-shots/v8.ts b/packages/compiler/shims/hot-shots/v8.ts index a8af7a19e..0d1871170 100644 --- a/packages/compiler/shims/hot-shots/v8.ts +++ b/packages/compiler/shims/hot-shots/v8.ts @@ -1,952 +1,8 @@ -// scriptc's built-in implementation of the `hot-shots` package, 8.x API. -// -// Programs whose installed hot-shots is 8.x compile this module in its -// place (packages/compiler/src/frontend/package-shims.ts). It is a typed -// port of hot-shots 8.5's StatsD client: the same datagrams, callbacks, -// error messages and child-client sharing, over node:dgram (udp) and -// node:net (tcp). The uds protocol needs the optional `unix-dgram` addon; -// this entry serves programs where it is not installed, so uds reports -// hot-shots' "not installed" error exactly as Node does. -import * as dgram from "node:dgram"; -import * as dns from "node:dns"; -import * as net from "node:net"; -import * as os from "node:os"; +// The hot-shots 8.x shim for installations without the optional unix-dgram +// addon: the uds protocol reports it missing, as hot-shots does under Node. +import { configureUnixDgram } from "./client.ts"; -export type Tags = { [key: string]: string } | string[]; +configureUnixDgram(false); -export interface ClientOptions { - bufferFlushInterval?: number; - bufferHolder?: { buffer: string }; - cacheDns?: boolean; - cacheDnsTtl?: number; - errorHandler?: (err: Error) => void; - globalTags?: Tags; - globalize?: boolean; - host?: string; - isChild?: boolean; - maxBufferSize?: number; - mock?: boolean; - path?: string; - port?: number; - prefix?: string; - protocol?: "tcp" | "udp" | "uds"; - sampleRate?: number; - suffix?: string; - telegraf?: boolean; - useDefaultRoute?: boolean; - tagPrefix?: string; - tagSeparator?: string; - udsGracefulErrorHandling?: boolean; - udsGracefulRestartRateLimit?: number; - closingFlushInterval?: number; -} - -export interface ChildClientOptions { - globalTags?: Tags; - prefix?: string; - suffix?: string; - errorHandler?: (err: Error) => void; -} - -export interface CheckOptions { - /** A Unix timestamp; hot-shots also takes a Date, which this shim's - * option records cannot hold yet. */ - date_happened?: number; - hostname?: string; - message?: string; -} - -export interface DatadogChecks { - OK: 0; - WARNING: 1; - CRITICAL: 2; - UNKNOWN: 3; -} - -export type DatadogChecksValues = 0 | 1 | 2 | 3; - -export interface EventOptions { - aggregation_key?: string; - alert_type?: "info" | "warning" | "success" | "error"; - /** A Unix timestamp; hot-shots also takes a Date, which this shim's - * option records cannot hold yet. */ - date_happened?: number; - hostname?: string; - priority?: "low" | "normal"; - source_type_name?: string; -} - -/** A send's completion: hot-shots passes `null` on success. */ -export type StatsCb = (error: Error | null | undefined, bytes?: any) => void; - -type SampleArg = number | Tags | StatsCb | undefined; -type TagsArg = Tags | StatsCb | undefined; - -const PROTOCOL_TCP = "tcp"; -const PROTOCOL_UDS = "uds"; -const PROTOCOL_UDP = "udp"; -const UDS_DEFAULT_GRACEFUL_RESTART_LIMIT = 1000; -const CACHE_DNS_TTL_DEFAULT = 60000; - -function udsErrorCodes(): number[] { - if (process.platform === "linux") { - return [os.constants.errno.ENOTCONN, os.constants.errno.ECONNREFUSED]; - } - if (process.platform === "darwin") { - return [os.constants.errno.EDESTADDRREQ, os.constants.errno.ECONNRESET]; - } - return []; -} -const UDS_ERROR_CODES = udsErrorCodes(); - -// ── helpers ────────────────────────────────────────────────────────────── - -function sanitizeTags(value: string, telegraf: boolean): string { - const blacklist = telegraf ? /:|\||,/g : /:|\||@|,/g; - return String(value).replace(blacklist, "_"); -} - -function formatTags(tags: Tags, telegraf: boolean): string[] { - if (Array.isArray(tags)) return tags; - const out: string[] = []; - for (const key of Object.keys(tags)) { - out.push(`${sanitizeTags(key, telegraf)}:${sanitizeTags(tags[key]!, telegraf)}`); - } - return out; -} - -function isArrayIndexKey(key: string): boolean { - return /^(0|[1-9]\d*)$/.test(key) && Number(key) < 4294967295; -} - -function overrideTags(parent: string[], child: Tags, telegraf: boolean): string[] { - const childKeys: string[] = []; - const childValues = new Map(); - const toAppend: string[] = []; - for (const tag of formatTags(child, telegraf)) { - const idx = tag.indexOf(":"); - if (idx < 1) { - toAppend.push(tag); - } else { - const key = tag.substring(0, idx); - const value = tag.substring(idx + 1); - let values = childValues.get(key); - if (values === undefined) { - values = []; - childValues.set(key, values); - childKeys.push(key); - } - values.push(value); - } - } - const result = parent.filter((tag) => { - const idx = tag.indexOf(":"); - if (idx < 1) return true; - return !childValues.has(tag.substring(0, idx)); - }); - // hot-shots walks an object's keys: array-index keys ascending first, - // then the rest in insertion order. - const indexKeys = childKeys.filter(isArrayIndexKey).sort((a, b) => Number(a) - Number(b)); - const ordered = indexKeys.concat(childKeys.filter((key) => !isArrayIndexKey(key))); - for (const key of ordered) { - for (const value of childValues.get(key)!) result.push(`${key}:${value}`); - } - return result.concat(toAppend); -} - -function formatDate(date: number): number { - return Math.round(date); -} - -function errorWithCode(message: string, code: string | undefined): Error { - const error: NodeJS.ErrnoException = new Error(message); - error.code = code; - return error; -} - -// ── transports ─────────────────────────────────────────────────────────── - -type SendCallback = (err: Error | null, bytes?: number) => void; - -/** The socket a client sends through (hot-shots' transport interface). */ -interface Transport { - createdAt: number; - send(buf: Buffer, callback: SendCallback): void; - close(): void; - onError(listener: (err: Error) => void): void; - offError(listener: (err: Error) => void): void; - onClose(listener: () => void): void; -} - -/** A socket's 'error' listeners, kept by the transport (the typed - * sockets have no removeListener): one socket listener dispatches to a - * snapshot, and an error nobody listens for throws, as an unhandled - * 'error' event does. */ -class ErrorListeners { - private listeners: ((err: Error) => void)[] = []; - add(listener: (err: Error) => void): void { - this.listeners.push(listener); - } - remove(listener: (err: Error) => void): void { - const index = this.listeners.indexOf(listener); - if (index !== -1) this.listeners.splice(index, 1); - } - emit(err: Error): void { - const snapshot = this.listeners.slice(); - if (snapshot.length === 0) throw err; - for (const listener of snapshot) listener(err); - } -} - -function addEol(buf: Buffer): string { - let msg = buf.toString(); - if (msg.length > 0 && msg[msg.length - 1] !== "\n") msg += "\n"; - return msg; -} - -class UdpTransport implements Transport { - createdAt = 0; - private readonly socket: dgram.Socket; - private readonly errors = new ErrorListeners(); - private resolvedAddress: string | undefined = undefined; - private resolvedAt = 0; - private readonly host: string | undefined; - private readonly port: number; - private readonly cacheDns: boolean; - private readonly cacheDnsTtl: number; - constructor(host: string | undefined, port: number, cacheDns: boolean, cacheDnsTtl: number) { - this.host = host; - this.port = port; - this.cacheDns = cacheDns; - this.cacheDnsTtl = cacheDnsTtl; - this.socket = dgram.createSocket("udp4"); - this.socket.unref(); - this.socket.on("error", (err) => this.errors.emit(err)); - } - send(buf: Buffer, callback: SendCallback): void { - if (!this.cacheDns) { - this.socket.send(buf, this.port, this.host || "127.0.0.1", callback); - return; - } - const now = Date.now(); - const cached = this.resolvedAddress; - if (cached === undefined || now - this.resolvedAt > this.cacheDnsTtl) { - dns.lookup(this.host ?? "localhost", (error, address) => { - if (error) { - callback(error); - return; - } - this.resolvedAddress = address; - this.resolvedAt = now; - this.socket.send(buf, this.port, address, callback); - }); - } else { - this.socket.send(buf, this.port, cached, callback); - } - } - close(): void { - this.socket.close(); - } - onError(listener: (err: Error) => void): void { - this.errors.add(listener); - } - offError(listener: (err: Error) => void): void { - this.errors.remove(listener); - } - onClose(listener: () => void): void { - this.socket.on("close", listener); - } -} - -class TcpTransport implements Transport { - createdAt = 0; - private readonly socket: net.Socket; - private readonly errors = new ErrorListeners(); - constructor(host: string | undefined, port: number) { - this.socket = net.connect(port, host ?? "localhost"); - this.socket.setKeepAlive(true); - this.socket.unref(); - this.socket.on("error", (err) => this.errors.emit(err)); - } - send(buf: Buffer, callback: SendCallback): void { - // The typed socket's write takes the data alone; the completion runs - // on the next tick. - this.socket.write(addEol(buf)); - process.nextTick(() => callback(null)); - } - close(): void { - this.socket.destroy(); - } - onError(listener: (err: Error) => void): void { - this.errors.add(listener); - } - offError(listener: (err: Error) => void): void { - this.errors.remove(listener); - } - onClose(listener: () => void): void { - this.socket.on("close", () => listener()); - } -} - -/** hot-shots reaches Unix datagram sockets through the optional - * `unix-dgram` addon; this entry serves programs without it. */ -function createUdsTransport(): Transport { - throw new Error( - "The library `unix_dgram`, needed for the uds protocol to work, is not installed. " + - "You need to pick another protocol to use hot-shots. " + - "See the hot-shots README for additional details.", - ); -} - -function createTransport(client: StatsD): Transport | null { - let transport: Transport | null = null; - const protocol = client.protocol; - try { - if (protocol === PROTOCOL_TCP) { - transport = new TcpTransport(client.host, client.port); - } else if (protocol === PROTOCOL_UDS) { - transport = createUdsTransport(); - } else if (protocol === PROTOCOL_UDP) { - transport = new UdpTransport(client.host, client.port, client.cacheDns, client.cacheDnsTtl); - } else { - throw new Error(`Unsupported protocol '${protocol}'`); - } - transport.createdAt = Date.now(); - } catch (e) { - const handler = client.errorHandler; - if (handler) { - handler(e as Error); - } else { - console.error(e); - } - } - return transport; -} - -// ── the client ─────────────────────────────────────────────────────────── - -class BufferHolder { - buffer = ""; -} - -/** What a child client inherits from its parent. */ -class ChildInit { - socket: Transport | null; - bufferHolder: BufferHolder; - dnsError: Error | undefined; - constructor(socket: Transport | null, bufferHolder: BufferHolder, dnsError: Error | undefined) { - this.socket = socket; - this.bufferHolder = bufferHolder; - this.dnsError = dnsError; - } -} - -export class StatsD { - protocol: string; - cacheDns: boolean; - cacheDnsTtl: number; - host: string | undefined; - port: number; - path: string | undefined; - prefix: string; - suffix: string; - tagPrefix: string; - tagSeparator: string; - mock: boolean; - globalTags: string[]; - telegraf: boolean; - maxBufferSize: number; - sampleRate: number; - bufferFlushInterval: number; - errorHandler: ((err: Error) => void) | undefined; - udsGracefulErrorHandling: boolean; - udsGracefulRestartRateLimit: number; - isChild: boolean; - closingFlushInterval: number; - mockBuffer: string[] | undefined = undefined; - messagesInFlight = 0; - CHECKS: DatadogChecks = { OK: 0, WARNING: 1, CRITICAL: 2, UNKNOWN: 3 }; - private bufferHolder: BufferHolder; - private transport: Transport | null = null; - private dnsError: Error | undefined = undefined; - private stopFlushInterval: (() => void) | undefined = undefined; - - constructor(options?: ClientOptions, child?: ChildInit) { - const o: ClientOptions = options ?? {}; - const protocol = o.protocol ? o.protocol.toLowerCase() : ""; - this.protocol = protocol ? protocol : PROTOCOL_UDP; - this.cacheDns = o.cacheDns === true; - this.cacheDnsTtl = o.cacheDnsTtl || CACHE_DNS_TTL_DEFAULT; - this.host = o.host || process.env["DD_AGENT_HOST"]; - this.port = o.port || parseInt(process.env["DD_DOGSTATSD_PORT"] ?? "", 10) || 8125; - this.path = o.path; - this.prefix = o.prefix || ""; - this.suffix = o.suffix || ""; - this.tagPrefix = o.tagPrefix || "#"; - this.tagSeparator = o.tagSeparator || ","; - this.mock = o.mock === true; - this.telegraf = o.telegraf || false; - const globalTags = o.globalTags; - this.globalTags = globalTags !== undefined ? formatTags(globalTags, this.telegraf) : []; - const entityId = process.env["DD_ENTITY_ID"]; - if (entityId) { - this.globalTags = this.globalTags.filter( - (item) => item.indexOf("dd.internal.entity_id:") !== 0, - ); - this.globalTags.push("dd.internal.entity_id:".concat(sanitizeTags(entityId, false))); - } - this.maxBufferSize = o.maxBufferSize || 0; - this.sampleRate = o.sampleRate || 1; - this.bufferFlushInterval = o.bufferFlushInterval || 1000; - this.bufferHolder = child !== undefined ? child.bufferHolder : new BufferHolder(); - this.errorHandler = o.errorHandler; - const graceful = o.udsGracefulErrorHandling; - this.udsGracefulErrorHandling = graceful === undefined ? true : graceful; - this.udsGracefulRestartRateLimit = - o.udsGracefulRestartRateLimit || UDS_DEFAULT_GRACEFUL_RESTART_LIMIT; - this.isChild = child !== undefined; - this.closingFlushInterval = o.closingFlushInterval || 50; - if (this.mock) this.mockBuffer = []; - if (child === undefined && this.maxBufferSize > 0) { - const handle = setInterval(() => this.onBufferFlushInterval(), this.bufferFlushInterval); - handle.unref(); - this.stopFlushInterval = () => clearInterval(handle); - } - if (child !== undefined) { - if (child.dnsError) this.dnsError = child.dnsError; - this.transport = child.socket; - } - if (!this.transport) this.transport = createTransport(this); - const handler = o.errorHandler; - const transport = this.transport; - if (transport !== null && child === undefined && handler) transport.onError(handler); - if (transport !== null && o.protocol === PROTOCOL_UDS) this.maybeAddUDSErrorHandler(); - } - - private maybeAddUDSErrorHandler(): void { - if (this.isChild || !this.udsGracefulErrorHandling) return; - const transport = this.transport; - if (transport !== null) transport.onError((err) => this.udsErrorHandler(err)); - } - - private udsErrorHandler(err: Error): void { - const code = Number((err as NodeJS.ErrnoException).code); - if (!UDS_ERROR_CODES.includes(-code)) return; - const socket = this.transport; - if (socket === null) return; - if (!socket.createdAt || Date.now() - socket.createdAt < this.udsGracefulRestartRateLimit) { - return; - } - const handler = this.errorHandler; - if (handler) socket.offError(handler); - const newSocket = createTransport(this); - if (newSocket === null) { - const errorMessage = "Could not replace UDS connection with new socket"; - if (handler) { - handler(new Error(errorMessage)); - } else { - console.error(errorMessage); - } - return; - } - socket.close(); - this.transport = newSocket; - this.maybeAddUDSErrorHandler(); - if (handler) { - newSocket.onError(handler); - } else { - newSocket.onError((error) => console.error(`hot-shots UDS error: ${String(error)}`)); - } - } - - // ── stats functions ── - - timing(stat: string | string[], time: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - timing(stat: string | string[], time: number, tags?: Tags, callback?: StatsCb): void; - timing(stat: string | string[], time: number, callback?: StatsCb): void; - timing(stat: string | string[], time: number, sampleRate?: number, callback?: StatsCb): void; - timing( - stat: string | string[], - time: number, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, time, "ms", sampleRate, tags, callback); - } - - increment(stat: string, tags?: Tags): void; - increment(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - increment(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; - increment(stat: string | string[], value: number, callback?: StatsCb): void; - increment(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; - increment( - stat: string | string[], - value?: number | Tags, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - // A non-number second argument of a two-argument call is the tags. - let amount = 1; - let tagArg: TagsArg = tags; - if (typeof value === "number") { - amount = value; - } else if (sampleRate === undefined && tags === undefined && callback === undefined) { - tagArg = value; - } - this.sendAll(stat, amount, "c", sampleRate, tagArg, callback); - } - - decrement(stat: string, tags?: Tags): void; - decrement(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - decrement(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; - decrement(stat: string | string[], value: number, callback?: StatsCb): void; - decrement(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; - decrement( - stat: string | string[], - value?: number | Tags, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - let amount = 1; - let tagArg: TagsArg = tags; - if (typeof value === "number") { - amount = value; - } else if (sampleRate === undefined && tags === undefined && callback === undefined) { - tagArg = value; - } - this.sendAll(stat, -amount, "c", sampleRate, tagArg, callback); - } - - histogram(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - histogram(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; - histogram(stat: string | string[], value: number, callback?: StatsCb): void; - histogram(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; - histogram( - stat: string | string[], - value: number, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, value, "h", sampleRate, tags, callback); - } - - distribution(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - distribution(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; - distribution(stat: string | string[], value: number, callback?: StatsCb): void; - distribution(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; - distribution( - stat: string | string[], - value: number, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, value, "d", sampleRate, tags, callback); - } - - gauge(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - gauge(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; - gauge(stat: string | string[], value: number, callback?: StatsCb): void; - gauge(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; - gauge( - stat: string | string[], - value: number, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, value, "g", sampleRate, tags, callback); - } - - set(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - set(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; - set(stat: string | string[], value: number | string, callback?: StatsCb): void; - set(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; - set( - stat: string | string[], - value: number | string, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, value, "s", sampleRate, tags, callback); - } - - unique(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; - unique(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; - unique(stat: string | string[], value: number | string, callback?: StatsCb): void; - unique(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; - unique( - stat: string | string[], - value: number | string, - sampleRate?: SampleArg, - tags?: TagsArg, - callback?: StatsCb, - ): void { - this.sendAll(stat, value, "s", sampleRate, tags, callback); - } - - check( - name: string, - status: DatadogChecksValues, - options?: CheckOptions, - tags?: Tags | StatsCb, - callback?: StatsCb, - ): void { - if (this.telegraf) { - const err = new Error("Not supported by Telegraf / InfluxDB"); - if (callback) return callback(err); - const handler = this.errorHandler; - if (handler) return handler(err); - throw err; - } - const check: string[] = ["_sc", this.prefix + name + this.suffix, String(status)]; - const metadata: CheckOptions = options ?? {}; - const happened = metadata.date_happened; - if (happened) { - const timestamp = formatDate(happened); - if (timestamp) check.push(`d:${timestamp}`); - } - if (metadata.hostname) check.push(`h:${metadata.hostname}`); - let mergedTags = this.globalTags; - if (tags !== undefined && typeof tags !== "function") { - mergedTags = overrideTags(mergedTags, tags, this.telegraf); - } - if (mergedTags.length > 0) check.push(`#${mergedTags.join(",")}`); - if (metadata.message) check.push(`m:${metadata.message}`); - let cb = callback; - if (typeof tags === "function" && callback === undefined) cb = tags; - this.sendRaw(check.join("|"), cb); - } - - event( - title: string, - text?: string, - options?: EventOptions, - tags?: Tags | StatsCb, - callback?: StatsCb, - ): void { - if (this.telegraf) { - const err = new Error("Not supported by Telegraf / InfluxDB"); - if (callback) return callback(err); - const handler = this.errorHandler; - if (handler) return handler(err); - throw err; - } - const msgTitle = String(title ? title : ""); - let msgText = String(text ? text : msgTitle); - msgText = msgText.replace(/\n/g, "\\n"); - let message = `_e{${msgTitle.length},${msgText.length}}:${msgTitle}|${msgText}`; - if (options) { - const happened = options.date_happened; - if (happened) { - const timestamp = formatDate(happened); - if (timestamp) message += `|d:${timestamp}`; - } - if (options.hostname) message += `|h:${options.hostname}`; - if (options.aggregation_key) message += `|k:${options.aggregation_key}`; - if (options.priority) message += `|p:${options.priority}`; - if (options.source_type_name) message += `|s:${options.source_type_name}`; - if (options.alert_type) message += `|t:${options.alert_type}`; - } - let cb = callback; - let tagList: Tags | undefined = undefined; - if (typeof tags === "function") { - if (callback === undefined) cb = tags; - } else { - tagList = tags; - } - this.send(message, tagList, cb); - } - - // ── sending ── - - private sendAll( - stat: string | string[], - value: number | string, - type: string, - sampleRateArg: SampleArg, - tagsArg: TagsArg, - callbackArg: StatsCb | undefined, - ): void { - let sampleRate: number | undefined = undefined; - let tags: Tags | undefined = undefined; - let callback: StatsCb | undefined = callbackArg; - if (typeof sampleRateArg === "number") { - sampleRate = sampleRateArg; - if (typeof tagsArg === "function") { - callback = tagsArg; - } else { - tags = tagsArg; - } - } else if (sampleRateArg !== undefined) { - // A non-number sample rate shifts into the tags, and the tags - // argument into the callback. - if (typeof sampleRateArg === "function") { - callback = sampleRateArg; - } else { - tags = sampleRateArg; - callback = typeof tagsArg === "function" ? tagsArg : undefined; - } - } else if (typeof tagsArg === "function") { - callback = tagsArg; - } else { - tags = tagsArg; - } - - if (!Array.isArray(stat)) { - this.sendStat(stat, value, type, sampleRate, tags, callback); - return; - } - let completed = 0; - let calledback = false; - let sentBytes = 0; - const count = stat.length; - const onSend: StatsCb = (error, bytes) => { - completed += 1; - if (calledback) return; - if (error) { - if (callback !== undefined) { - calledback = true; - callback(error); - } else { - const handler = this.errorHandler; - if (handler) { - calledback = true; - handler(error); - } - } - return; - } - if (bytes) sentBytes += bytes as number; - if (completed === count && callback !== undefined) callback(null, sentBytes); - }; - for (const item of stat) this.sendStat(item, value, type, sampleRate, tags, onSend); - } - - private sendStat( - stat: string, - value: number | string, - type: string, - sampleRateArg: number | undefined, - tags: Tags | undefined, - callback: StatsCb | undefined, - ): void { - let message = `${this.prefix + stat + this.suffix}:${value}|${type}`; - const sampleRate = sampleRateArg || this.sampleRate; - if (sampleRate && sampleRate < 1) { - if (Math.random() < sampleRate) { - message += `|@${sampleRate}`; - } else { - if (callback) callback(undefined); - return; - } - } - this.send(message, tags, callback); - } - - private send(message: string, tags: Tags | undefined, callback: StatsCb | undefined): void { - let mergedTags = this.globalTags; - if (tags !== undefined) mergedTags = overrideTags(mergedTags, tags, this.telegraf); - if (mergedTags.length > 0) { - if (this.telegraf) { - const parts = message.split(":"); - message = `${parts[0]!},${mergedTags.join(",").replace(/:/g, "=")}:${parts.slice(1).join(":")}`; - } else { - message += `|${this.tagPrefix}${mergedTags.join(this.tagSeparator)}`; - } - } - this.sendRaw(message, callback); - } - - /** hot-shots' `_send`: the message with its tags. */ - private sendRaw(message: string, callback: StatsCb | undefined): void { - const dnsError = this.dnsError; - if (dnsError) { - if (callback) return callback(dnsError); - const handler = this.errorHandler; - if (handler) return handler(dnsError); - throw dnsError; - } - if (!this.mock) { - if (this.maxBufferSize === 0) { - this.sendMessage(message, callback); - } else { - this.enqueue(message, callback); - } - } else { - const buffer = this.mockBuffer; - if (buffer !== undefined) buffer.push(message); - if (callback) callback(null, 0); - } - } - - private enqueue(message: string, callback: StatsCb | undefined): void { - message += "\n"; - if (this.bufferHolder.buffer.length + message.length > this.maxBufferSize) { - this.flushQueue(callback); - this.bufferHolder.buffer += message; - } else { - this.bufferHolder.buffer += message; - if (callback) callback(null); - } - } - - private flushQueue(callback?: StatsCb): void { - this.sendMessage(this.bufferHolder.buffer, callback); - this.bufferHolder.buffer = ""; - } - - private sendMessage(message: string, callback: StatsCb | undefined): void { - if (message === "") { - if (callback) callback(null); - return; - } - const socketWasMissing = this.transport === null; - if (socketWasMissing && this.protocol === PROTOCOL_UDS) { - this.transport = createTransport(this); - if (this.transport !== null) this.maybeAddUDSErrorHandler(); - } - const socket = this.transport; - if (socketWasMissing || socket === null) { - const error = new Error("Socket not created properly. Check previous errors for details."); - if (callback) return callback(error); - const handler = this.errorHandler; - if (handler) return handler(error); - console.error(String(error)); - return; - } - const handleCallback = (err: Error | null, bytes?: number): void => { - this.messagesInFlight--; - let errFormatted: Error | null = null; - if (err) { - errFormatted = errorWithCode( - `Error sending hot-shots message: ${String(err)}`, - (err as NodeJS.ErrnoException).code, - ); - if (this.protocol === PROTOCOL_UDS && (callback || this.errorHandler)) { - this.udsErrorHandler(err); - } - } - if (callback) { - callback(errFormatted, bytes); - } else if (errFormatted) { - const handler = this.errorHandler; - if (handler) { - handler(errFormatted); - } else { - console.error(String(errFormatted)); - } - } - }; - try { - this.messagesInFlight++; - socket.send(Buffer.from(message), handleCallback); - } catch (err) { - handleCallback(err as Error); - } - } - - private onBufferFlushInterval(): void { - this.flushQueue(); - } - - close(callback?: (error?: Error) => void): void { - const stop = this.stopFlushInterval; - if (stop !== undefined) stop(); - this.flushQueue((err) => { - if (err) { - if (callback) return callback(err); - console.error(err); - return; - } - let intervalAttempts = 0; - const waitForMessages = setInterval(() => { - intervalAttempts++; - if (intervalAttempts > 10) { - console.log("hot-shots could not clear out messages in flight but closing anyways"); - this.messagesInFlight = 0; - } - if (this.messagesInFlight <= 0) { - clearInterval(waitForMessages); - this.closeSocket(callback); - } - }, this.closingFlushInterval); - }); - } - - private closeSocket(callback: ((error?: Error) => void) | undefined): void { - let handledError = false; - const handleErr = (err: unknown): void => { - const errMessage = `Error closing hot-shots socket: ${String(err)}`; - if (handledError) { - console.error(errMessage); - } else { - handledError = true; - if (callback) { - callback(new Error(errMessage)); - } else { - const handler = this.errorHandler; - if (handler) { - handler(new Error(errMessage)); - } else { - console.error(errMessage); - } - } - } - }; - const socket = this.transport; - if (socket === null) { - handleErr(new TypeError("Cannot read properties of null (reading 'removeListener')")); - return; - } - const handler = this.errorHandler; - if (handler) socket.offError(handler); - socket.onError(handleErr); - if (callback) { - socket.onClose(() => { - if (!handledError) callback(undefined); - }); - } - try { - socket.close(); - } catch (err) { - handleErr(err); - } - } - - childClient(options?: ChildClientOptions): StatsD { - const o: ChildClientOptions = options ?? {}; - const childTags = o.globalTags; - return new StatsD( - { - isChild: true, - errorHandler: o.errorHandler || this.errorHandler, - host: this.host, - port: this.port, - tagPrefix: this.tagPrefix, - tagSeparator: this.tagSeparator, - prefix: (o.prefix || "") + this.prefix, - suffix: this.suffix + (o.suffix || ""), - globalize: false, - mock: this.mock, - globalTags: - childTags !== undefined - ? overrideTags(this.globalTags, childTags, this.telegraf) - : this.globalTags, - maxBufferSize: this.maxBufferSize, - bufferFlushInterval: this.bufferFlushInterval, - telegraf: this.telegraf, - protocol: this.protocol === "tcp" ? "tcp" : this.protocol === "uds" ? "uds" : "udp", - closingFlushInterval: this.closingFlushInterval, - }, - new ChildInit(this.transport, this.bufferHolder, this.dnsError), - ); - } -} - -export default StatsD; +export * from "./client.ts"; +export { default } from "./client.ts"; diff --git a/packages/compiler/src/backend/llvm/lib-datagram.ts b/packages/compiler/src/backend/llvm/lib-datagram.ts index 184fdb99e..6e10e9c62 100644 --- a/packages/compiler/src/backend/llvm/lib-datagram.ts +++ b/packages/compiler/src/backend/llvm/lib-datagram.ts @@ -105,6 +105,10 @@ export function emitDatagramLibCall(host: LlvmEmitterContext, e: LibCallExpr): L "dgram.sendStr": "scr_dgram_send_str", "dgram.sendBytes": "scr_dgram_send_bytes", "dgram.sendChk": "scr_dgram_send_chk", + "dgram.unixSocket": "scr_dgram_unix_socket", + "dgram.unixConnect": "scr_dgram_unix_connect", + "dgram.unixSend": "scr_dgram_unix_send", + "dgram.unixClose": "scr_dgram_unix_close", "dgram.ref": "scr_dgram_ref", "dgram.unref": "scr_dgram_unref", "dgram.setBroadcast": "scr_dgram_set_broadcast", diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 53971c7b0..3c04924c0 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -45,6 +45,7 @@ import { errorToStringCall } from "./error-methods.js"; import { lowerClassPrototypeAssign, lowerClassPrototypeDescriptors } from "./class-prototypes.js"; import { BYTES_ELEMENT_NAME, + BYTES_U8, BIGINT_T, BOOL, CAUGHT, @@ -53,6 +54,7 @@ import { F64, type IrExpr, type IrFunction, + type IrLibFn, type IrLocal, type IrParam, type IrStmt, @@ -76,6 +78,7 @@ import { } from "../../ir/ir.js"; import { lowerProtocolMethodCall } from "./class-protocol-dispatch.js"; import { isJsSourceFile, locOf, requireSpecOf } from "../program.js"; +import { isPackageShimFile, isShimIntrinsicName } from "../package-shims.js"; import { lowerJsonRequireCall } from "./json-require.js"; import { lowerAssertInstanceCall } from "./assert-instances.js"; import { @@ -292,6 +295,12 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const codeGeneration = codeGenerationCalleeOf(lowerer, expr.expression); if (codeGeneration !== null) return lowerCodeGenerationCall(lowerer, expr, codeGeneration); } + // 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)) { + const intrinsic = lowerShimIntrinsicCall(lowerer, expr, expr.expression, loc); + if (intrinsic) return intrinsic; + } // Inline require() of a program module (cjs-inline-require.ts): a // member call over its export table resolves like a binding's member // call after the module's %init at this position; the require itself @@ -10958,3 +10967,37 @@ function fenceClassCopyIntoFreshObject( `Object.assign copying a '${lowerer.fmt(rawSource.type)}' instance into a fresh object typed as the class (the copy is a plain object holding the instance's own fields, not an instance — build the object literal from the fields you need)`, ); } + +/** The runtime calls package shims declare as bodiless functions. */ +const SHIM_INTRINSICS: ReadonlyMap = new Map< + string, + { fn: IrLibFn; args: IrType[]; ret: IrType } +>([ + ["scriptcUnixDgramSocket", { fn: "dgram.unixSocket", args: [], ret: F64 }], + ["scriptcUnixDgramConnect", { fn: "dgram.unixConnect", args: [F64, STRING], ret: F64 }], + ["scriptcUnixDgramSend", { fn: "dgram.unixSend", args: [F64, BYTES_U8], ret: F64 }], + ["scriptcUnixDgramClose", { fn: "dgram.unixClose", args: [F64], ret: F64 }], +]); + +function lowerShimIntrinsicCall( + lowerer: Lowerer, + expr: ts.CallExpression, + callee: ts.Identifier, + loc: SrcLoc, +): IrExpr | null { + const intrinsic = SHIM_INTRINSICS.get(callee.text); + if (intrinsic === undefined) return null; + const decl = lowerer.checker.getSymbolAtLocation(callee)?.valueDeclaration; + if ( + decl === undefined || + !ts.isFunctionDeclaration(decl) || + decl.body || + !isPackageShimFile(ts.getSourceFileOfNode(decl).fileName) || + expr.arguments.nodes.length !== intrinsic.args.length + ) + return null; + const args = expr.arguments.nodes.map((arg, i) => + lowerer.lowerExprExpecting(arg, intrinsic.args[i]!), + ); + return { kind: "libCall", fn: intrinsic.fn, args, type: intrinsic.ret, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-namespaces.ts b/packages/compiler/src/frontend/lowering/lower-namespaces.ts index 19123dae3..ea844ab1e 100644 --- a/packages/compiler/src/frontend/lowering/lower-namespaces.ts +++ b/packages/compiler/src/frontend/lowering/lower-namespaces.ts @@ -38,7 +38,7 @@ * calls). */ import { positionTag, type PositionTagOwner } from "./structural-positions.js"; import * as ts from "../ts7/adapter.js"; -import { packageShimFor } from "../package-shims.js"; +import { isPackageShimFile, isShimIntrinsicName, packageShimFor } from "../package-shims.js"; import type { Lowerer } from "./lowerer.js"; import { boundIdentifiersOf } from "./lowerer.js"; import type { FileParts } from "./lower-modules.js"; @@ -654,6 +654,12 @@ export function ambientUndefinedFnSymbolOf( const sym = lowerer.resolveValueSymbol(ident); if (!sym || !(sym.flags & ts.SymbolFlags.Function)) return null; if (lowerer.isStdlibSymbol(sym)) return null; + // A package shim's runtime intrinsic (lower-calls.ts) is defined. + if ( + isShimIntrinsicName(ident.text) && + sym.declarations.some((d) => isPackageShimFile(ts.getSourceFileOfNode(d).fileName)) + ) + return null; let sawFn = false; for (const d of sym.declarations) { if (ts.isInterfaceDeclaration(d) || ts.isTypeAliasDeclaration(d)) continue; // type-world merge partners diff --git a/packages/compiler/src/frontend/package-shims.ts b/packages/compiler/src/frontend/package-shims.ts index f9cf1deb6..3af7ebf59 100644 --- a/packages/compiler/src/frontend/package-shims.ts +++ b/packages/compiler/src/frontend/package-shims.ts @@ -65,9 +65,14 @@ interface ImplementationShim { /** The package's declaration entry relative to its directory, when it * is not `index.d.ts`. */ typesFile?: string; + /** An alternative entry for this installation (relative to the shim + * root), or undefined for the version's own entry. */ + variant?: (pkgDir: string) => string | undefined; + /** Every variant entry, for the guard test that compiles each one. */ + variants?: readonly string[]; } -const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ +const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ [ "fs-extra", { @@ -100,6 +105,13 @@ const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ mainFile: "index.js", typesFile: "types.d.ts", versions: new Map([[8, "hot-shots/v8.ts"]]), + // hot-shots' uds protocol loads the optional unix-dgram addon: where + // it is installed, the entry with the native Unix datagram transport. + variant: (pkgDir: string) => + installedPackageDir(join(pkgDir, "index.js"), "unix-dgram") === null + ? undefined + : "hot-shots/v8-unix-dgram.ts", + variants: ["hot-shots/v8-unix-dgram.ts"], }, ], [ @@ -164,8 +176,10 @@ export function throughBundledShimForwarder(resolved: string): string { * the guard test that compiles each one. */ export function packageShimEntries(): string[] { const entries = new Set(); - for (const shim of IMPLEMENTATION_SHIMS.values()) + for (const shim of IMPLEMENTATION_SHIMS.values()) { for (const entry of shim.versions.values()) entries.add(join(packageShimRoot(), entry)); + for (const entry of shim.variants ?? []) entries.add(join(packageShimRoot(), entry)); + } return [...entries].sort(); } @@ -263,7 +277,8 @@ function shimEntryForPackageDir(pkgDir: string, expectedName: string | null): st if (shim === undefined) return null; const major = Number(/^(\d+)\./.exec(pkg.version)?.[1] ?? NaN); const entry = shim.versions.get(major); - return entry === undefined ? null : join(packageShimRoot(), entry); + if (entry === undefined) return null; + return join(packageShimRoot(), shim.variant?.(pkgDir) ?? entry); } /** The shim module `specifier` resolves to from `fromFile`, or null. Only @@ -355,6 +370,12 @@ export function isPackageShimFile(fileName: string): boolean { return fileName.startsWith(root.endsWith("/") ? root : `${root}/`); } +/** True for a name a shipped shim may declare as a bodiless runtime + * intrinsic (lower-calls.ts lowers its calls to runtime calls). */ +export function isShimIntrinsicName(name: string): boolean { + return name.startsWith("scriptcUnixDgram"); +} + /** Resets per-compile caches. */ export function clearPackageShimCaches(): void { installedCache.clear(); diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index fcdbe8694..29385db37 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1528,6 +1528,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ }, "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 diff --git a/packages/runtime/src/scr_dgram.c b/packages/runtime/src/scr_dgram.c index bb14d063e..8d1c7b058 100644 --- a/packages/runtime/src/scr_dgram.c +++ b/packages/runtime/src/scr_dgram.c @@ -2158,3 +2158,73 @@ void scr_dgram_send_chk(ScrDgramSocket *s, const ScrDyn *buffer, const ScrDyn *a * it removes a 'message' listener. Defined last so the functions above * keep their emission order. */ void scr_dgram_rearm(ScrDgramSocket *s) { scr_dgram_update_read(s); } + +/* ── Unix datagram sockets for the hot-shots package shim ────────────── + * The unix-dgram addon's surface, which hot-shots' uds transport uses: a + * non-blocking AF_UNIX datagram socket connected to a path. Each call + * answers its result (fd, 0) or a negative errno, as the addon's binding + * does; send answers 1 when the socket would block (the addon's + * "congestion"). Defined after the functions above so their emission + * order is unchanged. */ +#ifndef _WIN32 +#include +#endif + +double scr_dgram_unix_socket(void) { +#ifdef _WIN32 + return -(double)ENOSYS; +#else + int fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) return -(double)errno; + int flags = fcntl(fd, F_GETFL, 0); + if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK); + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + return (double)fd; +#endif +} + +double scr_dgram_unix_connect(double fd, ScrStr *path) { +#ifdef _WIN32 + (void)fd; + (void)path; + return -(double)ENOSYS; +#else + struct sockaddr_un addr; + memset(&addr, 0, sizeof addr); + addr.sun_family = AF_UNIX; + char *owned; + const char *bytes = scr_str_utf8(path, &owned); + size_t n = strlen(bytes); + if (n > sizeof addr.sun_path - 1) n = sizeof addr.sun_path - 1; + memcpy(addr.sun_path, bytes, n); + scr_str_utf8_end(owned); + if (connect((int)fd, (struct sockaddr *)&addr, sizeof addr) != 0) return -(double)errno; + return 0; +#endif +} + +double scr_dgram_unix_send(double fd, ScrBytes *data) { +#ifdef _WIN32 + (void)fd; + (void)data; + return -(double)ENOSYS; +#else + SCR_BYTES_SNAPSHOT(data); + ssize_t sent; + do { + sent = send((int)fd, data->data, data->len, 0); + } while (sent < 0 && errno == EINTR); + if (sent >= 0) return 0; + if (errno == EAGAIN || errno == EWOULDBLOCK) return 1; + return -(double)errno; +#endif +} + +double scr_dgram_unix_close(double fd) { +#ifdef _WIN32 + (void)fd; + return -(double)ENOSYS; +#else + return close((int)fd) != 0 ? -(double)errno : 0; +#endif +} From eef238eb9473ac937c5cf9ed1d1af73cc8930f8c Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 21:59:20 -0700 Subject: [PATCH 06/45] Pin chalk builder values and buffered hot-shots against Node A callable class instance in a narrower function slot crosses the checked function boundary. New npm cases: chalk5-builder, hot-shots-buffered. Co-Authored-By: Claude Opus 5.5 --- .../compiler/src/frontend/lowering/lowerer.ts | 16 + .../compiler/test/package-shim-guard.test.ts | 3 + .../fixtures/npm/cases/chalk5-builder/main.ts | 45 +++ .../chalk5-builder/node_modules/chalk/license | 9 + .../node_modules/chalk/package.json | 83 +++++ .../node_modules/chalk/source/index.d.ts | 325 ++++++++++++++++++ .../node_modules/chalk/source/index.js | 225 ++++++++++++ .../node_modules/chalk/source/utilities.js | 33 ++ .../source/vendor/ansi-styles/index.d.ts | 236 +++++++++++++ .../chalk/source/vendor/ansi-styles/index.js | 223 ++++++++++++ .../source/vendor/supports-color/browser.d.ts | 1 + .../source/vendor/supports-color/browser.js | 34 ++ .../source/vendor/supports-color/index.d.ts | 55 +++ .../source/vendor/supports-color/index.js | 190 ++++++++++ .../npm/cases/chalk5-builder/package.json | 1 + .../npm/cases/hot-shots-buffered/main.ts | 80 +++++ .../npm/cases/hot-shots-buffered/package.json | 1 + 17 files changed, 1560 insertions(+) create mode 100644 tests/fixtures/npm/cases/chalk5-builder/main.ts create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/license create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/package.json create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.js create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/utilities.js create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.js create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.js create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.d.ts create mode 100644 tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.js create mode 100644 tests/fixtures/npm/cases/chalk5-builder/package.json create mode 100644 tests/fixtures/npm/cases/hot-shots-buffered/main.ts create mode 100644 tests/fixtures/npm/cases/hot-shots-buffered/package.json diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b1867be32..ac1a778cf 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -230,6 +230,7 @@ import { arrayOf, BOOL, canAdaptDynFuncTo, + canBoxFuncIntoDyn, canDynCheckTo, canConvertToDyn, DYN, @@ -9642,6 +9643,21 @@ export class Lowerer { if (expected.kind === "func" && (expr.type.kind === "record" || expr.type.kind === "object")) { const un = this.hybridCallUnwrap(expr); if (un !== expr && typeEquals(un.type, expected)) return un; + // A callable class instance (the chalk shim's variadic builder) in a + // narrower function slot: its call closure crosses the checked + // function boundary, which adapts the arity. + if ( + un !== expr && + expr.type.kind === "object" && + un.type.kind === "func" && + canBoxFuncIntoDyn( + un.type, + (id) => this.shapes.get(id), + (id) => this.unions.get(id), + ) + ) { + return this.coerceToExpected({ kind: "dynFrom", value: un, type: DYN, loc: un.loc }, expected); + } } // A zero-param function whose RETURN is a wider record array than the // slot's (`getRoutes: () => cachedRoutes` against `() => Narrow[]`): diff --git a/packages/compiler/test/package-shim-guard.test.ts b/packages/compiler/test/package-shim-guard.test.ts index ff01acbb8..a8620c1ce 100644 --- a/packages/compiler/test/package-shim-guard.test.ts +++ b/packages/compiler/test/package-shim-guard.test.ts @@ -49,7 +49,10 @@ describe("package shims compile without refusals", () => { const entries = packageShimEntries(); test("the registry lists its shim modules", () => { expect(entries.map((e) => e.slice(shimRoot.length + 1))).toEqual([ + "chalk/v5.ts", "fs-extra/index.ts", + "hot-shots/v8-unix-dgram.ts", + "hot-shots/v8.ts", "undici/v5.ts", "undici/v7.ts", ]); diff --git a/tests/fixtures/npm/cases/chalk5-builder/main.ts b/tests/fixtures/npm/cases/chalk5-builder/main.ts new file mode 100644 index 000000000..8f2623717 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/main.ts @@ -0,0 +1,45 @@ +// chalk 5 builders used as values (the package compiles from scriptc's +// built-in shim): builders in function slots and arrays, styles picked at +// run time, visible at level 0, chalkStderr, and the root's own call. +import chalk, { Chalk, chalkStderr, type ChalkInstance, type ForegroundColorName } from "chalk"; + +const show = (label: string, value: string): void => { + console.log(label + " " + JSON.stringify(value)); +}; + +const c = new Chalk({ level: 1 }); +const paint: (text: string) => string = c.green; +show("slot", paint("go")); +const styles: ChalkInstance[] = [c.red, c.bold, c.underline.blue]; +show("array", styles.map((style) => style("x")).join("|")); +const byName = (name: ForegroundColorName): ChalkInstance => { + switch (name) { + case "red": + return c.red; + case "green": + return c.green; + default: + return c.white; + } +}; +show("picked", byName("red")("r") + byName("green")("g") + byName("cyan")("w")); +let chain: ChalkInstance = c; +for (const step of ["bold", "italic", "yellow"]) { + chain = step === "bold" ? chain.bold : step === "italic" ? chain.italic : chain.yellow; +} +show("built", chain("chain")); +show("cached", c.red === c.red ? "same" : "different"); +show("nested close", c.red("a" + c.blue("b") + "c" + c.red("d") + "e")); +show("bg nested", c.bgRed("a" + c.bgBlue("b") + "c")); + +const off = new Chalk({ level: 0 }); +show("visible off", off.visible("v") + "|" + off.red.visible("v") + "|" + off.red("plain")); +show("root call", c("a", 1, true) + "|" + c() + "|" + c(undefined) + "|" + c(null, "n")); +show("builder args", c.red(undefined) + "|" + c.red(null) + "|" + c.red(1, 2) + "|" + c.red()); +show("multiline", c.cyan("one\r\ntwo\nthree")); +show("stderr level", String(chalkStderr.level >= 0)); +show("rgb levels", [1, 2, 3].map((level) => new Chalk({ level: level as 1 | 2 | 3 }).rgb(255, 136, 0)("o")).join("|")); +show("hex bg", new Chalk({ level: 2 }).bgHex("#abcdef")("h") + new Chalk({ level: 1 }).bgHex("123")("i")); +c.level = 0; +show("after level 0", paint("go") + "|" + c.red("r")); +show("default red", chalk.level >= 0 ? "ok" : "bad"); diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/license b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/license new file mode 100644 index 000000000..fa7ceba3e --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +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/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/package.json b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/package.json new file mode 100644 index 000000000..c9e0dc52b --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/package.json @@ -0,0 +1,83 @@ +{ + "name": "chalk", + "version": "5.6.2", + "description": "Terminal string styling done right", + "license": "MIT", + "repository": "chalk/chalk", + "funding": "https://github.com/chalk/chalk?sponsor=1", + "type": "module", + "main": "./source/index.js", + "exports": "./source/index.js", + "imports": { + "#ansi-styles": "./source/vendor/ansi-styles/index.js", + "#supports-color": { + "node": "./source/vendor/supports-color/index.js", + "default": "./source/vendor/supports-color/browser.js" + } + }, + "types": "./source/index.d.ts", + "sideEffects": false, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "scripts": { + "test": "xo && c8 ava && tsd", + "bench": "matcha benchmark.js" + }, + "files": [ + "source", + "!source/index.test-d.ts" + ], + "keywords": [ + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "ansi", + "style", + "styles", + "tty", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "devDependencies": { + "@types/node": "^16.11.10", + "ava": "^3.15.0", + "c8": "^7.10.0", + "color-convert": "^2.0.1", + "execa": "^6.0.0", + "log-update": "^5.0.0", + "matcha": "^0.7.0", + "tsd": "^0.19.0", + "xo": "^0.57.0", + "yoctodelay": "^2.0.0" + }, + "xo": { + "rules": { + "unicorn/prefer-string-slice": "off", + "@typescript-eslint/consistent-type-imports": "off", + "@typescript-eslint/consistent-type-exports": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "unicorn/expiring-todo-comments": "off" + } + }, + "c8": { + "reporter": [ + "text", + "lcov" + ], + "exclude": [ + "source/vendor" + ] + } +} diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.d.ts b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.d.ts new file mode 100644 index 000000000..8295d9252 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.d.ts @@ -0,0 +1,325 @@ +// TODO: Make it this when TS suports that. +// import {ModifierName, ForegroundColor, BackgroundColor, ColorName} from '#ansi-styles'; +// import {ColorInfo, ColorSupportLevel} from '#supports-color'; +import { + ModifierName, + ForegroundColorName, + BackgroundColorName, + ColorName, +} from './vendor/ansi-styles/index.js'; +import {ColorInfo, ColorSupportLevel} from './vendor/supports-color/index.js'; + +export interface Options { + /** + Specify the color support for Chalk. + + By default, color support is automatically detected based on the environment. + + Levels: + - `0` - All colors disabled. + - `1` - Basic 16 colors support. + - `2` - ANSI 256 colors support. + - `3` - Truecolor 16 million colors support. + */ + readonly level?: ColorSupportLevel; +} + +/** +Return a new Chalk instance. +*/ +export const Chalk: new (options?: Options) => ChalkInstance; // eslint-disable-line @typescript-eslint/naming-convention + +export interface ChalkInstance { + (...text: unknown[]): string; + + /** + The color support for Chalk. + + By default, color support is automatically detected based on the environment. + + Levels: + - `0` - All colors disabled. + - `1` - Basic 16 colors support. + - `2` - ANSI 256 colors support. + - `3` - Truecolor 16 million colors support. + */ + level: ColorSupportLevel; + + /** + Use RGB values to set text color. + + @example + ``` + import chalk from 'chalk'; + + chalk.rgb(222, 173, 237); + ``` + */ + rgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set text color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.hex('#DEADED'); + ``` + */ + hex: (color: string) => this; + + /** + Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color. + + @example + ``` + import chalk from 'chalk'; + + chalk.ansi256(201); + ``` + */ + ansi256: (index: number) => this; + + /** + Use RGB values to set background color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgRgb(222, 173, 237); + ``` + */ + bgRgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set background color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgHex('#DEADED'); + ``` + */ + bgHex: (color: string) => this; + + /** + Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgAnsi256(201); + ``` + */ + bgAnsi256: (index: number) => this; + + /** + Modifier: Reset the current style. + */ + readonly reset: this; + + /** + Modifier: Make the text bold. + */ + readonly bold: this; + + /** + Modifier: Make the text have lower opacity. + */ + readonly dim: this; + + /** + Modifier: Make the text italic. *(Not widely supported)* + */ + readonly italic: this; + + /** + Modifier: Put a horizontal line below the text. *(Not widely supported)* + */ + readonly underline: this; + + /** + Modifier: Put a horizontal line above the text. *(Not widely supported)* + */ + readonly overline: this; + + /** + Modifier: Invert background and foreground colors. + */ + readonly inverse: this; + + /** + Modifier: Print the text but make it invisible. + */ + readonly hidden: this; + + /** + Modifier: Puts a horizontal line through the center of the text. *(Not widely supported)* + */ + readonly strikethrough: this; + + /** + Modifier: Print the text only when Chalk has a color level above zero. + + Can be useful for things that are purely cosmetic. + */ + readonly visible: this; + + readonly black: this; + readonly red: this; + readonly green: this; + readonly yellow: this; + readonly blue: this; + readonly magenta: this; + readonly cyan: this; + readonly white: this; + + /* + Alias for `blackBright`. + */ + readonly gray: this; + + /* + Alias for `blackBright`. + */ + readonly grey: this; + + readonly blackBright: this; + readonly redBright: this; + readonly greenBright: this; + readonly yellowBright: this; + readonly blueBright: this; + readonly magentaBright: this; + readonly cyanBright: this; + readonly whiteBright: this; + + readonly bgBlack: this; + readonly bgRed: this; + readonly bgGreen: this; + readonly bgYellow: this; + readonly bgBlue: this; + readonly bgMagenta: this; + readonly bgCyan: this; + readonly bgWhite: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGray: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGrey: this; + + readonly bgBlackBright: this; + readonly bgRedBright: this; + readonly bgGreenBright: this; + readonly bgYellowBright: this; + readonly bgBlueBright: this; + readonly bgMagentaBright: this; + readonly bgCyanBright: this; + readonly bgWhiteBright: this; +} + +/** +Main Chalk object that allows to chain styles together. + +Call the last one as a method with a string argument. + +Order doesn't matter, and later styles take precedent in case of a conflict. + +This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`. +*/ +declare const chalk: ChalkInstance; + +export const supportsColor: ColorInfo; + +export const chalkStderr: typeof chalk; +export const supportsColorStderr: typeof supportsColor; + +export { + ModifierName, ForegroundColorName, BackgroundColorName, ColorName, + modifierNames, foregroundColorNames, backgroundColorNames, colorNames, +// } from '#ansi-styles'; +} from './vendor/ansi-styles/index.js'; + +export { + ColorInfo, + ColorSupport, + ColorSupportLevel, +// } from '#supports-color'; +} from './vendor/supports-color/index.js'; + +// TODO: Remove these aliases in the next major version +/** +@deprecated Use `ModifierName` instead. + +Basic modifier names. +*/ +export type Modifiers = ModifierName; + +/** +@deprecated Use `ForegroundColorName` instead. + +Basic foreground color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ForegroundColor = ForegroundColorName; + +/** +@deprecated Use `BackgroundColorName` instead. + +Basic background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type BackgroundColor = BackgroundColorName; + +/** +@deprecated Use `ColorName` instead. + +Basic color names. The combination of foreground and background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type Color = ColorName; + +/** +@deprecated Use `modifierNames` instead. + +Basic modifier names. +*/ +export const modifiers: readonly Modifiers[]; + +/** +@deprecated Use `foregroundColorNames` instead. + +Basic foreground color names. +*/ +export const foregroundColors: readonly ForegroundColor[]; + +/** +@deprecated Use `backgroundColorNames` instead. + +Basic background color names. +*/ +export const backgroundColors: readonly BackgroundColor[]; + +/** +@deprecated Use `colorNames` instead. + +Basic color names. The combination of foreground and background color names. +*/ +export const colors: readonly Color[]; + +export default chalk; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.js b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.js new file mode 100644 index 000000000..8bc993da5 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/index.js @@ -0,0 +1,225 @@ +import ansiStyles from '#ansi-styles'; +import supportsColor from '#supports-color'; +import { // eslint-disable-line import/order + stringReplaceAll, + stringEncaseCRLFWithFirstIndex, +} from './utilities.js'; + +const {stdout: stdoutColor, stderr: stderrColor} = supportsColor; + +const GENERATOR = Symbol('GENERATOR'); +const STYLER = Symbol('STYLER'); +const IS_EMPTY = Symbol('IS_EMPTY'); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = [ + 'ansi', + 'ansi', + 'ansi256', + 'ansi16m', +]; + +const styles = Object.create(null); + +const applyOptions = (object, options = {}) => { + if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) { + throw new Error('The `level` option should be an integer from 0 to 3'); + } + + // Detect level if not set manually + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object.level = options.level === undefined ? colorLevel : options.level; +}; + +export class Chalk { + constructor(options) { + // eslint-disable-next-line no-constructor-return + return chalkFactory(options); + } +} + +const chalkFactory = options => { + const chalk = (...strings) => strings.join(' '); + applyOptions(chalk, options); + + Object.setPrototypeOf(chalk, createChalk.prototype); + + return chalk; +}; + +function createChalk(options) { + return chalkFactory(options); +} + +Object.setPrototypeOf(createChalk.prototype, Function.prototype); + +for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { + get() { + const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]); + Object.defineProperty(this, styleName, {value: builder}); + return builder; + }, + }; +} + +styles.visible = { + get() { + const builder = createBuilder(this, this[STYLER], true); + Object.defineProperty(this, 'visible', {value: builder}); + return builder; + }, +}; + +const getModelAnsi = (model, level, type, ...arguments_) => { + if (model === 'rgb') { + if (level === 'ansi16m') { + return ansiStyles[type].ansi16m(...arguments_); + } + + if (level === 'ansi256') { + return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_)); + } + + return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_)); + } + + if (model === 'hex') { + return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_)); + } + + return ansiStyles[type][model](...arguments_); +}; + +const usedModels = ['rgb', 'hex', 'ansi256']; + +for (const model of usedModels) { + styles[model] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); + }; + }, + }; + + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); + }; + }, + }; +} + +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { + enumerable: true, + get() { + return this[GENERATOR].level; + }, + set(level) { + this[GENERATOR].level = level; + }, + }, +}); + +const createStyler = (open, close, parent) => { + let openAll; + let closeAll; + if (parent === undefined) { + openAll = open; + closeAll = close; + } else { + openAll = parent.openAll + open; + closeAll = close + parent.closeAll; + } + + return { + open, + close, + openAll, + closeAll, + parent, + }; +}; + +const createBuilder = (self, _styler, _isEmpty) => { + // Single argument is hot path, implicit coercion is faster than anything + // eslint-disable-next-line no-implicit-coercion + const builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); + + // We alter the prototype because we must return a function, but there is + // no way to create a function with a different prototype + Object.setPrototypeOf(builder, proto); + + builder[GENERATOR] = self; + builder[STYLER] = _styler; + builder[IS_EMPTY] = _isEmpty; + + return builder; +}; + +const applyStyle = (self, string) => { + if (self.level <= 0 || !string) { + return self[IS_EMPTY] ? '' : string; + } + + let styler = self[STYLER]; + + if (styler === undefined) { + return string; + } + + const {openAll, closeAll} = styler; + if (string.includes('\u001B')) { + while (styler !== undefined) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + string = stringReplaceAll(string, styler.close, styler.open); + + styler = styler.parent; + } + } + + // We can move both next actions out of loop, because remaining actions in loop won't have + // any/visible effect on parts we add here. Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 + const lfIndex = string.indexOf('\n'); + if (lfIndex !== -1) { + string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); + } + + return openAll + string + closeAll; +}; + +Object.defineProperties(createChalk.prototype, styles); + +const chalk = createChalk(); +export const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0}); + +export { + modifierNames, + foregroundColorNames, + backgroundColorNames, + colorNames, + + // TODO: Remove these aliases in the next major version + modifierNames as modifiers, + foregroundColorNames as foregroundColors, + backgroundColorNames as backgroundColors, + colorNames as colors, +} from './vendor/ansi-styles/index.js'; + +export { + stdoutColor as supportsColor, + stderrColor as supportsColorStderr, +}; + +export default chalk; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/utilities.js b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/utilities.js new file mode 100644 index 000000000..4366dee0d --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/utilities.js @@ -0,0 +1,33 @@ +// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`. +export function stringReplaceAll(string, substring, replacer) { + let index = string.indexOf(substring); + if (index === -1) { + return string; + } + + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; + do { + returnValue += string.slice(endIndex, index) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} + +export function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) { + let endIndex = 0; + let returnValue = ''; + do { + const gotCR = string[index - 1] === '\r'; + returnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.d.ts b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.d.ts new file mode 100644 index 000000000..58f133abe --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.d.ts @@ -0,0 +1,236 @@ +export interface CSPair { // eslint-disable-line @typescript-eslint/naming-convention + /** + The ANSI terminal control sequence for starting this style. + */ + readonly open: string; + + /** + The ANSI terminal control sequence for ending this style. + */ + readonly close: string; +} + +export interface ColorBase { + /** + The ANSI terminal control sequence for ending this color. + */ + readonly close: string; + + ansi(code: number): string; + + ansi256(code: number): string; + + ansi16m(red: number, green: number, blue: number): string; +} + +export interface Modifier { + /** + Resets the current color chain. + */ + readonly reset: CSPair; + + /** + Make text bold. + */ + readonly bold: CSPair; + + /** + Emitting only a small amount of light. + */ + readonly dim: CSPair; + + /** + Make text italic. (Not widely supported) + */ + readonly italic: CSPair; + + /** + Make text underline. (Not widely supported) + */ + readonly underline: CSPair; + + /** + Make text overline. + + Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash. + */ + readonly overline: CSPair; + + /** + Inverse background and foreground colors. + */ + readonly inverse: CSPair; + + /** + Prints the text, but makes it invisible. + */ + readonly hidden: CSPair; + + /** + Puts a horizontal line through the center of the text. (Not widely supported) + */ + readonly strikethrough: CSPair; +} + +export interface ForegroundColor { + readonly black: CSPair; + readonly red: CSPair; + readonly green: CSPair; + readonly yellow: CSPair; + readonly blue: CSPair; + readonly cyan: CSPair; + readonly magenta: CSPair; + readonly white: CSPair; + + /** + Alias for `blackBright`. + */ + readonly gray: CSPair; + + /** + Alias for `blackBright`. + */ + readonly grey: CSPair; + + readonly blackBright: CSPair; + readonly redBright: CSPair; + readonly greenBright: CSPair; + readonly yellowBright: CSPair; + readonly blueBright: CSPair; + readonly cyanBright: CSPair; + readonly magentaBright: CSPair; + readonly whiteBright: CSPair; +} + +export interface BackgroundColor { + readonly bgBlack: CSPair; + readonly bgRed: CSPair; + readonly bgGreen: CSPair; + readonly bgYellow: CSPair; + readonly bgBlue: CSPair; + readonly bgCyan: CSPair; + readonly bgMagenta: CSPair; + readonly bgWhite: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGray: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGrey: CSPair; + + readonly bgBlackBright: CSPair; + readonly bgRedBright: CSPair; + readonly bgGreenBright: CSPair; + readonly bgYellowBright: CSPair; + readonly bgBlueBright: CSPair; + readonly bgCyanBright: CSPair; + readonly bgMagentaBright: CSPair; + readonly bgWhiteBright: CSPair; +} + +export interface ConvertColor { + /** + Convert from the RGB color space to the ANSI 256 color space. + + @param red - (`0...255`) + @param green - (`0...255`) + @param blue - (`0...255`) + */ + rgbToAnsi256(red: number, green: number, blue: number): number; + + /** + Convert from the RGB HEX color space to the RGB color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToRgb(hex: string): [red: number, green: number, blue: number]; + + /** + Convert from the RGB HEX color space to the ANSI 256 color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToAnsi256(hex: string): number; + + /** + Convert from the ANSI 256 color space to the ANSI 16 color space. + + @param code - A number representing the ANSI 256 color. + */ + ansi256ToAnsi(code: number): number; + + /** + Convert from the RGB color space to the ANSI 16 color space. + + @param red - (`0...255`) + @param green - (`0...255`) + @param blue - (`0...255`) + */ + rgbToAnsi(red: number, green: number, blue: number): number; + + /** + Convert from the RGB HEX color space to the ANSI 16 color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hexToAnsi(hex: string): number; +} + +/** +Basic modifier names. +*/ +export type ModifierName = keyof Modifier; + +/** +Basic foreground color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ForegroundColorName = keyof ForegroundColor; + +/** +Basic background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type BackgroundColorName = keyof BackgroundColor; + +/** +Basic color names. The combination of foreground and background color names. + +[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) +*/ +export type ColorName = ForegroundColorName | BackgroundColorName; + +/** +Basic modifier names. +*/ +export const modifierNames: readonly ModifierName[]; + +/** +Basic foreground color names. +*/ +export const foregroundColorNames: readonly ForegroundColorName[]; + +/** +Basic background color names. +*/ +export const backgroundColorNames: readonly BackgroundColorName[]; + +/* +Basic color names. The combination of foreground and background color names. +*/ +export const colorNames: readonly ColorName[]; + +declare const ansiStyles: { + readonly modifier: Modifier; + readonly color: ColorBase & ForegroundColor; + readonly bgColor: ColorBase & BackgroundColor; + readonly codes: ReadonlyMap; +} & ForegroundColor & BackgroundColor & Modifier & ConvertColor; + +export default ansiStyles; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.js b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.js new file mode 100644 index 000000000..eaa7bed6c --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/ansi-styles/index.js @@ -0,0 +1,223 @@ +const ANSI_BACKGROUND_OFFSET = 10; + +const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`; + +const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`; + +const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`; + +const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + overline: [53, 55], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29], + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + + // Bright color + blackBright: [90, 39], + gray: [90, 39], // Alias of `blackBright` + grey: [90, 39], // Alias of `blackBright` + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39], + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], + + // Bright color + bgBlackBright: [100, 49], + bgGray: [100, 49], // Alias of `bgBlackBright` + bgGrey: [100, 49], // Alias of `bgBlackBright` + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49], + }, +}; + +export const modifierNames = Object.keys(styles.modifier); +export const foregroundColorNames = Object.keys(styles.color); +export const backgroundColorNames = Object.keys(styles.bgColor); +export const colorNames = [...foregroundColorNames, ...backgroundColorNames]; + +function assembleStyles() { + const codes = new Map(); + + for (const [groupName, group] of Object.entries(styles)) { + for (const [styleName, style] of Object.entries(group)) { + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m`, + }; + + group[styleName] = styles[styleName]; + + codes.set(style[0], style[1]); + } + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false, + }); + } + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false, + }); + + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; + + styles.color.ansi = wrapAnsi16(); + styles.color.ansi256 = wrapAnsi256(); + styles.color.ansi16m = wrapAnsi16m(); + styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); + + // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js + Object.defineProperties(styles, { + rgbToAnsi256: { + value(red, green, blue) { + // We use the extended greyscale palette here, with the exception of + // black and white. normal palette only has 4 greyscale shades. + if (red === green && green === blue) { + if (red < 8) { + return 16; + } + + if (red > 248) { + return 231; + } + + return Math.round(((red - 8) / 247) * 24) + 232; + } + + return 16 + + (36 * Math.round(red / 255 * 5)) + + (6 * Math.round(green / 255 * 5)) + + Math.round(blue / 255 * 5); + }, + enumerable: false, + }, + hexToRgb: { + value(hex) { + const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); + if (!matches) { + return [0, 0, 0]; + } + + let [colorString] = matches; + + if (colorString.length === 3) { + colorString = [...colorString].map(character => character + character).join(''); + } + + const integer = Number.parseInt(colorString, 16); + + return [ + /* eslint-disable no-bitwise */ + (integer >> 16) & 0xFF, + (integer >> 8) & 0xFF, + integer & 0xFF, + /* eslint-enable no-bitwise */ + ]; + }, + enumerable: false, + }, + hexToAnsi256: { + value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)), + enumerable: false, + }, + ansi256ToAnsi: { + value(code) { + if (code < 8) { + return 30 + code; + } + + if (code < 16) { + return 90 + (code - 8); + } + + let red; + let green; + let blue; + + if (code >= 232) { + red = (((code - 232) * 10) + 8) / 255; + green = red; + blue = red; + } else { + code -= 16; + + const remainder = code % 36; + + red = Math.floor(code / 36) / 5; + green = Math.floor(remainder / 6) / 5; + blue = (remainder % 6) / 5; + } + + const value = Math.max(red, green, blue) * 2; + + if (value === 0) { + return 30; + } + + // eslint-disable-next-line no-bitwise + let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red)); + + if (value === 2) { + result += 60; + } + + return result; + }, + enumerable: false, + }, + rgbToAnsi: { + value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), + enumerable: false, + }, + hexToAnsi: { + value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), + enumerable: false, + }, + }); + + return styles; +} + +const ansiStyles = assembleStyles(); + +export default ansiStyles; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.d.ts b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.d.ts new file mode 100644 index 000000000..0e8a9ccb8 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.d.ts @@ -0,0 +1 @@ +export {default} from './index.js'; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.js b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.js new file mode 100644 index 000000000..fbb6ce0fc --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/browser.js @@ -0,0 +1,34 @@ +/* eslint-env browser */ + +const level = (() => { + if (!('navigator' in globalThis)) { + return 0; + } + + if (globalThis.navigator.userAgentData) { + const brand = navigator.userAgentData.brands.find(({brand}) => brand === 'Chromium'); + if (brand && brand.version > 93) { + return 3; + } + } + + if (/\b(Chrome|Chromium)\//.test(globalThis.navigator.userAgent)) { + return 1; + } + + return 0; +})(); + +const colorSupport = level !== 0 && { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, +}; + +const supportsColor = { + stdout: colorSupport, + stderr: colorSupport, +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.d.ts b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.d.ts new file mode 100644 index 000000000..db44a7851 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.d.ts @@ -0,0 +1,55 @@ +import type {WriteStream} from 'node:tty'; + +export type Options = { + /** + Whether `process.argv` should be sniffed for `--color` and `--no-color` flags. + + @default true + */ + readonly sniffFlags?: boolean; +}; + +/** +Levels: +- `0` - All colors disabled. +- `1` - Basic 16 colors support. +- `2` - ANSI 256 colors support. +- `3` - Truecolor 16 million colors support. +*/ +export type ColorSupportLevel = 0 | 1 | 2 | 3; + +/** +Detect whether the terminal supports color. +*/ +export type ColorSupport = { + /** + The color level. + */ + level: ColorSupportLevel; + + /** + Whether basic 16 colors are supported. + */ + hasBasic: boolean; + + /** + Whether ANSI 256 colors are supported. + */ + has256: boolean; + + /** + Whether Truecolor 16 million colors are supported. + */ + has16m: boolean; +}; + +export type ColorInfo = ColorSupport | false; + +export function createSupportsColor(stream?: WriteStream, options?: Options): ColorInfo; + +declare const supportsColor: { + stdout: ColorInfo; + stderr: ColorInfo; +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.js b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.js new file mode 100644 index 000000000..265d7f858 --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/node_modules/chalk/source/vendor/supports-color/index.js @@ -0,0 +1,190 @@ +import process from 'node:process'; +import os from 'node:os'; +import tty from 'node:tty'; + +// From: https://github.com/sindresorhus/has-flag/blob/main/index.js +/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) { +function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) { + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf('--'); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); +} + +const {env} = process; + +let flagForceColor; +if ( + hasFlag('no-color') + || hasFlag('no-colors') + || hasFlag('color=false') + || hasFlag('color=never') +) { + flagForceColor = 0; +} else if ( + hasFlag('color') + || hasFlag('colors') + || hasFlag('color=true') + || hasFlag('color=always') +) { + flagForceColor = 1; +} + +function envForceColor() { + if ('FORCE_COLOR' in env) { + if (env.FORCE_COLOR === 'true') { + return 1; + } + + if (env.FORCE_COLOR === 'false') { + return 0; + } + + return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); + } +} + +function translateLevel(level) { + if (level === 0) { + return false; + } + + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, + }; +} + +function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) { + const noFlagForceColor = envForceColor(); + if (noFlagForceColor !== undefined) { + flagForceColor = noFlagForceColor; + } + + const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; + + if (forceColor === 0) { + return 0; + } + + if (sniffFlags) { + if (hasFlag('color=16m') + || hasFlag('color=full') + || hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } + } + + // Check for Azure DevOps pipelines. + // Has to be above the `!streamIsTTY` check. + if ('TF_BUILD' in env && 'AGENT_NAME' in env) { + return 1; + } + + if (haveStream && !streamIsTTY && forceColor === undefined) { + return 0; + } + + const min = forceColor || 0; + + if (env.TERM === 'dumb') { + return min; + } + + if (process.platform === 'win32') { + // Windows 10 build 10586 is the first Windows release that supports 256 colors. + // Windows 10 build 14931 is the first release that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(osRelease[0]) >= 10 + && Number(osRelease[2]) >= 10_586 + ) { + return Number(osRelease[2]) >= 14_931 ? 3 : 2; + } + + return 1; + } + + if ('CI' in env) { + if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) { + return 3; + } + + if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } + + return min; + } + + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } + + if (env.COLORTERM === 'truecolor') { + return 3; + } + + if (env.TERM === 'xterm-kitty') { + return 3; + } + + if (env.TERM === 'xterm-ghostty') { + return 3; + } + + if (env.TERM === 'wezterm') { + return 3; + } + + if ('TERM_PROGRAM' in env) { + const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + + switch (env.TERM_PROGRAM) { + case 'iTerm.app': { + return version >= 3 ? 3 : 2; + } + + case 'Apple_Terminal': { + return 2; + } + // No default + } + } + + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } + + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + + if ('COLORTERM' in env) { + return 1; + } + + return min; +} + +export function createSupportsColor(stream, options = {}) { + const level = _supportsColor(stream, { + streamIsTTY: stream && stream.isTTY, + ...options, + }); + + return translateLevel(level); +} + +const supportsColor = { + stdout: createSupportsColor({isTTY: tty.isatty(1)}), + stderr: createSupportsColor({isTTY: tty.isatty(2)}), +}; + +export default supportsColor; diff --git a/tests/fixtures/npm/cases/chalk5-builder/package.json b/tests/fixtures/npm/cases/chalk5-builder/package.json new file mode 100644 index 000000000..3804daa8d --- /dev/null +++ b/tests/fixtures/npm/cases/chalk5-builder/package.json @@ -0,0 +1 @@ +{ "name": "chalk5-case", "private": true, "type": "module" } diff --git a/tests/fixtures/npm/cases/hot-shots-buffered/main.ts b/tests/fixtures/npm/cases/hot-shots-buffered/main.ts new file mode 100644 index 000000000..d17ce1167 --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-buffered/main.ts @@ -0,0 +1,80 @@ +// The hot-shots StatsD client (compiled from scriptc's built-in shim) in +// buffered mode: metrics join one datagram until maxBufferSize, close +// flushes the rest, child clients share the buffer. Also explicit sample +// rates of 1, the telegraf line format, stat arrays with a callback, and +// suffixes. +import * as dgram from "node:dgram"; +import { StatsD } from "hot-shots"; + +const server = dgram.createSocket("udp4"); +const received: string[] = []; +let waiting: (() => void) | null = null; +let want = 0; +server.on("message", (msg) => { + received.push(msg.toString()); + if (waiting !== null && received.length >= want) { + const done = waiting; + waiting = null; + done(); + } +}); + +function datagrams(count: number): Promise { + want = count; + return new Promise((resolve) => { + if (received.length >= want) resolve(); + else waiting = resolve; + }); +} + +function flush(label: string): void { + console.log("--", label); + for (const line of received.splice(0)) console.log(JSON.stringify(line)); +} + +async function run(port: number): Promise { + const buffered = new StatsD({ + host: "127.0.0.1", + port, + maxBufferSize: 64, + bufferFlushInterval: 60000, + suffix: ".s", + globalTags: ["team:core"], + }); + buffered.increment("one"); + buffered.increment("two", 2); + buffered.gauge("three", 3); + buffered.histogram("four", 4, ["h:1"]); + const child = buffered.childClient({ prefix: "kid.", suffix: ".x" }); + child.increment("five"); + await new Promise((resolve) => buffered.close(() => resolve())); + await datagrams(2); + flush("buffered"); + + const telegraf = new StatsD({ host: "127.0.0.1", port, telegraf: true, globalTags: { region: "eu" } }); + telegraf.increment("hits", 1, 1, { route: "/x" }); + telegraf.timing("lat", 7, ["kind:a"]); + await datagrams(2); + flush("telegraf"); + + const plain = new StatsD({ host: "127.0.0.1", port, prefix: "p." }); + await new Promise((resolve) => { + plain.increment(["a", "b", "c"], 1, 1, ["t:1"], (err: unknown, bytes: unknown) => { + console.log("array sent", err, bytes); + resolve(); + }); + }); + plain.set("users", 42, 1); + plain.unique("visitors", "v1"); + plain.decrement("down", 3, ["d:1"]); + plain.decrement("gone"); + await datagrams(7); + flush("plain"); + await new Promise((resolve) => { + telegraf.close(() => plain.close(() => resolve())); + }); +} + +server.bind(0, "127.0.0.1", () => { + void run(server.address().port).then(() => server.close(() => console.log("server closed"))); +}); diff --git a/tests/fixtures/npm/cases/hot-shots-buffered/package.json b/tests/fixtures/npm/cases/hot-shots-buffered/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-buffered/package.json @@ -0,0 +1 @@ +{ "type": "module" } From 6de7864697c5b49f90be08694b6104b2987d0b58 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 22:00:42 -0700 Subject: [PATCH 07/45] Record order baselines for the new chalk and hot-shots npm cases Co-Authored-By: Claude Opus 5.5 --- .../tests/fixtures/npm/cases/chalk5-builder/main.ts.json | 6 ++++++ .../fixtures/npm/cases/hot-shots-buffered/main.ts.json | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json new file mode 100644 index 000000000..545c4d701 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/chalk5-builder/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json new file mode 100644 index 000000000..e60660c09 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/hot-shots-buffered/main.ts" + ], + "diags": [] +} From 284517accbfd37cd06c87a5a352fe8b43acf10f8 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 22:04:27 -0700 Subject: [PATCH 08/45] Call chalk builders with one string through a typed method A callable class's %call1 method takes a single string argument directly, skipping the variadic closure's checked-dynamic call. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/chalk/v5.ts | 8 ++++ .../src/frontend/lowering/lower-calls.ts | 42 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/packages/compiler/shims/chalk/v5.ts b/packages/compiler/shims/chalk/v5.ts index 6599e35f9..494a9c69f 100644 --- a/packages/compiler/shims/chalk/v5.ts +++ b/packages/compiler/shims/chalk/v5.ts @@ -435,12 +435,14 @@ export class ChalkInstance { box: LevelBox; styler: Styler | undefined; isEmpty: boolean; + private readonly root: boolean; private readonly cache: (ChalkInstance | undefined)[] = []; constructor(box: LevelBox, styler: Styler | undefined, isEmpty: boolean, root: boolean) { this.box = box; this.styler = styler; this.isEmpty = isEmpty; + this.root = root; // One unconditional store: the field's definite assignment. this["%call"] = (...text: unknown[]): string => root @@ -448,6 +450,12 @@ export class ChalkInstance { : applyStyle(this, text.length === 1 ? "" + String(text[0]) : joinArguments(text)); } + /** One string argument: the compiler calls this instead of `%call` + * (no variadic arguments to box). */ + "%call1"(text: string): string { + return this.root ? text : applyStyle(this, text); + } + get level(): ColorSupportLevel { return this.box.level as ColorSupportLevel; } diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 3c04924c0..9d6f477f6 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1632,6 +1632,8 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // A getter returning a callable class instance (chalk's // `chalk.red("x")`): call through its `%call` field. if (callee.type.kind === "object") { + const direct = callableInstanceStringCall(lowerer, expr, callee, locOf(expr)); + if (direct) return direct; callee = lowerer.hybridCallUnwrap(callee); if (callee.type.kind === "func") return lowerCallThroughValue(lowerer, expr, callee, locOf(expr)); } @@ -1886,11 +1888,47 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // a non-func IR type was already rejected while lowering the callee. // HYBRID (function-with-properties) values call through their %call slot. let callee = lowerer.lowerExpr(expr.expression); + { + const direct = callableInstanceStringCall(lowerer, expr, callee, loc); + if (direct) return direct; + } if (callee.type.kind === "record" || callee.type.kind === "object") callee = lowerer.hybridCallUnwrap(callee); return lowerCallThroughValue(lowerer, expr, callee, loc); } +/** A callable class instance called with one string: its `%call1` method + * when the class has one (the chalk shim's typed fast path), skipping the + * variadic closure's checked-dynamic arguments. */ +function callableInstanceStringCall( + lowerer: Lowerer, + expr: ts.CallExpression, + callee: IrExpr, + loc: SrcLoc, +): IrExpr | null { + if (callee.type.kind !== "object" || expr.arguments.nodes.length !== 1) return null; + const arg = expr.arguments.nodes[0]!; + if (ts.isSpreadElement(arg)) return null; + const info = lowerer.classes.get(callee.type.className); + if (info === undefined || !info.fields.has("%call") || !lowerer.findMethodOn(info, "%call1")) + return null; + const value = lowerer.lowerExpr(arg); + if (value.type.kind === "string") + return lowerer.accessorCall(callee.type.className, "%call1", callee, [value], STRING, loc); + // Any other argument (a number behind a cast): the variadic closure, + // through the checked-dynamic call as lowerCallThroughValue would. + const closure = lowerer.hybridCallUnwrap(callee); + if (closure.type.kind !== "func") return null; + return { + kind: "dynCall", + callee: { kind: "dynFrom", value: closure, type: DYN, loc }, + calleeName: ts.isIdentifier(expr.expression) ? expr.expression.text : "value", + args: [lowerer.coerceToExpected(value, DYN)], + type: DYN, + loc, + }; +} + /** A call through an evaluated callee value: checked-dynamic callees, * function unions, typed-rest and runtime-arity closures. */ function lowerCallThroughValue( @@ -9208,6 +9246,10 @@ export function lowerRecordFieldCall( // A HYBRID (function-with-properties) field is callable through its // reserved %call slot — `colors.blue("x")` where blue also carries // `.bold` (the chalk shape). + if (callee.type.kind === "object" && !init) { + const direct = callableInstanceStringCall(lowerer, call, callee, loc); + if (direct) return direct; + } if (callee.type.kind === "record" || callee.type.kind === "object") callee = lowerer.hybridCallUnwrap(callee); // Inferred JavaScript option records can retain checked callables in From 88f9ba91eb94d63c254bc934beaaeb5dd887ea7e Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 22:08:46 -0700 Subject: [PATCH 09/45] Format the shims and scope the chalk declaration-merge lint exception Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/chalk/v5.ts | 241 +++++++++++++----- packages/compiler/shims/hot-shots/client.ts | 85 +++++- .../src/frontend/lowering/lower-calls.ts | 3 +- .../compiler/src/frontend/lowering/lowerer.ts | 5 +- .../compiler/src/frontend/package-shims.ts | 8 +- 5 files changed, 260 insertions(+), 82 deletions(-) diff --git a/packages/compiler/shims/chalk/v5.ts b/packages/compiler/shims/chalk/v5.ts index 494a9c69f..2d34c5c53 100644 --- a/packages/compiler/shims/chalk/v5.ts +++ b/packages/compiler/shims/chalk/v5.ts @@ -138,10 +138,7 @@ export const backgroundColorNames: BackgroundColorName[] = [ "bgCyanBright", "bgWhiteBright", ]; -export const colorNames: ColorName[] = [ - ...foregroundColorNames, - ...backgroundColorNames, -]; +export const colorNames: ColorName[] = [...foregroundColorNames, ...backgroundColorNames]; export const modifiers: Modifiers[] = modifierNames; export const foregroundColors: ForegroundColor[] = foregroundColorNames; export const backgroundColors: BackgroundColor[] = backgroundColorNames; @@ -151,14 +148,12 @@ const ESC = "\u001B["; /** Open and close codes, indexed by style id (the order of the getters). */ const OPEN_CODES: number[] = [ - 0, 1, 2, 3, 4, 53, 7, 8, 9, - 30, 31, 32, 33, 34, 35, 36, 37, 90, 90, 90, 91, 92, 93, 94, 95, 96, 97, - 40, 41, 42, 43, 44, 45, 46, 47, 100, 100, 100, 101, 102, 103, 104, 105, 106, 107, + 0, 1, 2, 3, 4, 53, 7, 8, 9, 30, 31, 32, 33, 34, 35, 36, 37, 90, 90, 90, 91, 92, 93, 94, 95, 96, + 97, 40, 41, 42, 43, 44, 45, 46, 47, 100, 100, 100, 101, 102, 103, 104, 105, 106, 107, ]; const CLOSE_CODES: number[] = [ - 0, 22, 22, 23, 24, 55, 27, 28, 29, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 0, 22, 22, 23, 24, 55, 27, 28, 29, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, ]; const VISIBLE = 45; @@ -238,9 +233,19 @@ function hasFlag(flag: string): boolean { } let flagForceColor: number | undefined = undefined; -if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { +if ( + hasFlag("no-color") || + hasFlag("no-colors") || + hasFlag("color=false") || + hasFlag("color=never") +) { flagForceColor = 0; -} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { +} else if ( + hasFlag("color") || + hasFlag("colors") || + hasFlag("color=true") || + hasFlag("color=always") +) { flagForceColor = 1; } @@ -277,7 +282,8 @@ function detectLevel(streamIsTTY: boolean): number { if (hasFlag("color=256")) return 2; if (inEnv("TF_BUILD") && inEnv("AGENT_NAME")) return 1; if (!streamIsTTY && forceColor === undefined) return 0; - const min = forceColor === undefined || forceColor === 0 || Number.isNaN(forceColor) ? 0 : forceColor; + const min = + forceColor === undefined || forceColor === 0 || Number.isNaN(forceColor) ? 0 : forceColor; const env = process.env; const term = env["TERM"]; if (term === "dumb") return min; @@ -388,7 +394,10 @@ function stringEncaseCRLFWithFirstIndex( do { const gotCR = string[index - 1] === "\r"; returnValue += - string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix; + string.slice(endIndex, gotCR ? index - 1 : index) + + prefix + + (gotCR ? "\r\n" : "\n") + + postfix; endIndex = index + 1; index = string.indexOf("\n", endIndex); } while (index !== -1); @@ -426,12 +435,19 @@ function joinArguments(args: unknown[]): string { /** A chalk instance or one of its style chains: callable (chalk's call * signature merges in from the interface), with every style a cached * getter. */ +// The merge is the point: the interface gives instances chalk's call +// signature, and the class's `%call` field implements it. +// oxlint-disable-next-line typescript/no-unsafe-declaration-merging export interface ChalkInstance { (...text: unknown[]): string; } +// oxlint-disable-next-line typescript/no-unsafe-declaration-merging export class ChalkInstance { - "%call": (...text: unknown[]) => string; + "%call": (...text: unknown[]) => string = (...text: unknown[]): string => + this.root + ? joinArguments(text) + : applyStyle(this, text.length === 1 ? "" + String(text[0]) : joinArguments(text)); box: LevelBox; styler: Styler | undefined; isEmpty: boolean; @@ -443,11 +459,6 @@ export class ChalkInstance { this.styler = styler; this.isEmpty = isEmpty; this.root = root; - // One unconditional store: the field's definite assignment. - this["%call"] = (...text: unknown[]): string => - root - ? joinArguments(text) - : applyStyle(this, text.length === 1 ? "" + String(text[0]) : joinArguments(text)); } /** One string argument: the compiler calls this instead of `%call` @@ -509,57 +520,153 @@ export class ChalkInstance { return this.model(ansi256Open(10, index), true); } - get reset(): ChalkInstance { return this.style(0); } - get bold(): ChalkInstance { return this.style(1); } - get dim(): ChalkInstance { return this.style(2); } - get italic(): ChalkInstance { return this.style(3); } - get underline(): ChalkInstance { return this.style(4); } - get overline(): ChalkInstance { return this.style(5); } - get inverse(): ChalkInstance { return this.style(6); } - get hidden(): ChalkInstance { return this.style(7); } - get strikethrough(): ChalkInstance { return this.style(8); } - get visible(): ChalkInstance { return this.style(VISIBLE); } - get black(): ChalkInstance { return this.style(9); } - get red(): ChalkInstance { return this.style(10); } - get green(): ChalkInstance { return this.style(11); } - get yellow(): ChalkInstance { return this.style(12); } - get blue(): ChalkInstance { return this.style(13); } - get magenta(): ChalkInstance { return this.style(14); } - get cyan(): ChalkInstance { return this.style(15); } - get white(): ChalkInstance { return this.style(16); } - get blackBright(): ChalkInstance { return this.style(17); } - get gray(): ChalkInstance { return this.style(18); } - get grey(): ChalkInstance { return this.style(19); } - get redBright(): ChalkInstance { return this.style(20); } - get greenBright(): ChalkInstance { return this.style(21); } - get yellowBright(): ChalkInstance { return this.style(22); } - get blueBright(): ChalkInstance { return this.style(23); } - get magentaBright(): ChalkInstance { return this.style(24); } - get cyanBright(): ChalkInstance { return this.style(25); } - get whiteBright(): ChalkInstance { return this.style(26); } - get bgBlack(): ChalkInstance { return this.style(27); } - get bgRed(): ChalkInstance { return this.style(28); } - get bgGreen(): ChalkInstance { return this.style(29); } - get bgYellow(): ChalkInstance { return this.style(30); } - get bgBlue(): ChalkInstance { return this.style(31); } - get bgMagenta(): ChalkInstance { return this.style(32); } - get bgCyan(): ChalkInstance { return this.style(33); } - get bgWhite(): ChalkInstance { return this.style(34); } - get bgBlackBright(): ChalkInstance { return this.style(35); } - get bgGray(): ChalkInstance { return this.style(36); } - get bgGrey(): ChalkInstance { return this.style(37); } - get bgRedBright(): ChalkInstance { return this.style(38); } - get bgGreenBright(): ChalkInstance { return this.style(39); } - get bgYellowBright(): ChalkInstance { return this.style(40); } - get bgBlueBright(): ChalkInstance { return this.style(41); } - get bgMagentaBright(): ChalkInstance { return this.style(42); } - get bgCyanBright(): ChalkInstance { return this.style(43); } - get bgWhiteBright(): ChalkInstance { return this.style(44); } + get reset(): ChalkInstance { + return this.style(0); + } + get bold(): ChalkInstance { + return this.style(1); + } + get dim(): ChalkInstance { + return this.style(2); + } + get italic(): ChalkInstance { + return this.style(3); + } + get underline(): ChalkInstance { + return this.style(4); + } + get overline(): ChalkInstance { + return this.style(5); + } + get inverse(): ChalkInstance { + return this.style(6); + } + get hidden(): ChalkInstance { + return this.style(7); + } + get strikethrough(): ChalkInstance { + return this.style(8); + } + get visible(): ChalkInstance { + return this.style(VISIBLE); + } + get black(): ChalkInstance { + return this.style(9); + } + get red(): ChalkInstance { + return this.style(10); + } + get green(): ChalkInstance { + return this.style(11); + } + get yellow(): ChalkInstance { + return this.style(12); + } + get blue(): ChalkInstance { + return this.style(13); + } + get magenta(): ChalkInstance { + return this.style(14); + } + get cyan(): ChalkInstance { + return this.style(15); + } + get white(): ChalkInstance { + return this.style(16); + } + get blackBright(): ChalkInstance { + return this.style(17); + } + get gray(): ChalkInstance { + return this.style(18); + } + get grey(): ChalkInstance { + return this.style(19); + } + get redBright(): ChalkInstance { + return this.style(20); + } + get greenBright(): ChalkInstance { + return this.style(21); + } + get yellowBright(): ChalkInstance { + return this.style(22); + } + get blueBright(): ChalkInstance { + return this.style(23); + } + get magentaBright(): ChalkInstance { + return this.style(24); + } + get cyanBright(): ChalkInstance { + return this.style(25); + } + get whiteBright(): ChalkInstance { + return this.style(26); + } + get bgBlack(): ChalkInstance { + return this.style(27); + } + get bgRed(): ChalkInstance { + return this.style(28); + } + get bgGreen(): ChalkInstance { + return this.style(29); + } + get bgYellow(): ChalkInstance { + return this.style(30); + } + get bgBlue(): ChalkInstance { + return this.style(31); + } + get bgMagenta(): ChalkInstance { + return this.style(32); + } + get bgCyan(): ChalkInstance { + return this.style(33); + } + get bgWhite(): ChalkInstance { + return this.style(34); + } + get bgBlackBright(): ChalkInstance { + return this.style(35); + } + get bgGray(): ChalkInstance { + return this.style(36); + } + get bgGrey(): ChalkInstance { + return this.style(37); + } + get bgRedBright(): ChalkInstance { + return this.style(38); + } + get bgGreenBright(): ChalkInstance { + return this.style(39); + } + get bgYellowBright(): ChalkInstance { + return this.style(40); + } + get bgBlueBright(): ChalkInstance { + return this.style(41); + } + get bgMagentaBright(): ChalkInstance { + return this.style(42); + } + get bgCyanBright(): ChalkInstance { + return this.style(43); + } + get bgWhiteBright(): ChalkInstance { + return this.style(44); + } } function optionsLevel(options: Options | undefined): number { const level = options === undefined ? undefined : options.level; - if (level !== undefined && level !== 0 && !(Number.isInteger(level) && level >= 0 && level <= 3)) { + if ( + level !== undefined && + level !== 0 && + !(Number.isInteger(level) && level >= 0 && level <= 3) + ) { throw new Error("The `level` option should be an integer from 0 to 3"); } if (level === undefined) return stdoutColor === false ? 0 : stdoutColor.level; diff --git a/packages/compiler/shims/hot-shots/client.ts b/packages/compiler/shims/hot-shots/client.ts index d0b5c8924..2f8ca0580 100644 --- a/packages/compiler/shims/hot-shots/client.ts +++ b/packages/compiler/shims/hot-shots/client.ts @@ -542,7 +542,13 @@ export class StatsD { // ── stats functions ── - timing(stat: string | string[], time: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + timing( + stat: string | string[], + time: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; timing(stat: string | string[], time: number, tags?: Tags, callback?: StatsCb): void; timing(stat: string | string[], time: number, callback?: StatsCb): void; timing(stat: string | string[], time: number, sampleRate?: number, callback?: StatsCb): void; @@ -557,7 +563,13 @@ export class StatsD { } increment(stat: string, tags?: Tags): void; - increment(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + increment( + stat: string | string[], + value: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; increment(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; increment(stat: string | string[], value: number, callback?: StatsCb): void; increment(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; @@ -580,7 +592,13 @@ export class StatsD { } decrement(stat: string, tags?: Tags): void; - decrement(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + decrement( + stat: string | string[], + value: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; decrement(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; decrement(stat: string | string[], value: number, callback?: StatsCb): void; decrement(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; @@ -601,7 +619,13 @@ export class StatsD { this.sendAll(stat, -amount, "c", sampleRate, tagArg, callback); } - histogram(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + histogram( + stat: string | string[], + value: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; histogram(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; histogram(stat: string | string[], value: number, callback?: StatsCb): void; histogram(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; @@ -615,10 +639,21 @@ export class StatsD { this.sendAll(stat, value, "h", sampleRate, tags, callback); } - distribution(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + distribution( + stat: string | string[], + value: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; distribution(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; distribution(stat: string | string[], value: number, callback?: StatsCb): void; - distribution(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; + distribution( + stat: string | string[], + value: number, + sampleRate?: number, + callback?: StatsCb, + ): void; distribution( stat: string | string[], value: number, @@ -629,7 +664,13 @@ export class StatsD { this.sendAll(stat, value, "d", sampleRate, tags, callback); } - gauge(stat: string | string[], value: number, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + gauge( + stat: string | string[], + value: number, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; gauge(stat: string | string[], value: number, tags?: Tags, callback?: StatsCb): void; gauge(stat: string | string[], value: number, callback?: StatsCb): void; gauge(stat: string | string[], value: number, sampleRate?: number, callback?: StatsCb): void; @@ -643,10 +684,21 @@ export class StatsD { this.sendAll(stat, value, "g", sampleRate, tags, callback); } - set(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + set( + stat: string | string[], + value: number | string, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; set(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; set(stat: string | string[], value: number | string, callback?: StatsCb): void; - set(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + set( + stat: string | string[], + value: number | string, + sampleRate?: number, + callback?: StatsCb, + ): void; set( stat: string | string[], value: number | string, @@ -657,10 +709,21 @@ export class StatsD { this.sendAll(stat, value, "s", sampleRate, tags, callback); } - unique(stat: string | string[], value: number | string, sampleRate?: number, tags?: Tags, callback?: StatsCb): void; + unique( + stat: string | string[], + value: number | string, + sampleRate?: number, + tags?: Tags, + callback?: StatsCb, + ): void; unique(stat: string | string[], value: number | string, tags?: Tags, callback?: StatsCb): void; unique(stat: string | string[], value: number | string, callback?: StatsCb): void; - unique(stat: string | string[], value: number | string, sampleRate?: number, callback?: StatsCb): void; + unique( + stat: string | string[], + value: number | string, + sampleRate?: number, + callback?: StatsCb, + ): void; unique( stat: string | string[], value: number | string, diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 9d6f477f6..b650ca567 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1635,7 +1635,8 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const direct = callableInstanceStringCall(lowerer, expr, callee, locOf(expr)); if (direct) return direct; callee = lowerer.hybridCallUnwrap(callee); - if (callee.type.kind === "func") return lowerCallThroughValue(lowerer, expr, callee, locOf(expr)); + if (callee.type.kind === "func") + return lowerCallThroughValue(lowerer, expr, callee, locOf(expr)); } if (callee.type.kind === "func") { const args = completeFuncValueArgs(lowerer, expr, callee.type, locOf(expr)); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index ac1a778cf..206c42fdc 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9656,7 +9656,10 @@ export class Lowerer { (id) => this.unions.get(id), ) ) { - return this.coerceToExpected({ kind: "dynFrom", value: un, type: DYN, loc: un.loc }, expected); + return this.coerceToExpected( + { kind: "dynFrom", value: un, type: DYN, loc: un.loc }, + expected, + ); } } // A zero-param function whose RETURN is a wider record array than the diff --git a/packages/compiler/src/frontend/package-shims.ts b/packages/compiler/src/frontend/package-shims.ts index 3af7ebf59..a0c2e4cb9 100644 --- a/packages/compiler/src/frontend/package-shims.ts +++ b/packages/compiler/src/frontend/package-shims.ts @@ -72,7 +72,10 @@ interface ImplementationShim { variants?: readonly string[]; } -const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map([ +const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map< + string, + ImplementationShim +>([ [ "fs-extra", { @@ -330,7 +333,8 @@ function shimOfDeclarationPath(path: string): { pkgDir: string; shim: Implementa for (const shim of IMPLEMENTATION_SHIMS.values()) { if (shim.typesFile === undefined) continue; const suffix = `/${shim.name}/${shim.typesFile}`; - if (path.endsWith(suffix)) return { pkgDir: path.slice(0, path.length - suffix.length + shim.name.length + 1), shim }; + if (path.endsWith(suffix)) + return { pkgDir: path.slice(0, path.length - suffix.length + shim.name.length + 1), shim }; } return null; } From 8c9f5cfc9ff02dccb7a97266d210bfba559a5ccc Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Thu, 22 Oct 2026 01:42:01 -0700 Subject: [PATCH 10/45] Free hot-shots' unclosed udp and tcp transports at exit The socket's error listener captured the transport, so a client that is never closed (mock mode) kept a cycle the RC audit reports at exit; it now captures only the listener list. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/hot-shots/client.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/compiler/shims/hot-shots/client.ts b/packages/compiler/shims/hot-shots/client.ts index 2f8ca0580..aa752d703 100644 --- a/packages/compiler/shims/hot-shots/client.ts +++ b/packages/compiler/shims/hot-shots/client.ts @@ -218,7 +218,11 @@ class UdpTransport implements Transport { this.cacheDnsTtl = cacheDnsTtl; this.socket = dgram.createSocket("udp4"); this.socket.unref(); - this.socket.on("error", (err) => this.errors.emit(err)); + // The listener captures the list, not the transport: a socket that is + // never closed keeps its listener, and a capture of `this` would make + // a cycle the reference counts cannot free at exit. + const errors = this.errors; + this.socket.on("error", (err) => errors.emit(err)); } send(buf: Buffer, callback: SendCallback): void { if (!this.cacheDns) { @@ -263,7 +267,11 @@ class TcpTransport implements Transport { this.socket = net.connect(port, host ?? "localhost"); this.socket.setKeepAlive(true); this.socket.unref(); - this.socket.on("error", (err) => this.errors.emit(err)); + // The listener captures the list, not the transport: a socket that is + // never closed keeps its listener, and a capture of `this` would make + // a cycle the reference counts cannot free at exit. + const errors = this.errors; + this.socket.on("error", (err) => errors.emit(err)); } send(buf: Buffer, callback: SendCallback): void { // The typed socket's write takes the data alone; the completion runs From 2e297caf9955cf8cb4606c9acd7dda8f3eac5877 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Thu, 22 Oct 2026 05:33:34 -0700 Subject: [PATCH 11/45] Log hot-shots' failed final flush through an unknown value Programs whose Error subclasses define accessors still compile the shim's close logging. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/shims/hot-shots/client.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/compiler/shims/hot-shots/client.ts b/packages/compiler/shims/hot-shots/client.ts index aa752d703..b407132f4 100644 --- a/packages/compiler/shims/hot-shots/client.ts +++ b/packages/compiler/shims/hot-shots/client.ts @@ -155,6 +155,13 @@ function formatDate(date: number): number { return Math.round(date); } +/** console.error of an arbitrary value, as hot-shots logs errors. The + * value crosses as unknown: the typed Error path has no inspect lowering + * in programs whose Error subclasses define accessors. */ +function logError(value: unknown): void { + console.error(value); +} + function errorWithCode(message: string, code: string | undefined): Error { const error: NodeJS.ErrnoException = new Error(message); error.code = code; @@ -1013,7 +1020,7 @@ export class StatsD { this.flushQueue((err) => { if (err) { if (callback) return callback(err); - console.error(err); + logError(err); return; } let intervalAttempts = 0; From 164174f811a2f0f927fde6f76f5578c6ff538139 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Thu, 22 Oct 2026 02:29:47 -0700 Subject: [PATCH 12/45] Keep literal key order for records a narrowing throw arm types The key-order witness pass read every libCall typed as a record as an opaque producer of that record, which pins the declaration order. A void runtime call typed by its use site, such as error.nodeThrow in the ternary that narrows a possibly-undefined binding before a member read, never produces a value. A module-level accumulator enumerated in its interface's order instead of its literal's. New corpus program 6915. Co-Authored-By: Claude Opus 5.5 --- .../frontend/lowering/key-order-witness.ts | 6 +- .../6915-key-order-narrowed-throw.ts.json | 6 ++ tests/corpus/6915-key-order-narrowed-throw.ts | 72 +++++++++++++++++++ .../6915-key-order-narrowed-throw.ts.json | 1 + 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6915-key-order-narrowed-throw.ts.json create mode 100644 tests/corpus/6915-key-order-narrowed-throw.ts create mode 100644 tests/harness/corpus-costs/6915-key-order-narrowed-throw.ts.json diff --git a/packages/compiler/src/frontend/lowering/key-order-witness.ts b/packages/compiler/src/frontend/lowering/key-order-witness.ts index 2fc9a6cbd..7ce8ae074 100644 --- a/packages/compiler/src/frontend/lowering/key-order-witness.ts +++ b/packages/compiler/src/frontend/lowering/key-order-witness.ts @@ -45,6 +45,7 @@ import type { IrExpr, IrFunction, IrRecordShape, IrStmt, IrType } from "../../ir import { shapeHasAccessorSlots, typeEquals, UNDEFINED_T } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild, everyTypeChild } from "../../ir/traverse.js"; import type { Lowerer } from "./lowerer.js"; +import { LIB_FN_SIGS } from "../../ir/builtin-signatures.js"; /** One property of an object literal, in source order. */ export type KeyOrderSegment = @@ -312,7 +313,10 @@ export function applyKeyOrderWitnesses(lowerer: Lowerer, fns: readonly IrFunctio // Runtime surfaces (console, util.format, workers) that take a // record may walk its keys; runtime builders make new records. for (const arg of e.args) observedRoots.push(arg.type); - producedBy(e.type, true); + // A void runtime call typed by its use site is a throw standing in + // for a value (`error.nodeThrow` in a narrowing ternary): it never + // produces one. + if (LIB_FN_SIGS[e.fn].result.kind !== "void") producedBy(e.type, true); return; case "intrinsic": // Intrinsics hand back values built elsewhere, except allSettled's diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6915-key-order-narrowed-throw.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6915-key-order-narrowed-throw.ts.json new file mode 100644 index 000000000..83f8cc5d5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6915-key-order-narrowed-throw.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6915-key-order-narrowed-throw.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6915-key-order-narrowed-throw.ts b/tests/corpus/6915-key-order-narrowed-throw.ts new file mode 100644 index 000000000..d4bc693f2 --- /dev/null +++ b/tests/corpus/6915-key-order-narrowed-throw.ts @@ -0,0 +1,72 @@ +// A record whose reads narrow a possibly-undefined binding (the narrowing +// ternary's throw arm stands in for a value of the record's type) still +// takes its literal's key order: a module-level accumulator typed by an +// interface declared in another order, as an event batcher builds it. +interface Entry { + id: string; + at: number; + text?: string; + stream: "out" | "err"; +} +interface Batch { + team: string; + project: string; + job: string; + origin: "task" | "worker"; + host: string; + entries: Entry[]; + sizes?: number[]; + stage?: "live" | "staging"; + branch?: string; + run?: string; + entry?: string; + path?: string; +} +interface Job { + id: string; + run?: string; + project: string; + team: string; + host: string; + stage: string | null; +} +let acc: Batch | undefined; + +function append(j: Job, text: string): void { + if (!acc) { + acc = { + run: j.run, + job: j.id, + stage: j.stage === null ? "staging" : "live", + project: j.project, + team: j.team, + origin: "task", + host: j.host, + entry: ".", + entries: [], + }; + } + acc.entries.push({ id: String(acc.entries.length), at: 1, text, stream: "out" }); + setTimeout(() => { + const batch = acc; + if (!batch) return; + acc = undefined; + for (const line of split(batch)) console.log(line); + }, 1); +} + +function split(batch: Batch): string[] { + const json = JSON.stringify(batch); + if (json.length < 200 || batch.entries.length < 2) return [json]; + const index = Math.floor(batch.entries.length / 2); + const first = { ...batch, entries: batch.entries.slice(0, index) }; + const second = { ...batch, entries: batch.entries.slice(index) }; + return [...split(first), ...split(second)]; +} + +const j: Job = { id: "job", run: "r1", project: "prj", team: "core", host: "h", stage: "live" }; +append(j, "one"); +append(j, "two"); +setTimeout(() => { + for (let i = 0; i < 6; i++) append(j, "line " + i); +}, 5); diff --git a/tests/harness/corpus-costs/6915-key-order-narrowed-throw.ts.json b/tests/harness/corpus-costs/6915-key-order-narrowed-throw.ts.json new file mode 100644 index 000000000..fae2adeb4 --- /dev/null +++ b/tests/harness/corpus-costs/6915-key-order-narrowed-throw.ts.json @@ -0,0 +1 @@ +{ "plain": 1500, "san": 9000 } From 712b4e84a1e52dca58f559a20123f935e68e54c5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 08:12:12 -0500 Subject: [PATCH 13/45] Support the env option of spawnSync `spawnSync(cmd, args, { env })` replaces the child's environment with the given record, as spawn and execFileSync already do, alone or with the timeout, killSignal and stdio options. The fallback typings declare the option. --- .../ambient/scriptc-node-fallback.d.ts | 4 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/backend/llvm/reference-writes.ts | 1 + .../lowering/builtins/child-process.ts | 19 +++++++++- .../compiler/src/ir/builtin-signatures.ts | 6 +++ .../tests/corpus/7030-spawn-sync-env.ts.json | 6 +++ packages/runtime/src/scr_child.c | 38 +++++++++++++++---- packages/runtime/src/scr_child.h | 5 +++ tests/corpus/7030-spawn-sync-env.ts | 28 ++++++++++++++ .../corpus-costs/7030-spawn-sync-env.ts.json | 1 + 10 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7030-spawn-sync-env.ts.json create mode 100644 tests/corpus/7030-spawn-sync-env.ts create mode 100644 tests/harness/corpus-costs/7030-spawn-sync-env.ts.json diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 2a3f11be9..c5fce2423 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3512,7 +3512,8 @@ declare module "child_process" { * killSignal at the deadline and the result carries error: ETIMEDOUT + * the signal, never a throw), killSignal (a signal NAME literal), * stdio ("ignore"/"inherit"/"pipe" or a 3-tuple of those — captures - * read "" for non-piped streams), and windowsHide (a POSIX no-op). */ + * read "" for non-piped streams), env (replaces the child's + * environment), and windowsHide (a POSIX no-op). */ export function spawnSync( command: string, args?: string[], @@ -3521,6 +3522,7 @@ declare module "child_process" { timeout?: number; killSignal?: string; stdio?: "pipe" | "ignore" | "inherit" | ("pipe" | "ignore" | "inherit")[]; + env?: { [k: string]: string | undefined }; windowsHide?: boolean; }, ): SpawnSyncReturns; diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9a65d9a24..f18e4a7d5 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -754,6 +754,7 @@ export const LIB_FN_SYMS: Record = { "cp.spawnSync": "scr_spawn_sync", "cp.spawnSyncOpts": "scr_spawn_sync_opts", "cp.spawnSyncStdioStr": "scr_spawn_sync_stdio_str", + "cp.spawnSyncEnv": "scr_spawn_sync_env", "cp.execSync": "scr_exec_sync", "cp.execCapture": "scr_exec_capture", "spawnRes.stdout": "scr_spawn_res_stdout", diff --git a/packages/compiler/src/backend/llvm/reference-writes.ts b/packages/compiler/src/backend/llvm/reference-writes.ts index d31f14d12..6d1593a55 100644 --- a/packages/compiler/src/backend/llvm/reference-writes.ts +++ b/packages/compiler/src/backend/llvm/reference-writes.ts @@ -118,6 +118,7 @@ const INERT_LIB_CALLS = new Set([ "worker.parentPort", "worker.root", "cp.spawnSyncOpts", + "cp.spawnSyncEnv", ]); /** jsval conversions (ir/jsval.ts): no user code, no stores. */ diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process.ts b/packages/compiler/src/frontend/lowering/builtins/child-process.ts index ea2dd379d..9096316a3 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process.ts @@ -115,6 +115,8 @@ export function lowerSpawnSyncCall(lowerer: Lowerer, expr: ts.CallExpression, lo // "pipe"`) — accepted when its TYPE proves every arm is a supported // literal; the runtime maps the value to the modes at the call. let stdioStr: IrExpr | null = null; + // The `env` option's [k,v,...] pairs, which replace the child's environment. + let envPairs: IrExpr | null = null; let plain = true; // no behavior-changing option: the historical libCall if (optsNode) { @@ -227,11 +229,16 @@ export function lowerSpawnSyncCall(lowerer: Lowerer, expr: ts.CallExpression, lo case "windowsHide": lowerer.lowerExpr(m.value); // Node no-op on POSIX break; + case "env": + // A REPLACEMENT environment, as for spawn and execFileSync. + envPairs = recordToEnvPairs(lowerer, m.value); + plain = false; + break; default: lowerer.noLowering( `spawnSync option '${m.name}'`, p, - "encoding, timeout, killSignal, stdio, and windowsHide are the supported options", + "encoding, timeout, killSignal, stdio, env, and windowsHide are the supported options", ); } } @@ -239,6 +246,13 @@ export function lowerSpawnSyncCall(lowerer: Lowerer, expr: ts.CallExpression, lo if (plain) { return { kind: "libCall", fn: "cp.spawnSync", args: [cmd, argv], type: SPAWNRES_T, loc }; } + if (stdioStr !== null && envPairs !== null) { + lowerer.noLowering( + "spawnSync with a runtime stdio value and env", + optsNode!, + 'pass stdio as a "pipe"/"ignore"/"inherit" literal when env is set', + ); + } if (stdioStr !== null) { return { kind: "libCall", @@ -250,7 +264,7 @@ export function lowerSpawnSyncCall(lowerer: Lowerer, expr: ts.CallExpression, lo } return { kind: "libCall", - fn: "cp.spawnSyncOpts", + fn: envPairs !== null ? "cp.spawnSyncEnv" : "cp.spawnSyncOpts", args: [ cmd, argv, @@ -259,6 +273,7 @@ export function lowerSpawnSyncCall(lowerer: Lowerer, expr: ts.CallExpression, lo numLit(inMode, loc), numLit(outMode, loc), numLit(errMode, loc), + ...(envPairs !== null ? [envPairs] : []), ], type: SPAWNRES_T, loc, diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index fcdbe8694..6b7dc1741 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1318,6 +1318,12 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ 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 diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7030-spawn-sync-env.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7030-spawn-sync-env.ts.json new file mode 100644 index 000000000..f8afbe00b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7030-spawn-sync-env.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7030-spawn-sync-env.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index ec685656d..387885c42 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -1105,9 +1105,9 @@ char **scr_child_argv(ScrStr *cmd, ScrArr *args) { static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeout_ms, int killsig, int in_mode, int out_mode, - int err_mode) { + int err_mode, ScrArr *env_pairs) { ScrWinSyncRes w; - scr_win_run_sync(cmd, args, NULL, in_mode, out_mode, err_mode, NULL, NULL, + scr_win_run_sync(cmd, args, NULL, in_mode, out_mode, err_mode, NULL, env_pairs, timeout_ms, &w); if (w.spawn_errname != NULL) { free(w.out.data); @@ -1136,19 +1136,26 @@ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeou } ScrSpawnRes *scr_spawn_sync(ScrStr *cmd, ScrArr *args) { - return scr_spawn_sync_core(cmd, args, 0, SIGTERM, 0, 0, 0); + return scr_spawn_sync_core(cmd, args, 0, SIGTERM, 0, 0, 0, NULL); } ScrSpawnRes *scr_spawn_sync_opts(ScrStr *cmd, ScrArr *args, double timeout_ms, ScrStr *killsignal, double in_mode, double out_mode, double err_mode) { + return scr_spawn_sync_env(cmd, args, timeout_ms, killsignal, in_mode, out_mode, err_mode, + NULL); +} + +ScrSpawnRes *scr_spawn_sync_env(ScrStr *cmd, ScrArr *args, double timeout_ms, + ScrStr *killsignal, double in_mode, double out_mode, + double err_mode, ScrArr *env_pairs) { int killsig = SIGTERM; if (killsignal->len > 0) { int resolved = scr_signal_from_name(killsignal); if (resolved > 0) killsig = resolved; } return scr_spawn_sync_core(cmd, args, timeout_ms, killsig, (int)in_mode, - (int)out_mode, (int)err_mode); + (int)out_mode, (int)err_mode, env_pairs); } ScrSpawnRes *scr_spawn_sync_stdio_str(ScrStr *cmd, ScrArr *args, double timeout_ms, @@ -3101,9 +3108,14 @@ static ScrSpawnRes *scr_spawn_res_new(bool has_status, double status, * documented divergence). timeout_ms > 0 sends `killsig` at the deadline * and the result carries error: ETIMEDOUT + the signal — never a throw, * Node's spawnSync shape. */ +static char **scr_exec_envp(ScrArr *pairs); +static void scr_exec_envp_free(char **envp); + +/* env_pairs: NULL inherits the parent's environment; else [k,v,...] + * replaces it, as Node's `env` option does. */ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeout_ms, int killsig, int in_mode, int out_mode, - int err_mode) { + int err_mode, ScrArr *env_pairs) { if (out_mode == 2 || err_mode == 2) { /* Inherited output fds: flush the parent's buffers first so earlier * logs precede the child's writes (Node's practical ordering). */ @@ -3138,10 +3150,13 @@ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeou } char **argv = scr_child_argv(cmd, args); + char **envp = env_pairs != NULL ? scr_exec_envp(env_pairs) : NULL; pid_t pid = -1; - int spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, environ); + int spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, + envp != NULL ? envp : environ); posix_spawn_file_actions_destroy(&fa); free(argv); + scr_exec_envp_free(envp); if (cap_out) close(outfd[1]); if (cap_err) close(errfd[1]); @@ -3242,7 +3257,7 @@ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeou } ScrSpawnRes *scr_spawn_sync(ScrStr *cmd, ScrArr *args) { - return scr_spawn_sync_core(cmd, args, 0, SIGTERM, 0, 0, 0); + return scr_spawn_sync_core(cmd, args, 0, SIGTERM, 0, 0, 0, NULL); } /* The options entry (cp.spawnSyncOpts): killSignal as a NAME ("" = the @@ -3252,13 +3267,20 @@ ScrSpawnRes *scr_spawn_sync(ScrStr *cmd, ScrArr *args) { ScrSpawnRes *scr_spawn_sync_opts(ScrStr *cmd, ScrArr *args, double timeout_ms, ScrStr *killsignal, double in_mode, double out_mode, double err_mode) { + return scr_spawn_sync_env(cmd, args, timeout_ms, killsignal, in_mode, out_mode, err_mode, + NULL); +} + +ScrSpawnRes *scr_spawn_sync_env(ScrStr *cmd, ScrArr *args, double timeout_ms, + ScrStr *killsignal, double in_mode, double out_mode, + double err_mode, ScrArr *env_pairs) { int killsig = SIGTERM; if (killsignal->len > 0) { int resolved = scr_signal_from_name(killsignal); if (resolved > 0) killsig = resolved; } return scr_spawn_sync_core(cmd, args, timeout_ms, killsig, (int)in_mode, - (int)out_mode, (int)err_mode); + (int)out_mode, (int)err_mode, env_pairs); } /* The runtime-string stdio entry (cp.spawnSyncStdioStr): the compiler diff --git a/packages/runtime/src/scr_child.h b/packages/runtime/src/scr_child.h index e899130d8..a5853ad59 100644 --- a/packages/runtime/src/scr_child.h +++ b/packages/runtime/src/scr_child.h @@ -23,6 +23,11 @@ ScrSpawnRes *scr_spawn_sync(ScrStr *cmd, ScrArr *args); /* +1, never throws */ ScrSpawnRes *scr_spawn_sync_opts(ScrStr *cmd, ScrArr *args, double timeout_ms, ScrStr *killsignal, double in_mode, double out_mode, double err_mode); +/* scr_spawn_sync_opts with an `env` option: [k,v,...] pairs replace the + * child's environment (NULL inherits the parent's). */ +ScrSpawnRes *scr_spawn_sync_env(ScrStr *cmd, ScrArr *args, double timeout_ms, + ScrStr *killsignal, double in_mode, double out_mode, + double err_mode, ScrArr *env_pairs); /* The runtime-string stdio entry: the compiler proved the value is * "pipe" | "ignore" | "inherit" by type; the mode mapping happens here. */ ScrSpawnRes *scr_spawn_sync_stdio_str(ScrStr *cmd, ScrArr *args, double timeout_ms, diff --git a/tests/corpus/7030-spawn-sync-env.ts b/tests/corpus/7030-spawn-sync-env.ts new file mode 100644 index 000000000..e613c81f0 --- /dev/null +++ b/tests/corpus/7030-spawn-sync-env.ts @@ -0,0 +1,28 @@ +// spawnSync's env option replaces the child's environment, alone or with +// the other options. +import { spawnSync } from "node:child_process"; + +const merged = spawnSync("sh", ["-c", 'echo "$GREETING $HOME_SET"'], { + env: { ...process.env, GREETING: "hello", HOME_SET: process.env.HOME ? "yes" : "no" }, + encoding: "utf8", +}); +console.log(merged.stdout.trim(), merged.status); + +const only = spawnSync("/bin/sh", ["-c", 'echo "${GREETING:-unset} ${HOME:-nohome}"'], { + env: { GREETING: "only" }, + encoding: "utf8", +}); +console.log(only.stdout.trim()); + +const empty = spawnSync("/bin/sh", ["-c", "env | grep -c ."], { env: {}, encoding: "utf8" }); +console.log(Number(empty.stdout.trim()) <= 3, empty.status); + +const quiet = spawnSync("sh", ["-c", 'echo "$MODE" >&2; exit 4'], { + env: { PATH: process.env.PATH ?? "/usr/bin:/bin", MODE: "loud" }, + stdio: ["ignore", "pipe", "pipe"], + timeout: 5000, +}); +console.log(quiet.status, quiet.stderr.toString().trim(), quiet.stdout.toString() === ""); + +const missing = spawnSync("/nonexistent/tool", [], { env: { A: "1" } }); +console.log(missing.status, missing.error?.message); diff --git a/tests/harness/corpus-costs/7030-spawn-sync-env.ts.json b/tests/harness/corpus-costs/7030-spawn-sync-env.ts.json new file mode 100644 index 000000000..cf8ef4d26 --- /dev/null +++ b/tests/harness/corpus-costs/7030-spawn-sync-env.ts.json @@ -0,0 +1 @@ +{ "plain": 2460, "san": 4060 } From 7259f10ad47c79d5f201502eb88208990ad82d08 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 08:16:36 -0500 Subject: [PATCH 14/45] Keep running maximum and minimum updates as branches With a running maximum in a register, LLVM turns `if (v > max) { max = v; at = i; }` into selects, so each element waits on the previous one's `maxsd`. The update gets rarer as a scan goes on and its branch predicts well, so such an `if` now carries branch weights that say it is rarely taken, and LLVM keeps the branch. An `if` qualifies when it has no `else`, its condition is one numeric `<`, `<=`, `>` or `>=` between a local and another expression, and it assigns that expression to the local. The local must be an accumulator: inside a loop the `if` is a statement of the innermost loop's body, the local is declared outside that loop, and the loop writes it only in this `if`; outside a loop the `if` is a statement of the function body and the local is a binding the function captures and writes only there, as in a callback. A clamp of a value read in the same iteration, or a sum clamped after each addition, is left alone: its branch goes whichever way the data goes. So is an update nested in another branch, whose kept branch can stop LLVM from turning the enclosing, data-dependent branch into selects. --- packages/compiler/src/backend/llvm/blocks.ts | 4 +- .../src/backend/llvm/emit-function.ts | 2 + .../src/backend/llvm/emit-statements.ts | 7 +- packages/compiler/src/backend/llvm/emitter.ts | 3 + .../src/backend/llvm/running-extrema.test.ts | 97 ++++++++++ .../src/backend/llvm/running-extrema.ts | 110 ++++++++++++ .../test/running-extrema-branches.test.ts | 75 ++++++++ .../7301-running-extrema-branches.ts.json | 6 + tests/corpus/7301-running-extrema-branches.ts | 169 ++++++++++++++++++ .../7301-running-extrema-branches.ts.json | 1 + 10 files changed, 471 insertions(+), 3 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/running-extrema.test.ts create mode 100644 packages/compiler/src/backend/llvm/running-extrema.ts create mode 100644 packages/compiler/test/running-extrema-branches.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7301-running-extrema-branches.ts.json create mode 100644 tests/corpus/7301-running-extrema-branches.ts create mode 100644 tests/harness/corpus-costs/7301-running-extrema-branches.ts.json diff --git a/packages/compiler/src/backend/llvm/blocks.ts b/packages/compiler/src/backend/llvm/blocks.ts index 6d22bf3bf..354e631c6 100644 --- a/packages/compiler/src/backend/llvm/blocks.ts +++ b/packages/compiler/src/backend/llvm/blocks.ts @@ -95,8 +95,8 @@ export class BlockBuilder { this.terminate(`br label %${label}`); } - condBr(v: string, t: string, f: string): void { - this.terminate(`br i1 ${v}, label %${t}, label %${f}`); + condBr(v: string, t: string, f: string, attachment = ""): void { + this.terminate(`br i1 ${v}, label %${t}, label %${f}${attachment}`); } /** Emit a double-indexed `for (i = 0; i < len; i++)` loop. `next` is diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index 09e6551c3..3aa9a28a7 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -55,6 +55,7 @@ import { INT32_ABI_SUFFIX, SCALAR_UNION_RESULT } from "./int32-abi.js"; import { f64Lit } from "./common.js"; import { RESULT_ENTRY_PREFIX } from "./record-results.js"; import { emitIntegerClone, emitIntegerDispatcher } from "./integer-clones.js"; +import { runningExtremumUpdates } from "./running-extrema.js"; export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { const B = new BlockBuilder(); @@ -81,6 +82,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.currentLocals.set(id, plain); emitter.lazyCaptureBoxes.set(id, ""); } + emitter.runningExtrema = emitter.debug === null ? runningExtremumUpdates(fn) : new Set(); emitter.currentConstantCallbacks = emitter.debug === null ? (emitter.constantCallbacks.get(fn.name) ?? new Map()) : new Map(); // Preserve concrete source bindings for debugger inspection. Suspended diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 7239db7d8..0227776ab 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -782,7 +782,12 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { const trueLabel = B.newLabel("if.t"); const joinLabel = B.newLabel("if.j"); const falseLabel = s.else_ ? B.newLabel("if.f") : joinLabel; - B.condBr(cond, trueLabel, falseLabel); + // A running maximum or minimum is rarely updated; the weights keep + // the branch, where a select would make each element wait on the last. + const weights = emitter.runningExtrema.has(s) + ? `, !prof !{!"branch_weights", i32 1, i32 1000}` + : ""; + B.condBr(cond, trueLabel, falseLabel, weights); B.startBlock(trueLabel); emitter.emitBlock(s.then); B.br(joinLabel); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index ed1785912..ed1029b85 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -831,6 +831,9 @@ export class LlEmitter { readonly callLifetimes: CallLifetimes; readonly constantCallbacks: Map>; currentConstantCallbacks: ReadonlyMap = new Map(); + /** The current function's running maximum and minimum updates, whose + * branches are weighted as rarely taken (running-extrema.ts). */ + runningExtrema: ReadonlySet = new Set(); readonly stackCallbacks: StackCallbacks; readonly receiverReaders: AmbientReceiverReaders; readonly stackCaptures: StackCaptures; diff --git a/packages/compiler/src/backend/llvm/running-extrema.test.ts b/packages/compiler/src/backend/llvm/running-extrema.test.ts new file mode 100644 index 000000000..4ce307c5c --- /dev/null +++ b/packages/compiler/src/backend/llvm/running-extrema.test.ts @@ -0,0 +1,97 @@ +import { expect, test } from "vitest"; +import { BOOL, F64, type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; +import { runningExtremumUpdates } from "./running-extrema.js"; + +const loc = { file: "extrema.ts", start: 0, end: 0 }; +const ref = (localId: string): IrExpr => ({ kind: "varRef", localId, type: F64, loc }); +const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); +const assign = (localId: string, value: IrExpr): IrStmt => ({ + kind: "assign", + localId, + value, + loc, +}); +const decl = (localId: string): IrStmt => ({ kind: "varDecl", localId, init: num(0), loc }); +const compare = (op: "<" | ">", left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "bin", + op, + left, + right, + type: BOOL, + loc, +}); +/** `if (v > max) max = v;` */ +const update = (): IrStmt & { kind: "if" } => ({ + kind: "if", + cond: compare(">", ref("v"), ref("max")), + then: [assign("max", ref("v"))], + else_: null, + loc, +}); +const loop = (body: IrStmt[]): IrStmt => ({ + kind: "while", + cond: compare(">", ref("n"), num(0)), + body, + loc, +}); +const fn = (body: IrStmt[], captures: string[] = []): IrFunction => ({ + name: "scan", + params: [], + locals: ["v", "max", "n"].map((id) => ({ id, name: id, type: F64, mutable: true })), + captures: captures.map((localId) => ({ localId, name: localId, type: F64 })), + returnType: F64, + body, + loc, +}); + +test("a loop's update of an accumulator declared outside it qualifies", () => { + const s = update(); + expect(runningExtremumUpdates(fn([decl("max"), loop([decl("v"), s])])).has(s)).toBe(true); +}); + +test("the local may be on either side of the comparison", () => { + const s = update(); + s.cond = compare("<", ref("max"), ref("v")); + expect(runningExtremumUpdates(fn([decl("max"), loop([s])])).has(s)).toBe(true); +}); + +test("a local declared in the loop is not an accumulator", () => { + const s = update(); + expect(runningExtremumUpdates(fn([loop([decl("max"), s])])).size).toBe(0); +}); + +test("another write in the loop disqualifies the update", () => { + const s = update(); + const body = [decl("max"), loop([assign("max", num(1)), s])]; + expect(runningExtremumUpdates(fn(body)).size).toBe(0); +}); + +test("the assigned value must be the compared expression", () => { + const s = update(); + s.then = [assign("max", num(5))]; + expect(runningExtremumUpdates(fn([decl("max"), loop([s])])).size).toBe(0); +}); + +test("outside a loop only a captured binding qualifies", () => { + const captured = update(); + expect(runningExtremumUpdates(fn([captured], ["max"])).has(captured)).toBe(true); + expect(runningExtremumUpdates(fn([update()])).size).toBe(0); +}); + +test("an else branch disqualifies the update", () => { + const s = update(); + s.else_ = [assign("v", num(0))]; + expect(runningExtremumUpdates(fn([decl("max"), loop([s])])).size).toBe(0); +}); + +test("an update nested in another branch does not qualify", () => { + const s = update(); + const guard: IrStmt = { + kind: "if", + cond: compare(">", ref("v"), num(0)), + then: [s], + else_: null, + loc, + }; + expect(runningExtremumUpdates(fn([decl("max"), loop([guard])])).size).toBe(0); +}); diff --git a/packages/compiler/src/backend/llvm/running-extrema.ts b/packages/compiler/src/backend/llvm/running-extrema.ts new file mode 100644 index 000000000..1ddea603d --- /dev/null +++ b/packages/compiler/src/backend/llvm/running-extrema.ts @@ -0,0 +1,110 @@ +// Running maximum and minimum updates, `if (v > max) { max = v; ... }`. +// With the accumulator in a register LLVM turns such an update into a +// select (`maxsd`, or a compare and mask), so every element waits on the +// previous one's. The update gets rarer as a scan goes on, so a branch +// predicts well; emitStmtBody gives these `if`s branch weights that say the +// update is rarely taken, and LLVM keeps the branch. A clamp of a value read +// in the same iteration is not an accumulator and keeps its select: its +// branch would go whichever way the data goes. An update nested in another +// branch keeps its select too: kept, its branch can stop LLVM from turning +// the enclosing branch into selects, and that branch may follow the data. + +import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; +import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; + +type Loop = IrStmt & { kind: "for" | "while" | "doWhile" | "forOf" }; + +const RELATIONAL = new Set(["<", "<=", ">", ">="]); + +/** The `if` statements of `fn` that update a running maximum or minimum: + * no `else`, a numeric `<`, `<=`, `>` or + * `>=` between a local and another expression, and a then-block that + * assigns that expression to the local. The local must carry across + * iterations: inside a loop the `if` is a statement of the innermost loop's + * body, the local is declared outside that loop, and the loop writes it only + * in this `if`; outside any loop the `if` is a statement of the function + * body and the local is a binding the function captures and writes only in + * this `if` (a callback that a loop elsewhere calls). */ +export function runningExtremumUpdates(fn: IrFunction): Set { + const found = new Set(); + const captured = new Set((fn.captures ?? []).map((c) => c.localId)); + const loops: Loop[] = []; + const candidates: { s: IrStmt; local: string; loop: Loop | undefined }[] = []; + const expr = (e: IrExpr): boolean => everyExprChild(e, expr, stmt); + const stmt = (s: IrStmt): boolean => { + if (s.kind === "if") { + const local = updatedExtremum(s); + if (local !== undefined) candidates.push({ s, local, loop: loops[loops.length - 1] }); + } + const loop = + s.kind === "for" || s.kind === "while" || s.kind === "doWhile" || s.kind === "forOf"; + if (loop) loops.push(s); + everyStmtChild(s, expr, stmt); + if (loop) loops.pop(); + return true; + }; + for (const s of fn.body) stmt(s); + for (const { s, local, loop } of candidates) { + const scope = loop ?? (captured.has(local) ? fn.body : undefined); + const body = loop ? loop.body : fn.body; + if (scope !== undefined && body.includes(s) && writes(scope, local) === 1) found.add(s); + } + return found; +} + +/** The local an `if` updates to a new maximum or minimum, if it is one. */ +function updatedExtremum(s: IrStmt & { kind: "if" }): string | undefined { + if (s.else_ !== null && s.else_.length > 0) return undefined; + const c = s.cond; + if (c.kind !== "bin" || !RELATIONAL.has(c.op)) return undefined; + if (c.left.type.kind !== "f64" || c.right.type.kind !== "f64") return undefined; + for (const [local, other] of [ + [c.left, c.right], + [c.right, c.left], + ]) { + if (local!.kind !== "varRef") continue; + const id = local!.localId; + const assigns = s.then.some( + (x) => x.kind === "assign" && x.localId === id && sameExpr(x.value, other!), + ); + if (assigns) return id; + } + return undefined; +} + +/** Declarations and writes of `local` under `scope`. A declaration counts + * as a write too, so a local declared inside a loop does not qualify. */ +function writes(scope: IrStmt | IrStmt[], local: string): number { + let n = 0; + const expr = (e: IrExpr): boolean => { + if ((e.kind === "assignExpr" || e.kind === "incDec") && e.localId === local) n++; + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + if ((s.kind === "assign" || s.kind === "varDecl" || s.kind === "forOf") && s.localId === local) + n++; + else if (s.kind === "tryCatch" && s.catchLocalId === local) n++; + return everyStmtChild(s, expr, stmt); + }; + if (Array.isArray(scope)) for (const s of scope) stmt(s); + else stmt(scope); + return n; +} + +/** Structural equality of two small expressions (`v`, `a[i]`), ignoring + * source locations and types; larger expressions do not compare equal. */ +function sameExpr(a: IrExpr, b: IrExpr): boolean { + let budget = 64; + const same = (x: unknown, y: unknown): boolean => { + if (--budget < 0) return false; + if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) return x === y; + if (Array.isArray(x) !== Array.isArray(y)) return false; + const keys = Object.keys(x).filter((k) => k !== "loc" && k !== "type"); + if (keys.length !== Object.keys(y).filter((k) => k !== "loc" && k !== "type").length) + return false; + return keys.every((k) => + same((x as Record)[k], (y as Record)[k]), + ); + }; + return same(a, b); +} diff --git a/packages/compiler/test/running-extrema-branches.test.ts b/packages/compiler/test/running-extrema-branches.test.ts new file mode 100644 index 000000000..e1f5a7837 --- /dev/null +++ b/packages/compiler/test/running-extrema-branches.test.ts @@ -0,0 +1,75 @@ +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-running-extrema-")); + 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" }); + if (!result.ok) throw new Error(result.diagnostics.map((d) => d.message).join("\n")); + return await readFile(outPath, "utf8"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +const RARE = + /br i1 %\S+, label %if\.t\d+, label %if\.j\d+, !prof !\{!"branch_weights", i32 1, i32 1000\}/; + +test("a running maximum's update is weighted as rarely taken", async () => { + const llvm = await emitLlvm(` + function argmax(a: Float64Array): number { + let max = -Infinity; + let at = -1; + for (let i = 0; i < a.length; i++) { + const v = a[i]!; + if (v > max) { max = v; at = i; } + } + return at; + } + console.log(argmax(new Float64Array([1, 3, 2]))); + `); + expect(llvm).toMatch(RARE); +}); + +test("a callback's update of a captured minimum is weighted", async () => { + const llvm = await emitLlvm(` + function least(values: number[]): number { + let min = Infinity; + values.forEach((v) => { if (min > v) min = v; }); + return min; + } + console.log(least([3, 1, 2])); + `); + expect(llvm).toMatch(RARE); +}); + +test("clamps and saturating sums keep their selects", async () => { + const llvm = await emitLlvm(` + function clampSum(a: Float64Array, hi: number): number { + let s = 0; + for (let i = 0; i < a.length; i++) { + let v = a[i]!; + if (hi < v) v = hi; + s += v; + } + return s; + } + function saturate(a: Float64Array, hi: number): number { + let v = 0; + for (let i = 0; i < a.length; i++) { + v += a[i]!; + if (hi < v) v = hi; + } + return v; + } + const a = new Float64Array([0.5, 2, 0.25]); + console.log(clampSum(a, 1), saturate(a, 1)); + `); + expect(llvm).not.toContain("branch_weights"); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7301-running-extrema-branches.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7301-running-extrema-branches.ts.json new file mode 100644 index 000000000..6dcb4b57d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7301-running-extrema-branches.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7301-running-extrema-branches.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7301-running-extrema-branches.ts b/tests/corpus/7301-running-extrema-branches.ts new file mode 100644 index 000000000..9941ce538 --- /dev/null +++ b/tests/corpus/7301-running-extrema-branches.ts @@ -0,0 +1,169 @@ +// Running maximum and minimum scans over ascending, descending, alternating, +// pseudo-random and NaN-holding data: plain for, while, do-while and for-of +// loops, `<=` and `>=` ties, an argmax that records its index, typed array +// and array element reads, callbacks that update captured bindings, a scan +// nested in an outer loop, an update nested in another branch, and the clamp +// and saturating updates that are not running extrema. + +function shapes(n: number): [string, Float64Array][] { + const ascending = new Float64Array(n); + const descending = new Float64Array(n); + const alternating = new Float64Array(n); + const random = new Float64Array(n); + const holes = new Float64Array(n); + let x = 12345; + for (let i = 0; i < n; i++) { + ascending[i] = i; + descending[i] = n - i; + alternating[i] = i % 2 === 0 ? 0 : i; + x = (x * 1103515245 + 12345) % 2147483648; + random[i] = (x % 1000) - 500; + holes[i] = i % 7 === 3 ? NaN : (x % 97) - 48; + } + return [ + ["ascending", ascending], + ["descending", descending], + ["alternating", alternating], + ["random", random], + ["nan", holes], + ]; +} + +function argmax(a: Float64Array): string { + let max = -Infinity; + let at = -1; + for (let i = 0; i < a.length; i++) { + const v = a[i]!; + if (v > max) { + max = v; + at = i; + } + } + return `${max}@${at}`; +} + +function lastMin(a: Float64Array): string { + let min = Infinity; + let at = -1; + let i = 0; + while (i < a.length) { + if (a[i]! <= min) { + min = a[i]!; + at = i; + } + i++; + } + return `${min}@${at}`; +} + +function bothEnds(values: number[]): string { + let lo = Infinity; + let hi = -Infinity; + for (const v of values) { + if (lo > v) lo = v; + if (v >= hi) hi = v; + } + return `${lo}..${hi}`; +} + +function firstDrop(a: Float64Array): number { + let floor = a[0]!; + let i = 0; + do { + if (a[i]! < floor) floor = a[i]!; + i++; + } while (i < a.length); + return floor; +} + +function callbackPeak(a: Float64Array): string { + let max = -Infinity; + let at = -1; + a.forEach((v, i) => { + if (v > max) { + max = v; + at = i; + } + }); + return `${max}@${at}`; +} + +function arrayCallbackMin(values: number[]): number { + let min = Infinity; + values.forEach((v) => { + if (v < min) min = v; + }); + return min; +} + +function rowMaxima(a: Float64Array, width: number): string { + const out: number[] = []; + for (let row = 0; row * width < a.length; row++) { + let best = -Infinity; + for (let j = row * width; j < Math.min(a.length, (row + 1) * width); j++) { + if (a[j]! > best) best = a[j]!; + } + out.push(best); + } + return out.join(","); +} + +function longestNonNegativeRun(a: Float64Array): number { + let longest = 0; + let run = 0; + for (let i = 0; i < a.length; i++) { + if (a[i]! >= 0) { + run++; + if (run > longest) longest = run; + } else run = 0; + } + return longest; +} + +function clampSum(a: Float64Array, hi: number): number { + let s = 0; + for (let i = 0; i < a.length; i++) { + let v = a[i]!; + if (hi < v) v = hi; + s += v; + } + return s; +} + +function saturate(a: Float64Array, hi: number): number { + let v = 0; + for (let i = 0; i < a.length; i++) { + v += a[i]!; + if (hi < v) v = hi; + } + return v; +} + +for (const [name, a] of shapes(40)) { + const values = Array.from(a); + console.log( + name, + argmax(a), + lastMin(a), + bothEnds(values), + firstDrop(a), + callbackPeak(a), + arrayCallbackMin(values), + ); + console.log( + " rows", + rowMaxima(a, 7), + "run", + longestNonNegativeRun(a), + "clamp", + clampSum(a, 5), + "saturate", + saturate(a, 30), + ); +} + +const signed = new Float64Array([0, -0, 0, -0]); +let top = -Infinity; +for (let i = 0; i < signed.length; i++) if (signed[i]! >= top) top = signed[i]!; +console.log("signed zero", Object.is(top, -0), argmax(signed), lastMin(signed)); +console.log("empty", argmax(new Float64Array(0)), bothEnds([]), arrayCallbackMin([])); diff --git a/tests/harness/corpus-costs/7301-running-extrema-branches.ts.json b/tests/harness/corpus-costs/7301-running-extrema-branches.ts.json new file mode 100644 index 000000000..74df88f0c --- /dev/null +++ b/tests/harness/corpus-costs/7301-running-extrema-branches.ts.json @@ -0,0 +1 @@ +{ "plain": 5300, "san": 5800 } From 8aac437ed281fbedde2f96296c6ca867035b3e0a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 08:53:50 -0500 Subject: [PATCH 15/45] Keep reduce accumulators and callback argument counts as Node runs them Array reduce typed its accumulator by the call's checked type, widened with undefined only when the callback could return a missing value or a receiver without an initial value could have holes. Three runtime values fell outside it and threw "not representable in the target union": - an initial value read from a missing element; - a callback result of another primitive (`missing[0] ?? "fallback"`); - a callback wrapped in parentheses, which the analysis and the callback lowering did not see as the arrow it wraps. The accumulator now also takes undefined from a possibly missing initial value, and the primitive arms the callback's result can have. Array callbacks are taken without their parentheses. `arguments.length` in a fixed-arity function expression folded to its declared parameter count. When the expression flows into a fixed-arity function type with more parameters, as array callbacks do (value, index, array, and the accumulator for reduce), every call passes that type's count, and the length is that count. --- .../lowering/containers/callback-arguments.ts | 2 + .../lowering/expressions/property-access.ts | 30 +++++++++++-- .../compiler/src/frontend/lowering/lowerer.ts | 32 ++++++++++---- .../7184-reduce-runtime-accumulator.ts.json | 6 +++ ...85-array-callback-arguments-length.ts.json | 6 +++ .../corpus/7184-reduce-runtime-accumulator.ts | 24 +++++++++++ .../7185-array-callback-arguments-length.ts | 42 +++++++++++++++++++ .../7184-reduce-runtime-accumulator.ts.json | 1 + ...85-array-callback-arguments-length.ts.json | 1 + 9 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7184-reduce-runtime-accumulator.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7185-array-callback-arguments-length.ts.json create mode 100644 tests/corpus/7184-reduce-runtime-accumulator.ts create mode 100644 tests/corpus/7185-array-callback-arguments-length.ts create mode 100644 tests/harness/corpus-costs/7184-reduce-runtime-accumulator.ts.json create mode 100644 tests/harness/corpus-costs/7185-array-callback-arguments-length.ts.json diff --git a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts index 9db04e95b..d95640978 100644 --- a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts +++ b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts @@ -53,6 +53,8 @@ export function lowerArrayCallback( bindUntyped = false, expectedReturn?: IrType, ): { fnArg: IrExpr & { type: IrType & { kind: "func" } }; arity: number } { + // `xs.map(((x) => x))`: a parenthesized callback is the function itself. + while (ts.isParenthesizedExpression(argNode)) argNode = argNode.expression; // The ambient `Boolean` as the callback (`flags.every(Boolean)`, // `xs.some(Boolean)`, `xs.map(Boolean)`): Boolean(value) answers the // ToBoolean of its FIRST argument and ignores the rest, so the callback diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 7f3910c15..44d38acd4 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -666,11 +666,12 @@ export function lowerPropertyAccessExpr( ); if (fixedArity) { // A `this` parameter is type-only: callers never pass it. + const declared = (fn as ts.FunctionLikeDeclaration).parameters.nodes.filter( + (p) => !isThisParameter(p), + ).length; return { kind: "numLit", - value: (fn as ts.FunctionLikeDeclaration).parameters.nodes.filter( - (p) => !isThisParameter(p), - ).length, + value: Math.max(declared, contextualArgumentCount(lowerer, fn) ?? 0), type: F64, loc, }; @@ -4440,3 +4441,26 @@ function lowerPromiseConstructorRead( } return null; } + +/** 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; +} diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index b02a0a843..a42cadb48 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -6619,7 +6619,10 @@ export class Lowerer { node.expression.name.text, node.arguments.nodes.length >= 2, ); - const callback = node.arguments.nodes[0]; + // `xs.map(((x) => x))`: the parenthesized callback is the arrow. + let callback = node.arguments.nodes[0]; + while (callback !== undefined && ts.isParenthesizedExpression(callback)) + callback = callback.expression; if (callbackIndices !== null && callback !== undefined && !ts.isSpreadElement(callback)) { const receiverNode = node.expression.expression; const receiverTs = this.typeOf(receiverNode); @@ -6678,13 +6681,26 @@ export class Lowerer { presentSites.set(node, elementsPresent && !reduce); if (elementsPresent && reduce && retypeInlineCallback(callback, callbackIndices)) changed = true; - if ( - (method === "reduce" || method === "reduceRight") && - ((!elementsPresent && node.arguments.nodes.length < 2) || - callbackReturnsOptional(callback)) - ) { - if (promoteHofCallback(callback, [0, 1])) changed = true; - const result = this.runtimeOptionalType(this.irTypeOf(node)); + // The accumulator holds undefined when the callback can return + // it, when an initial value can be missing, or when elements can + // be absent and there is no initial value. It holds another + // primitive when the callback's result can be one at run time + // (`missing[0] ?? "fallback"`). + const initial = node.arguments.nodes[1]; + const optional = + (!elementsPresent && initial === undefined) || + (initial !== undefined && !ts.isSpreadElement(initial) && mayBeOptional(initial)) || + callbackReturnsOptional(callback); + const arithmetic = + reduce && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback)) + ? lambdaArithmeticReturn(callback) + : null; + if (reduce && (optional || arithmetic !== null)) { + if (optional && promoteHofCallback(callback, [0, 1])) changed = true; + let result = this.irTypeOf(node); + if (arithmetic !== null) + result = joinPrimitiveTypes([result, arithmetic]) ?? result; + if (optional) result = this.runtimeOptionalType(result); siteDependencies?.read(node); const previous = this.runtimeOptionalReduceTypes.get(node); if (!previous || !typeEquals(previous, result)) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7184-reduce-runtime-accumulator.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7184-reduce-runtime-accumulator.ts.json new file mode 100644 index 000000000..b93eb61b6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7184-reduce-runtime-accumulator.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7184-reduce-runtime-accumulator.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7185-array-callback-arguments-length.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7185-array-callback-arguments-length.ts.json new file mode 100644 index 000000000..2514bcaa8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7185-array-callback-arguments-length.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7185-array-callback-arguments-length.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7184-reduce-runtime-accumulator.ts b/tests/corpus/7184-reduce-runtime-accumulator.ts new file mode 100644 index 000000000..bd2c8e4d9 --- /dev/null +++ b/tests/corpus/7184-reduce-runtime-accumulator.ts @@ -0,0 +1,24 @@ +// Array reduce keeps the values its callback and initial value produce at +// run time: an initial value read from a missing element is undefined, a +// callback can produce another primitive through `??`, and a parenthesized +// callback widens like a bare one. +const noStrings: string[] = []; +const noNumbers: number[] = []; + +const fromMissingInit = ([] as number[]).reduce((_acc, _value) => "ok", noStrings[0]); +console.log(typeof fromMissingInit, fromMissingInit); + +const nonEmpty = [1, 2].reduce((acc, value) => acc + value, noNumbers[0]); +console.log(typeof nonEmpty, nonEmpty); + +const fallback = [1, 2].reduce((_acc, _value) => noNumbers[0] ?? "fallback"); +console.log(typeof fallback, fallback); + +const parenthesized = [1, 2].reduce((acc, x) => (x === 1 ? noStrings[0] : acc + "!"), ""); +console.log(parenthesized); + +const wrapped = [1, 2].reduce(((acc, x) => (x === 1 ? noStrings[0] : acc + "!")), ""); +console.log(wrapped); + +const right = ["a", "b"].reduceRight((acc, s) => acc + s, noStrings[0]); +console.log(right); diff --git a/tests/corpus/7185-array-callback-arguments-length.ts b/tests/corpus/7185-array-callback-arguments-length.ts new file mode 100644 index 000000000..ae5a8d847 --- /dev/null +++ b/tests/corpus/7185-array-callback-arguments-length.ts @@ -0,0 +1,42 @@ +// `arguments.length` in a function-expression callback counts every +// argument the array method passes: value, index and array, plus the +// accumulator for reduce. One stored in a fixed-arity function type counts +// that type's parameters, which every call passes. +const seen: number[] = []; +[10, 20].forEach(function (value) { + seen.push(arguments.length, value); +}); +console.log(seen.join(",")); + +console.log( + [1, 2] + .map(function (value) { + return `${value}:${arguments.length}`; + }) + .join(" "), +); + +console.log([5].filter(function () { + return arguments.length === 3; +}).length); + +console.log([1].reduce(function (acc, value) { + return acc + value + arguments.length; +}, 0)); + +console.log(["x", "y"].reduceRight(function (acc: string, value: string) { + return `${acc}${value}${arguments.length}`; +}, "")); + +console.log([3, 4].some(function (value) { + return arguments.length === 3 && value === 4; +})); + +const sum: (a: number, b: number) => number = function (a) { + return a + arguments.length; +}; +console.log(sum(1, 2)); + +console.log([3, 1, 2].sort(function (a, b) { + return arguments.length === 2 ? a - b : 0; +}).join(",")); diff --git a/tests/harness/corpus-costs/7184-reduce-runtime-accumulator.ts.json b/tests/harness/corpus-costs/7184-reduce-runtime-accumulator.ts.json new file mode 100644 index 000000000..c480bea3f --- /dev/null +++ b/tests/harness/corpus-costs/7184-reduce-runtime-accumulator.ts.json @@ -0,0 +1 @@ +{ "plain": 2541, "san": 3260 } diff --git a/tests/harness/corpus-costs/7185-array-callback-arguments-length.ts.json b/tests/harness/corpus-costs/7185-array-callback-arguments-length.ts.json new file mode 100644 index 000000000..b86a9e70a --- /dev/null +++ b/tests/harness/corpus-costs/7185-array-callback-arguments-length.ts.json @@ -0,0 +1 @@ +{ "plain": 2528, "san": 3201 } From 20f4d1ff125804302495c2f357f1f10cfa5efa3d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:08:35 -0500 Subject: [PATCH 16/45] Support the legacy createCipheriv modes and crypto.checkPrime/generatePrime --- .../limitations/builtin-apis/crypto.mdx | 5 +- .../src/generated/node-v24-compatibility.json | 24 +- .../generated/node-v24-internal.json | 40 +- internal/compatibility/static-support.json | 8 +- .../ambient/scriptc-node-fallback.d.ts | 58 +- .../compiler/src/backend/llvm/lib-shared.ts | 6 + .../src/backend/target-diagnostics.ts | 8 +- .../src/frontend/lowering/builtins/crypto.ts | 77 ++- .../src/frontend/lowering/surfaces.ts | 9 +- packages/compiler/src/ir/builtin-effects.ts | 6 + .../compiler/src/ir/builtin-signatures.ts | 10 + packages/compiler/src/ir/runtime-features.ts | 18 +- packages/compiler/src/library/ir-policy.ts | 2 + packages/compiler/surface-manifest.json | 26 +- .../corpus/7150-cipher-legacy-modes.ts.json | 6 + .../corpus/7151-cipher-legacy-errors.cjs.json | 6 + .../tests/corpus/7152-crypto-prime.ts.json | 6 + .../corpus/7153-crypto-prime-errors.cjs.json | 6 + packages/runtime/src/scr_cipher.c | 324 +++++++++-- packages/runtime/src/scr_crypto.h | 8 + packages/runtime/src/scr_dh.c | 536 +++++++++++++++++- tests/corpus/7150-cipher-legacy-modes.ts | 74 +++ tests/corpus/7151-cipher-legacy-errors.cjs | 83 +++ tests/corpus/7152-crypto-prime.ts | 96 ++++ tests/corpus/7153-crypto-prime-errors.cjs | 80 +++ tests/fixtures/node-types/fenced.ts | 8 +- .../__snapshots__/node-types-fenced.txt | 14 +- .../7150-cipher-legacy-modes.ts.json | 1 + .../7151-cipher-legacy-errors.cjs.json | 1 + .../corpus-costs/7152-crypto-prime.ts.json | 1 + .../7153-crypto-prime-errors.cjs.json | 1 + tests/harness/errors.test.ts | 5 +- 32 files changed, 1445 insertions(+), 108 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7150-cipher-legacy-modes.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7151-cipher-legacy-errors.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7152-crypto-prime.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7153-crypto-prime-errors.cjs.json create mode 100644 tests/corpus/7150-cipher-legacy-modes.ts create mode 100644 tests/corpus/7151-cipher-legacy-errors.cjs create mode 100644 tests/corpus/7152-crypto-prime.ts create mode 100644 tests/corpus/7153-crypto-prime-errors.cjs create mode 100644 tests/harness/corpus-costs/7150-cipher-legacy-modes.ts.json create mode 100644 tests/harness/corpus-costs/7151-cipher-legacy-errors.cjs.json create mode 100644 tests/harness/corpus-costs/7152-crypto-prime.ts.json create mode 100644 tests/harness/corpus-costs/7153-crypto-prime-errors.cjs.json diff --git a/docs/content/limitations/builtin-apis/crypto.mdx b/docs/content/limitations/builtin-apis/crypto.mdx index c84ce3e52..971065408 100644 --- a/docs/content/limitations/builtin-apis/crypto.mdx +++ b/docs/content/limitations/builtin-apis/crypto.mdx @@ -8,7 +8,7 @@ `randomFill`, `randomFillSync` (every view kind and ArrayBuffer), `randomInt`, `randomUUID`, and `randomUUIDv7` follow Node 24.22, including callback timing; a `randomInt` callback whose error parameter is typed `Error | null` receives `null` where Node passes `undefined`. Scrypt supports its default parameters, numeric options, aliases, and memory limit. Both KDFs accept strings, Buffers, numeric typed arrays, DataViews, and fixed-length ArrayBuffers. - `createCipheriv` and `createDecipheriv` support aes-128, aes-192, and aes-256 in CBC, CTR, and GCM modes and chacha20-poly1305, on native targets, through `update()`, `final()`, `setAAD()`, `setAutoPadding()`, `getAuthTag()`, and `setAuthTag()`; other ciphers and wasm32-wasi builds are refused. + `createCipheriv` and `createDecipheriv` support aes-128, aes-192, and aes-256 in CBC, CTR, GCM, ECB, CFB, CFB8, CFB1, and OFB modes, des-ede3 in CBC, ECB, CFB, CFB8, CFB1, and OFB modes, des-ede in CBC, ECB, CFB, and OFB modes, chacha20, and chacha20-poly1305, on native targets, through `update()`, `final()`, `setAAD()`, `setAutoPadding()`, `getAuthTag()`, and `setAuthTag()`; other ciphers and wasm32-wasi builds are refused. Cipheriv and Decipheriv values are also Transforms: they can be written, piped into, used as `pipeline()` stages, read, iterated with `for await`, and listened to, and their stream properties read as in Node; written chunks go through `update()`, and the end pushes `final()` or reports its error through `'error'`. Through `unknown` and `any` slots and untyped JavaScript, in a program that uses streams, their stream properties and their `on`, `once`, `off`, `pipe`, `unpipe`, `read`, `pause`, `resume`, `setEncoding`, `write`, `end`, `destroy`, `cork`, and `uncork` members work; `write` and `end` take no encoding or callback there, and the other stream members throw a coded SC2020 error. Hash, Hmac, Cipheriv, and Decipheriv streams count a written string's bytes in `writableLength`, where Node counts the string's length. @@ -25,6 +25,9 @@ `Object.keys()` and `in` do not see a DiffieHellman's own `verifyError` property, and `JSON.stringify()` and `instanceof` are refused. After `createDiffieHellman(primeLength)` throws `Invalid DH parameters`, the next OpenSSL error Node throws can list the failed generation's errors in `opensslErrorStack`; errors in a compiled binary list only their own. `crypto.diffieHellman`, which takes DH, EC, or X25519 KeyObjects, and the `DiffieHellman` and `DiffieHellmanGroup` constructors are not available. + `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, and Ed25519 private and public KeyObjects come from `generateKeyPairSync`, `generateKeyPair`, `createPrivateKey`, and `createPublicKey`, on native targets. 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 keys use PKCS#8, SubjectPublicKeyInfo, and JWK); `createPublicKey` also takes a private key or an X.509 certificate. diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 574c49ff4..c341da852 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -11085,9 +11085,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" } }, { @@ -11108,9 +11108,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" } }, { @@ -11614,9 +11614,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" } }, { @@ -11637,9 +11637,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 31ce5da02..9393fcaa8 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -19328,6 +19328,10 @@ "tests/corpus/7084-crypto-key-pairs.cjs", "tests/corpus/7122-webcrypto-node-crypto.ts", "tests/corpus/7123-webcrypto-node-crypto.cjs", + "tests/corpus/7150-cipher-legacy-modes.ts", + "tests/corpus/7151-cipher-legacy-errors.cjs", + "tests/corpus/7152-crypto-prime.ts", + "tests/corpus/7153-crypto-prime-errors.cjs", "tests/corpus/node24-crypto-kdf-errors.ts", "tests/corpus/node24-crypto-kdf-options.ts", "tests/corpus/node24-crypto-kdf.ts", @@ -19658,8 +19662,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "surface-manifest:node-builtin.crypto.checkPrime", + "tests": [ + "tests/corpus/7152-crypto-prime.ts", + "tests/corpus/7153-crypto-prime-errors.cjs" + ] }, "anchorSource": "exact" }, @@ -19681,8 +19689,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "surface-manifest:node-builtin.crypto.checkPrimeSync", + "tests": [ + "tests/corpus/7152-crypto-prime.ts", + "tests/corpus/7153-crypto-prime-errors.cjs" + ] }, "anchorSource": "exact" }, @@ -19707,6 +19719,8 @@ "status": "partial", "evidence": "surface-manifest:node-builtin.crypto.createCipheriv", "tests": [ + "tests/corpus/7150-cipher-legacy-modes.ts", + "tests/corpus/7151-cipher-legacy-errors.cjs", "tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", @@ -19746,6 +19760,8 @@ "status": "partial", "evidence": "surface-manifest:node-builtin.crypto.createDecipheriv", "tests": [ + "tests/corpus/7150-cipher-legacy-modes.ts", + "tests/corpus/7151-cipher-legacy-errors.cjs", "tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", @@ -20364,8 +20380,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "surface-manifest:node-builtin.crypto.generatePrime", + "tests": [ + "tests/corpus/7152-crypto-prime.ts", + "tests/corpus/7153-crypto-prime-errors.cjs" + ] }, "anchorSource": "exact" }, @@ -20387,8 +20407,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "surface-manifest:node-builtin.crypto.generatePrimeSync", + "tests": [ + "tests/corpus/7152-crypto-prime.ts", + "tests/corpus/7153-crypto-prime-errors.cjs" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index a59d6365a..06aad26cf 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -42,8 +42,10 @@ "node-builtin.child_process": ["tests/corpus/1361-spawn-events.ts", "tests/corpus/1565-spawn-pipe-streams.ts", "tests/corpus/2911-execfile-callback.ts", "tests/corpus/2939-child-shell-text.ts", "tests/corpus/2946-child-fork-ipc/main.ts", "tests/corpus/3127-spawn-runtime-options.ts", "tests/corpus/3130-child-generic-streams.ts", "tests/corpus/3131-child-rest-listeners.js", "tests/corpus/3132-child-generic-stream-completion.ts"], "node-builtin.cluster": ["tests/corpus/957-builtins-namespace.ts"], "node-builtin.console": ["tests/corpus/console-imports.cjs", "tests/corpus/2440-console-inspect-args.ts", "tests/corpus/console-native-value.js", "tests/harness/npm-static.test.ts"], - "node-builtin.crypto.createCipheriv": ["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"], - "node-builtin.crypto.createDecipheriv": ["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"], + "node-builtin.crypto.checkPrime": ["tests/corpus/7152-crypto-prime.ts", "tests/corpus/7153-crypto-prime-errors.cjs"], + "node-builtin.crypto.checkPrimeSync": ["tests/corpus/7152-crypto-prime.ts", "tests/corpus/7153-crypto-prime-errors.cjs"], + "node-builtin.crypto.createCipheriv": ["tests/corpus/7150-cipher-legacy-modes.ts", "tests/corpus/7151-cipher-legacy-errors.cjs", "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"], + "node-builtin.crypto.createDecipheriv": ["tests/corpus/7150-cipher-legacy-modes.ts", "tests/corpus/7151-cipher-legacy-errors.cjs", "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"], "node-builtin.crypto.createDiffieHellman": ["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"], "node-builtin.crypto.createDiffieHellmanGroup": ["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"], "node-builtin.crypto.createECDH": ["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"], @@ -120,6 +122,8 @@ "node-builtin.os.version": ["tests/corpus/5140-os-host-facts.ts"], "node-builtin.os.constants": ["tests/corpus/5141-os-constants.ts"], "node-builtin.fs.constants": ["tests/corpus/6207-fs-constants-object.ts", "tests/corpus/6208-fs-constants-require.cjs"], + "node-builtin.crypto.generatePrime": ["tests/corpus/7152-crypto-prime.ts", "tests/corpus/7153-crypto-prime-errors.cjs"], + "node-builtin.crypto.generatePrimeSync": ["tests/corpus/7152-crypto-prime.ts", "tests/corpus/7153-crypto-prime-errors.cjs"], "node-builtin.crypto.getDiffieHellman": ["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"], "node-builtin.crypto.getRandomValues": ["tests/corpus/6204-crypto-get-random-values.ts", "tests/corpus/6205-crypto-get-random-values.js"], "node-builtin.url.parse": ["tests/corpus/5220-url-parse-warnings.ts", "tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", "tests/corpus/5223-url-parse-query.ts", "tests/corpus/5227-url-legacy-dependency/main.ts", "tests/corpus/5229-url-legacy-errors.cjs", "packages/runtime/test/url-legacy.test.ts", "tests/fixtures/node-types/url-legacy.ts"], diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 2a3f11be9..519608393 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3171,7 +3171,8 @@ declare module "crypto" { callback: (error: Error | null, buffer: Buffer) => void, ): void; export type BinaryLike = string | ArrayBuffer | ArrayBufferView; - /* Cipheriv/Decipheriv: aes-128/192/256 in cbc, ctr, and gcm modes and + /* Cipheriv/Decipheriv: aes-128/192/256 in cbc, ctr, gcm, ecb, cfb, cfb8, + * cfb1, and ofb modes, des-ede3 and des-ede, chacha20, and * chacha20-poly1305. Both are Transforms: written chunks go through * update(), and the end pushes final(). */ export type CipherGCMTypes = "aes-128-gcm" | "aes-192-gcm" | "aes-256-gcm"; @@ -3351,6 +3352,61 @@ declare module "crypto" { ): DiffieHellman; export function getDiffieHellman(groupName: string): DiffieHellmanGroup; export function createDiffieHellmanGroup(name: string): DiffieHellmanGroup; + export type LargeNumberLike = ArrayBufferView | SharedArrayBuffer | ArrayBuffer | bigint; + export interface GeneratePrimeOptions { + add?: LargeNumberLike | undefined; + rem?: LargeNumberLike | undefined; + safe?: boolean | undefined; + bigint?: boolean | undefined; + } + export interface GeneratePrimeOptionsBigInt extends GeneratePrimeOptions { + bigint: true; + } + export interface GeneratePrimeOptionsArrayBuffer extends GeneratePrimeOptions { + bigint?: false | undefined; + } + export function generatePrime( + size: number, + callback: (err: Error | null, prime: ArrayBuffer) => void, + ): void; + export function generatePrime( + size: number, + options: GeneratePrimeOptionsBigInt, + callback: (err: Error | null, prime: bigint) => void, + ): void; + export function generatePrime( + size: number, + options: GeneratePrimeOptionsArrayBuffer, + callback: (err: Error | null, prime: ArrayBuffer) => void, + ): void; + export function generatePrime( + size: number, + options: GeneratePrimeOptions, + callback: (err: Error | null, prime: ArrayBuffer | bigint) => void, + ): void; + export function generatePrimeSync(size: number): ArrayBuffer; + export function generatePrimeSync(size: number, options: GeneratePrimeOptionsBigInt): bigint; + export function generatePrimeSync( + size: number, + options: GeneratePrimeOptionsArrayBuffer, + ): ArrayBuffer; + export function generatePrimeSync( + size: number, + options: GeneratePrimeOptions, + ): ArrayBuffer | bigint; + export interface CheckPrimeOptions { + checks?: number | undefined; + } + export function checkPrime( + value: LargeNumberLike, + callback: (err: Error | null, result: boolean) => void, + ): void; + export function checkPrime( + value: LargeNumberLike, + options: CheckPrimeOptions, + callback: (err: Error | null, result: boolean) => void, + ): void; + export function checkPrimeSync(candidate: LargeNumberLike, options?: CheckPrimeOptions): boolean; export interface ScryptOptions { N?: number; r?: number; diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9a65d9a24..23f0a0291 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -579,6 +579,10 @@ export const LIB_FN_SYMS: Record = { "crypto.ecdhNew": "scr_crypto_ecdh_new", "crypto.ecdhConvertKey": "scr_crypto_ecdh_convert_key", "crypto.dhNew": "scr_crypto_dh_new", + "crypto.checkPrimeSync": "scr_crypto_check_prime_sync", + "crypto.checkPrimeCb": "scr_crypto_check_prime_async", + "crypto.generatePrimeSync": "scr_crypto_generate_prime_sync", + "crypto.generatePrimeCb": "scr_crypto_generate_prime_async", "crypto.dhGroupNew": "scr_crypto_dh_group_new", "crypto.hmacNewStr": "scr_crypto_hmac_new_str", "crypto.hmacNewBytes": "scr_crypto_hmac_new_bytes", @@ -1600,6 +1604,8 @@ export function mockTimerSym( export const USES_TIMERS_LIB_FNS = new Set([ "crypto.generateKeyPairCb", + "crypto.checkPrimeCb", + "crypto.generatePrimeCb", "process.emitWarning", // Constructor-function streams defer their events on the stream ticks. "dyn.builtinStreamClass", diff --git a/packages/compiler/src/backend/target-diagnostics.ts b/packages/compiler/src/backend/target-diagnostics.ts index 3e97d0c10..236ce12cf 100644 --- a/packages/compiler/src/backend/target-diagnostics.ts +++ b/packages/compiler/src/backend/target-diagnostics.ts @@ -3,6 +3,7 @@ import type { LlvmUnsupportedError } from "./llvm/emitter.js"; import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; import { type IrModule, type SrcLoc } from "../ir/ir.js"; import { + DH_LIB_FNS, PKI_LIB_FNS, moduleUsesFetch, moduleUsesWebCryptoAsymmetric, @@ -232,9 +233,12 @@ export function moduleWasiUnavailableSurface( }; return false; } - if (node.fn === "crypto.dhNew" || node.fn === "crypto.dhGroupNew") { + if (DH_LIB_FNS.has(node.fn)) { found = { - surface: "DiffieHellman (the wasm32-wasi runtime does not include the mbedTLS library)", + surface: + node.fn === "crypto.dhNew" || node.fn === "crypto.dhGroupNew" + ? "DiffieHellman (the wasm32-wasi runtime does not include the mbedTLS library)" + : "checkPrime and generatePrime (the wasm32-wasi runtime does not include the mbedTLS library)", loc, }; return false; diff --git a/packages/compiler/src/frontend/lowering/builtins/crypto.ts b/packages/compiler/src/frontend/lowering/builtins/crypto.ts index 7a1791197..47e66f9b2 100644 --- a/packages/compiler/src/frontend/lowering/builtins/crypto.ts +++ b/packages/compiler/src/frontend/lowering/builtins/crypto.ts @@ -702,6 +702,8 @@ export function lowerCryptoModuleCall( } const pki = lowerPkiCall(lowerer, expr, bi.member, args, loc); if (pki) return pki; + const prime = lowerPrimeCall(lowerer, expr, bi.member, args, loc); + if (prime) return prime; if (bi.member === "createSecretKey") { if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) lowerer.noLowering( @@ -867,11 +869,29 @@ const IMPLEMENTED_CIPHERS = new Set([ "id-aes192-gcm", "id-aes256-gcm", "chacha20-poly1305", + ...["128", "192", "256"].flatMap((bits) => + ["ecb", "cfb", "cfb8", "cfb1", "ofb"].map((mode) => `aes-${bits}-${mode}`), + ), + "des-ede3-cbc", + "des3", + "des-ede3", + "des-ede3-ecb", + "des-ede3-cfb", + "des-ede3-cfb8", + "des-ede3-cfb1", + "des-ede3-ofb", + "des-ede-cbc", + "des-ede", + "des-ede-ecb", + "des-ede-cfb", + "des-ede-ofb", + "chacha20", ]); const SUPPORTED_CIPHERS_HINT = - "the supported ciphers are aes-128-cbc, aes-192-cbc, aes-256-cbc, aes-128-ctr, aes-192-ctr, " + - "aes-256-ctr, aes-128-gcm, aes-192-gcm, aes-256-gcm, and chacha20-poly1305"; + "the supported ciphers are aes-128, aes-192 and aes-256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1 " + + "and ofb modes, des-ede3 in cbc, ecb, cfb, cfb8, cfb1 and ofb modes, des-ede in cbc, ecb, cfb " + + "and ofb modes, chacha20, and chacha20-poly1305"; /** A literal cipher name that Node knows but the runtime does not * implement is refused at compile time. Unknown literal names keep Node's @@ -1346,6 +1366,59 @@ export function isWebCryptoReceiver(lowerer: Lowerer, receiver: ts.Expression): return false; } +/** Node calls checkPrime's and generatePrime's callbacks with undefined as + * the error, where @types/node declares Error | null: whether this + * callback's error parameter can hold undefined. One that cannot receives + * null instead. */ +function takesUndefinedError(lowerer: Lowerer, callback: ts.Expression): boolean { + const type = lowerer.irTypeOf(callback); + if (type.kind !== "func") return true; + const error = type.params[0]; + if (error === undefined || error.kind === "dyn" || error.kind === "undefinedT") return true; + if (error.kind !== "union") return false; + return !!lowerer.unions.get(error.unionId)?.arms.some((arm) => arm.kind === "undefinedT"); +} + +/** checkPrime, checkPrimeSync, generatePrime and generatePrimeSync + * (scr_dh.c): checked-dynamic arguments, which the runtime checks as Node + * does (a function in the options position is the callback), and the + * sync forms' boolean, ArrayBuffer or bigint converted to the call site's + * type. Null for other members. */ +function lowerPrimeCall( + lowerer: Lowerer, + expr: ts.CallExpression, + member: string, + args: readonly ts.Expression[], + loc: SrcLoc, +): IrExpr | null { + const forms: Readonly> = { + checkPrimeSync: ["crypto.checkPrimeSync", 1, 2, "checkPrimeSync(candidate[, options])"], + checkPrime: ["crypto.checkPrimeCb", 1, 3, "checkPrime(candidate[, options], callback)"], + generatePrimeSync: ["crypto.generatePrimeSync", 1, 2, "generatePrimeSync(size[, options])"], + generatePrime: ["crypto.generatePrimeCb", 1, 3, "generatePrime(size[, options], callback)"], + }; + const form = forms[member]; + if (!form) return null; + const [fn, min, max, supported] = form; + if (args.length < min || args.length > max || args.some(ts.isSpreadElement)) + lowerer.noLowering( + `crypto.${member} with ${args.length} arguments`, + expr, + `${supported} is supported`, + ); + const values = Array.from({ length: max }, (_, i) => dynArg(lowerer, args[i], loc)); + if (fn === "crypto.checkPrimeCb" || fn === "crypto.generatePrimeCb") { + const callback = args[args.length - 1]; + const nullError = callback !== undefined && !takesUndefinedError(lowerer, callback); + values.push({ kind: "boolLit", value: nullError, type: BOOL, loc }); + return { kind: "libCall", fn, args: values, type: VOID, loc }; + } + const call: IrExpr = { kind: "libCall", fn, args: values, type: DYN, loc }; + const result = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (result === null || result.kind === "dyn") return call; + return lowerer.coerceInto(expr, call, result); +} + /** The asymmetric-key and signature members (scr_pki.c): checked-dynamic * arguments, and the result converted to the call site's type * (KeyObject, Sign and Verify are checked-dynamic handles; key pairs, diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 0167adf12..cb16fd257 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1590,6 +1590,12 @@ export const BUILTIN_MODULE_FNS: Record< 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 }, + 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 @@ -3099,7 +3105,8 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record< ["getCipherInfo"].map((m) => [ m, "cipher metadata has no lowering — createCipheriv and createDecipheriv support " + - "aes-128/192/256 in cbc, ctr, and gcm modes and chacha20-poly1305", + "aes-128/192/256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1, and ofb modes, des-ede3 and " + + "des-ede, chacha20, and chacha20-poly1305", ]), ), setFips: diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 16db45b6c..e98ae0bd9 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -16,6 +16,12 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ // Node's prime, generator, size, encoding and group-name errors. "crypto.dhNew", "crypto.dhGroupNew", + // Node's candidate, size, options, add and rem errors, and OpenSSL's + // generation errors. + "crypto.checkPrimeSync", + "crypto.checkPrimeCb", + "crypto.generatePrimeSync", + "crypto.generatePrimeCb", // node:test's { timeout } and { concurrency } range checks. "test.register", "test.registerEmpty", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index fcdbe8694..edadaa244 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2820,6 +2820,16 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** 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 }, + "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 }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 5b984f318..ec2edb931 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -626,6 +626,16 @@ const rule = (r: RuntimeFeatureRule): RuntimeFeatureRule => r; /* The HTTP, HTTPS, HTTP/2 and TLS surfaces, which link the net unit. */ const NET_PREFIXES: readonly string[] = ["net.", "http.", "tls.", "https.", "http2."]; +/** The scr_dh.c entry points (the dh unit). */ +export const DH_LIB_FNS: ReadonlySet = new Set([ + "crypto.dhNew", + "crypto.dhGroupNew", + "crypto.checkPrimeSync", + "crypto.checkPrimeCb", + "crypto.generatePrimeSync", + "crypto.generatePrimeCb", +]); + /** The scr_pki.c entry points (the pki unit). */ export const PKI_LIB_FNS: ReadonlySet = new Set([ "crypto.createPrivateKey", @@ -820,9 +830,10 @@ const RUNTIME_FEATURE_RULES = { * process-warning unit, and unknown encodings and formats render through * the inspect unit. */ ecdh: rule({ fns: ["crypto.ecdhNew", "crypto.ecdhConvertKey"] }), - /** scr_dh.c over the mbedTLS archive; unknown encodings render through + /** scr_dh.c over the mbedTLS archive, also for checkPrime and + * generatePrime; unknown encodings and argument values render through * the inspect unit. */ - dh: rule({ fns: ["crypto.dhNew", "crypto.dhGroupNew"] }), + dh: rule({ fns: [...DH_LIB_FNS] }), emitter: rule({ initial: (mod) => mod.workers === true || (mod.classes ?? []).some((c) => c.name === RUNTIME_EMITTER_CLASS), @@ -872,8 +883,7 @@ const RUNTIME_FEATURE_RULES = { "webcrypto.unwrapKey", "crypto.ecdhNew", "crypto.ecdhConvertKey", - "crypto.dhNew", - "crypto.dhGroupNew", + ...DH_LIB_FNS, ...BUILTIN_CLASS_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS, ], diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index fb0575121..e8fad6dd1 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -54,6 +54,8 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [ ["crypto.ecdh", "crypto.createECDH and ECDH.convertKey"], ["crypto.dhNew", "crypto.createDiffieHellman"], ["crypto.dhGroupNew", "crypto.getDiffieHellman and createDiffieHellmanGroup"], + ["crypto.checkPrime", "crypto.checkPrime and checkPrimeSync"], + ["crypto.generatePrime", "crypto.generatePrime and generatePrimeSync"], ["crypto.createPrivateKey", "asymmetric KeyObjects, generateKeyPair, sign and verify"], ["crypto.createPublicKey", "asymmetric KeyObjects, generateKeyPair, sign and verify"], ["crypto.createSign", "asymmetric KeyObjects, generateKeyPair, sign and verify"], diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 45b3edbaa..d6eb69f6f 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -480,6 +480,18 @@ "status": "static", "note": "recognized module (bare and node:-prefixed specifiers)" }, + { + "id": "node-builtin.crypto.checkPrime", + "kind": "node-builtin", + "name": "crypto.checkPrime", + "status": "static" + }, + { + "id": "node-builtin.crypto.checkPrimeSync", + "kind": "node-builtin", + "name": "crypto.checkPrimeSync", + "status": "static" + }, { "id": "node-builtin.crypto.createCipheriv", "kind": "node-builtin", @@ -584,13 +596,25 @@ "name": "crypto.generateKeySync", "status": "static" }, + { + "id": "node-builtin.crypto.generatePrime", + "kind": "node-builtin", + "name": "crypto.generatePrime", + "status": "static" + }, + { + "id": "node-builtin.crypto.generatePrimeSync", + "kind": "node-builtin", + "name": "crypto.generatePrimeSync", + "status": "static" + }, { "id": "node-builtin.crypto.getCipherInfo", "kind": "node-builtin", "name": "crypto.getCipherInfo", "status": "unsupported", "code": "SC2020", - "note": "cipher metadata has no lowering — createCipheriv and createDecipheriv support aes-128/192/256 in cbc, ctr, and gcm modes and chacha20-poly1305" + "note": "cipher metadata has no lowering — createCipheriv and createDecipheriv support aes-128/192/256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1, and ofb modes, des-ede3 and des-ede, chacha20, and chacha20-poly1305" }, { "id": "node-builtin.crypto.getDiffieHellman", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7150-cipher-legacy-modes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7150-cipher-legacy-modes.ts.json new file mode 100644 index 000000000..c0e5f9812 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7150-cipher-legacy-modes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7150-cipher-legacy-modes.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7151-cipher-legacy-errors.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7151-cipher-legacy-errors.cjs.json new file mode 100644 index 000000000..1f37c6b64 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7151-cipher-legacy-errors.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7151-cipher-legacy-errors.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7152-crypto-prime.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7152-crypto-prime.ts.json new file mode 100644 index 000000000..722ebaacb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7152-crypto-prime.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7152-crypto-prime.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7153-crypto-prime-errors.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7153-crypto-prime-errors.cjs.json new file mode 100644 index 000000000..9d121895a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7153-crypto-prime-errors.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7153-crypto-prime-errors.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_cipher.c b/packages/runtime/src/scr_cipher.c index c8a10a731..00d229bad 100644 --- a/packages/runtime/src/scr_cipher.c +++ b/packages/runtime/src/scr_cipher.c @@ -20,16 +20,30 @@ #include "mbedtls/aes.h" #include "mbedtls/chacha20.h" +#include "mbedtls/des.h" #include "mbedtls/gcm.h" #include "mbedtls/poly1305.h" #include "mbedtls/platform_util.h" -typedef enum { SC_CBC, SC_CTR, SC_GCM, SC_CHACHA } ScCipherMode; +/* SC_CHACHA is chacha20-poly1305; SC_CHACHA20 the bare stream cipher. */ +typedef enum { + SC_CBC, + SC_CTR, + SC_GCM, + SC_CHACHA, + SC_ECB, + SC_CFB, + SC_CFB8, + SC_CFB1, + SC_OFB, + SC_CHACHA20, +} ScCipherMode; typedef struct { const char *name; ScCipherMode mode; unsigned key_len; + bool des; /* triple DES (two- or three-key) rather than AES */ } ScCipherSpec; /* Node's names for the implemented ciphers, including OpenSSL's aliases. @@ -41,6 +55,35 @@ static const ScCipherSpec sc_specs[] = { {"aes-128-gcm", SC_GCM, 16}, {"aes-192-gcm", SC_GCM, 24}, {"aes-256-gcm", SC_GCM, 32}, {"id-aes128-gcm", SC_GCM, 16}, {"id-aes192-gcm", SC_GCM, 24}, {"id-aes256-gcm", SC_GCM, 32}, {"chacha20-poly1305", SC_CHACHA, 32}, + {"aes-128-ecb", SC_ECB, 16}, {"aes-192-ecb", SC_ECB, 24}, {"aes-256-ecb", SC_ECB, 32}, + {"aes-128-cfb", SC_CFB, 16}, {"aes-192-cfb", SC_CFB, 24}, {"aes-256-cfb", SC_CFB, 32}, + {"aes-128-cfb8", SC_CFB8, 16}, {"aes-192-cfb8", SC_CFB8, 24}, {"aes-256-cfb8", SC_CFB8, 32}, + {"aes-128-cfb1", SC_CFB1, 16}, {"aes-192-cfb1", SC_CFB1, 24}, {"aes-256-cfb1", SC_CFB1, 32}, + {"aes-128-ofb", SC_OFB, 16}, {"aes-192-ofb", SC_OFB, 24}, {"aes-256-ofb", SC_OFB, 32}, + {"des-ede3-cbc", SC_CBC, 24, true}, {"des3", SC_CBC, 24, true}, + {"des-ede3", SC_ECB, 24, true}, {"des-ede3-ecb", SC_ECB, 24, true}, + {"des-ede3-cfb", SC_CFB, 24, true}, {"des-ede3-cfb8", SC_CFB8, 24, true}, + {"des-ede3-cfb1", SC_CFB1, 24, true}, {"des-ede3-ofb", SC_OFB, 24, true}, + {"des-ede-cbc", SC_CBC, 16, true}, {"des-ede", SC_ECB, 16, true}, + {"des-ede-ecb", SC_ECB, 16, true}, {"des-ede-cfb", SC_CFB, 16, true}, + {"des-ede-ofb", SC_OFB, 16, true}, + {"chacha20", SC_CHACHA20, 32}, +}; + +/* Ciphers OpenSSL 3 keeps in its legacy provider, which Node 24 does not + * load: crypto.getCipherInfo() knows them, and createCipheriv checks their + * IV length, then fails with OpenSSL's "unsupported" error. */ +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}, }; /* crypto.getCiphers() on Node 24.22 (OpenSSL 3.5). Names in this list that @@ -88,15 +131,21 @@ typedef struct ScCipher { ScCipherMode mode; bool decrypt; bool active; /* false after final() or a failed backend call */ - bool pad; /* CBC automatic padding */ + bool pad; /* CBC and ECB automatic padding */ + bool des; /* triple DES rather than AES */ + unsigned bs; /* the block size: 16 for AES, 8 for triple DES */ bool data_started; /* a non-empty update() ran, so non-empty AAD is refused */ int tag_len; /* SC_NO_TAG until known */ int tag_state; unsigned char tag[16]; - unsigned char block[16]; /* CBC: chaining value; CTR: counter block */ - unsigned char buf[16]; /* CBC: buffered input; CTR: keystream block */ - size_t bufsz; /* CBC: buffered bytes; CTR: keystream offset */ + unsigned char block[16]; /* CBC: chaining value; CTR: counter block; CFB, OFB: + shift register; chacha20: the IV */ + unsigned char buf[16]; /* CBC, ECB: buffered input; CTR: keystream block */ + size_t bufsz; /* CBC, ECB: buffered bytes; CTR, CFB, OFB: keystream + offset */ + uint64_t chacha_left; /* chacha20: bytes before the low counter word wraps */ mbedtls_aes_context aes; + mbedtls_des3_context des3; mbedtls_gcm_context gcm; mbedtls_chacha20_context chacha; mbedtls_poly1305_context poly; @@ -127,6 +176,7 @@ static void sc_trace(void *h, ScrTraceVisit visit, void *ctx) { static void sc_gcfree(void *h) { ScCipher *c = h; mbedtls_aes_free(&c->aes); + mbedtls_des3_free(&c->des3); mbedtls_gcm_free(&c->gcm); mbedtls_chacha20_free(&c->chacha); mbedtls_poly1305_free(&c->poly); @@ -184,18 +234,21 @@ static void sc_invalid_tag(unsigned long length) { /* An OpenSSL provider error as Node reports it: the formatted message plus * own opensslErrorStack, library, reason and code properties, in Node's * key order. */ -static void sc_throw_openssl(const char *packed, const char *reason, const char *code) { +/* OpenSSL's error with its library, reason and error stack; Node's + * code. */ +static void sc_throw_openssl_in(const char *packed, const char *library, const char *reason, + const char *code) { char message[128]; - snprintf(message, sizeof message, "error:%s:Provider routines::%s", packed, reason); + snprintf(message, sizeof message, "error:%s:%s::%s", packed, library, reason); ScrStr *text = scr_str_new(message, strlen(message)); ScrError *e = scr_error_new(SCR_ERR_ERROR, text); ScrDyn *stack = scr_dyn_new_arr(); scr_dyn_arr_push(stack, scr_dyn_new_str(text)); scr_str_release(text); scr_error_set_prop(e, "opensslErrorStack", 17, stack); - ScrStr *library = scr_str_new("Provider routines", 17); - scr_error_set_prop(e, "library", 7, scr_dyn_new_str(library)); - scr_str_release(library); + ScrStr *library_text = scr_str_new(library, strlen(library)); + scr_error_set_prop(e, "library", 7, scr_dyn_new_str(library_text)); + scr_str_release(library_text); ScrStr *reason_text = scr_str_new(reason, strlen(reason)); scr_error_set_prop(e, "reason", 6, scr_dyn_new_str(reason_text)); scr_str_release(reason_text); @@ -206,6 +259,10 @@ static void sc_throw_openssl(const char *packed, const char *reason, const char scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg()); } +static void sc_throw_openssl(const char *packed, const char *reason, const char *code) { + sc_throw_openssl_in(packed, "Provider routines", reason, code); +} + /* ERR_INVALID_ARG_VALUE's property flavor: "The property 'options.x' is * invalid. Received ". */ static void sc_invalid_property(const char *name, const ScrDyn *value) { @@ -440,6 +497,27 @@ static const ScCipherSpec *sc_lookup(const ScrStr *name) { return NULL; } +/* The legacy-provider IV length of `name`, or -1 for other names. */ +static int sc_legacy_iv(const ScrStr *name) { + for (size_t i = 0; i < sizeof sc_legacy / sizeof sc_legacy[0]; i++) + if (sc_ascii_eq_ci(name->data, name->len, sc_legacy[i].name)) return (int)sc_legacy[i].iv_len; + return -1; +} + +/* The IV length a mode takes; SC_GCM takes any nonzero length. */ +static size_t sc_iv_length(ScCipherMode mode, bool des) { + switch (mode) { + case SC_ECB: + return 0; + case SC_CHACHA: + return 12; + case SC_CHACHA20: + return 16; + default: + return des ? 8 : 16; + } +} + static bool sc_known_name(const ScrStr *name) { for (size_t i = 0; i < sizeof sc_known / sizeof sc_known[0]; i++) if (sc_ascii_eq_ci(name->data, name->len, sc_known[i])) return true; @@ -451,9 +529,10 @@ static void sc_unsupported_cipher(const ScrStr *name) { scr_jb_init(&b); scr_jb_puts(&b, "The cipher '"); scr_jb_put_str(&b, name); - scr_jb_puts(&b, "' has no native implementation; the supported ciphers are aes-128-cbc, aes-192-cbc, " - "aes-256-cbc, aes-128-ctr, aes-192-ctr, aes-256-ctr, aes-128-gcm, aes-192-gcm, " - "aes-256-gcm and chacha20-poly1305"); + scr_jb_puts(&b, "' has no native implementation; the supported ciphers are aes-128, aes-192 and " + "aes-256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1 and ofb modes, des-ede3 in cbc, ecb, " + "cfb, cfb8, cfb1 and ofb modes, des-ede in cbc, ecb, cfb and ofb modes, chacha20 and " + "chacha20-poly1305"); ScrStr *message = scr_jb_finish(&b); scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020"); scr_str_release(message); @@ -522,14 +601,24 @@ static ScrDyn *sc_cipher_new(bool decrypt, ScrDyn *cipher, ScrDyn *key, ScrDyn * goto done; } const ScCipherSpec *spec = sc_lookup(cipher->v.str); + size_t iv_len = iv_bytes ? iv_bytes->len : 0; if (!spec) { - if (sc_known_name(cipher->v.str)) sc_unsupported_cipher(cipher->v.str); - else sc_throw(SCR_ERR_ERROR, "ERR_CRYPTO_UNKNOWN_CIPHER", "Unknown cipher"); + int legacy_iv = sc_legacy_iv(cipher->v.str); + if (legacy_iv >= 0) { + if (iv_len != (size_t)legacy_iv || (legacy_iv > 0 && !iv_bytes)) + sc_throw(SCR_ERR_TYPE, "ERR_CRYPTO_INVALID_IV", "Invalid initialization vector"); + else + sc_throw_openssl_in("0308010C", "digital envelope routines", "unsupported", + "ERR_OSSL_EVP_UNSUPPORTED"); + } else if (sc_known_name(cipher->v.str)) { + sc_unsupported_cipher(cipher->v.str); + } else { + sc_throw(SCR_ERR_ERROR, "ERR_CRYPTO_UNKNOWN_CIPHER", "Unknown cipher"); + } goto done; } - size_t iv_len = iv_bytes ? iv_bytes->len : 0; - bool aead = spec->mode == SC_GCM || spec->mode == SC_CHACHA; - if (iv_len == 0 || (!aead && iv_len != 16) || (spec->mode == SC_CHACHA && iv_len != 12)) { + size_t expected_iv = sc_iv_length(spec->mode, spec->des); + if (spec->mode == SC_GCM ? iv_len == 0 : iv_len != expected_iv || (expected_iv > 0 && !iv_bytes)) { sc_throw(SCR_ERR_TYPE, "ERR_CRYPTO_INVALID_IV", "Invalid initialization vector"); goto done; } @@ -570,8 +659,11 @@ static ScrDyn *sc_cipher_new(bool decrypt, ScrDyn *cipher, ScrDyn *key, ScrDyn * c->decrypt = decrypt; c->active = true; c->pad = true; + c->des = spec->des; + c->bs = spec->des ? 8 : 16; c->tag_len = tag_len; mbedtls_aes_init(&c->aes); + mbedtls_des3_init(&c->des3); mbedtls_gcm_init(&c->gcm); mbedtls_chacha20_init(&c->chacha); mbedtls_poly1305_init(&c->poly); @@ -579,9 +671,39 @@ static ScrDyn *sc_cipher_new(bool decrypt, ScrDyn *cipher, ScrDyn *key, ScrDyn * unsigned bits = spec->key_len * 8; switch (spec->mode) { case SC_CBC: - rc = decrypt ? mbedtls_aes_setkey_dec(&c->aes, key_bytes->data, bits) - : mbedtls_aes_setkey_enc(&c->aes, key_bytes->data, bits); + case SC_ECB: + case SC_CFB: + case SC_CFB8: + case SC_CFB1: + case SC_OFB: { + /* CBC and ECB decrypt with the inverse cipher; the feedback modes run + * the forward cipher both ways. */ + bool inverse = decrypt && (spec->mode == SC_CBC || spec->mode == SC_ECB); + if (spec->des && spec->key_len == 24) + rc = inverse ? mbedtls_des3_set3key_dec(&c->des3, key_bytes->data) + : mbedtls_des3_set3key_enc(&c->des3, key_bytes->data); + else if (spec->des) + rc = inverse ? mbedtls_des3_set2key_dec(&c->des3, key_bytes->data) + : mbedtls_des3_set2key_enc(&c->des3, key_bytes->data); + else + rc = inverse ? mbedtls_aes_setkey_dec(&c->aes, key_bytes->data, bits) + : mbedtls_aes_setkey_enc(&c->aes, key_bytes->data, bits); + if (expected_iv) memcpy(c->block, iv_bytes->data, expected_iv); + break; + } + case SC_CHACHA20: + /* OpenSSL's IV is a 64-bit little-endian block counter and an 8-byte + * nonce; mbedTLS takes a 32-bit counter and a 12-byte nonce, so the + * stream restarts each time the low counter word wraps. */ memcpy(c->block, iv_bytes->data, 16); + rc = mbedtls_chacha20_setkey(&c->chacha, key_bytes->data); + if (rc == 0) { + uint32_t low = (uint32_t)c->block[0] | (uint32_t)c->block[1] << 8 | + (uint32_t)c->block[2] << 16 | (uint32_t)c->block[3] << 24; + c->chacha_left = ((uint64_t)1 << 32) - low; + c->chacha_left *= 64; + rc = mbedtls_chacha20_starts(&c->chacha, c->block + 4, low); + } break; case SC_CTR: rc = mbedtls_aes_setkey_enc(&c->aes, key_bytes->data, bits); @@ -635,39 +757,123 @@ done: /* ── the cipher transforms ────────────────────────────────────────────── */ -/* Raw CBC over whole blocks. */ +/* Raw CBC or ECB over whole blocks. */ static bool sc_cbc_blocks(ScCipher *c, const unsigned char *in, size_t len, unsigned char *out) { + if (c->mode == SC_ECB) { + for (size_t off = 0; off < len; off += c->bs) { + int rc = c->des ? mbedtls_des3_crypt_ecb(&c->des3, in + off, out + off) + : mbedtls_aes_crypt_ecb(&c->aes, c->decrypt ? MBEDTLS_AES_DECRYPT : MBEDTLS_AES_ENCRYPT, + in + off, out + off); + if (rc != 0) return false; + } + return true; + } + if (c->des) + return mbedtls_des3_crypt_cbc(&c->des3, c->decrypt ? MBEDTLS_DES_DECRYPT : MBEDTLS_DES_ENCRYPT, len, c->block, + in, out) == 0; return mbedtls_aes_crypt_cbc(&c->aes, c->decrypt ? MBEDTLS_AES_DECRYPT : MBEDTLS_AES_ENCRYPT, len, c->block, in, out) == 0; } -/* OpenSSL's ossl_cipher_generic_block_update for CBC: complete blocks - * are processed, the remainder is buffered, and a decryption that ends on - * a block boundary holds the last block back for padding removal. Returns - * the output length, or -1 when the backend fails; out has room for - * len + 16 bytes. */ +/* One forward block of the feedback modes' cipher. */ +static bool sc_forward(ScCipher *c, const unsigned char *in, unsigned char *out) { + return (c->des ? mbedtls_des3_crypt_ecb(&c->des3, in, out) + : mbedtls_aes_crypt_ecb(&c->aes, MBEDTLS_AES_ENCRYPT, in, out)) == 0; +} + +/* CFB (full-block feedback), CFB8, CFB1 and OFB, as OpenSSL's + * CRYPTO_cfb128_encrypt, CRYPTO_cfb128_8_encrypt, CRYPTO_cfb128_1_encrypt + * and CRYPTO_ofb128_encrypt: CFB and OFB keep their keystream offset across + * updates; CFB1 feeds back one bit at a time, most significant first. */ +static bool sc_feedback(ScCipher *c, const unsigned char *in, size_t len, unsigned char *out) { + unsigned char stream[16]; + size_t bs = c->bs; + for (size_t i = 0; i < len; i++) { + switch (c->mode) { + case SC_CFB: + case SC_OFB: + if (c->bufsz == 0 && !sc_forward(c, c->block, c->block)) return false; + out[i] = (unsigned char)(in[i] ^ c->block[c->bufsz]); + if (c->mode == SC_CFB) c->block[c->bufsz] = c->decrypt ? in[i] : out[i]; + c->bufsz = (c->bufsz + 1) % bs; + break; + case SC_CFB8: { + if (!sc_forward(c, c->block, stream)) return false; + unsigned char byte = (unsigned char)(in[i] ^ stream[0]); + memmove(c->block, c->block + 1, bs - 1); + c->block[bs - 1] = c->decrypt ? in[i] : byte; + out[i] = byte; + break; + } + default: { + unsigned char result = 0; + for (int bit = 7; bit >= 0; bit--) { + if (!sc_forward(c, c->block, stream)) return false; + unsigned in_bit = (in[i] >> bit) & 1u; + unsigned out_bit = in_bit ^ (stream[0] >> 7); + unsigned feed = c->decrypt ? in_bit : out_bit; + for (size_t k = 0; k + 1 < bs; k++) + c->block[k] = (unsigned char)(c->block[k] << 1 | c->block[k + 1] >> 7); + c->block[bs - 1] = (unsigned char)(c->block[bs - 1] << 1 | feed); + result |= (unsigned char)(out_bit << bit); + } + out[i] = result; + break; + } + } + } + mbedtls_platform_zeroize(stream, sizeof stream); + return true; +} + +/* chacha20 over len bytes: when the 64-bit counter's low word wraps, the + * high word steps (and wraps itself, as OpenSSL's does) and the stream + * restarts from block 0 of the next word. */ +static bool sc_chacha20_update(ScCipher *c, const unsigned char *in, size_t len, unsigned char *out) { + while (len > 0) { + size_t n = len < c->chacha_left ? len : (size_t)c->chacha_left; + if (mbedtls_chacha20_update(&c->chacha, n, in, out) != 0) return false; + in += n; + out += n; + len -= n; + c->chacha_left -= n; + if (c->chacha_left == 0) { + for (int k = 4; k < 8 && ++c->block[k] == 0; k++) { + } + memset(c->block, 0, 4); + c->chacha_left = (uint64_t)1 << 38; + if (mbedtls_chacha20_starts(&c->chacha, c->block + 4, 0) != 0) return false; + } + } + return true; +} + +/* OpenSSL's ossl_cipher_generic_block_update for CBC and ECB: complete + * blocks are processed, the remainder is buffered, and a decryption that + * ends on a block boundary holds the last block back for padding removal. + * Returns the output length, or -1 when the backend fails; out has room + * for len + 16 bytes. */ static long sc_cbc_update(ScCipher *c, const unsigned char *in, size_t inl, unsigned char *out) { + size_t bs = c->bs; size_t outl = 0; size_t nextblocks; if (c->bufsz != 0) { - size_t remain = 16 - c->bufsz; + size_t remain = bs - c->bufsz; if (inl < remain) remain = inl; memcpy(c->buf + c->bufsz, in, remain); in += remain; inl -= remain; c->bufsz += remain; - nextblocks = inl & ~(size_t)15; - } else { - nextblocks = inl & ~(size_t)15; } - if (c->bufsz == 16 && (!c->decrypt || inl > 0 || !c->pad)) { - if (!sc_cbc_blocks(c, c->buf, 16, out)) return -1; + nextblocks = inl - inl % bs; + if (c->bufsz == bs && (!c->decrypt || inl > 0 || !c->pad)) { + if (!sc_cbc_blocks(c, c->buf, bs, out)) return -1; c->bufsz = 0; - outl = 16; - out += 16; + outl = bs; + out += bs; } if (nextblocks > 0) { - if (c->decrypt && c->pad && nextblocks == inl) nextblocks -= 16; + if (c->decrypt && c->pad && nextblocks == inl) nextblocks -= bs; if (nextblocks > 0) { if (!sc_cbc_blocks(c, in, nextblocks, out)) return -1; outl += nextblocks; @@ -682,33 +888,35 @@ static long sc_cbc_update(ScCipher *c, const unsigned char *in, size_t inl, unsi return (long)outl; } -/* ossl_cipher_generic_block_final for CBC. Returns the output length, -1 - * after throwing OpenSSL's error, or -2 when the backend fails. */ +/* ossl_cipher_generic_block_final for CBC and ECB. Returns the output + * length, -1 after throwing OpenSSL's error, or -2 when the backend + * fails. */ static long sc_cbc_final(ScCipher *c, unsigned char out[16]) { + size_t bs = c->bs; if (!c->decrypt) { if (c->pad) { - unsigned char fill = (unsigned char)(16 - c->bufsz); - for (size_t i = c->bufsz; i < 16; i++) c->buf[i] = fill; + unsigned char fill = (unsigned char)(bs - c->bufsz); + for (size_t i = c->bufsz; i < bs; i++) c->buf[i] = fill; } else if (c->bufsz == 0) { return 0; - } else if (c->bufsz != 16) { + } else if (c->bufsz != bs) { sc_throw_openssl("1C80006B", "wrong final block length", "ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH"); return -1; } - if (!sc_cbc_blocks(c, c->buf, 16, out)) return -2; + if (!sc_cbc_blocks(c, c->buf, bs, out)) return -2; c->bufsz = 0; - return 16; + return (long)bs; } - if (c->bufsz != 16) { + if (c->bufsz != bs) { if (c->bufsz == 0 && !c->pad) return 0; sc_throw_openssl("1C80006B", "wrong final block length", "ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH"); return -1; } - if (!sc_cbc_blocks(c, c->buf, 16, c->buf)) return -2; - size_t len = 16; + if (!sc_cbc_blocks(c, c->buf, bs, c->buf)) return -2; + size_t len = bs; if (c->pad) { - unsigned char fill = c->buf[15]; - bool bad = fill == 0 || fill > 16; + unsigned char fill = c->buf[bs - 1]; + bool bad = fill == 0 || fill > bs; for (size_t i = 0; !bad && i < fill; i++) bad = c->buf[--len] != fill; if (bad) { sc_throw_openssl("1C800064", "bad decrypt", "ERR_OSSL_BAD_DECRYPT"); @@ -769,7 +977,8 @@ static ScrBytes *sc_transform(ScCipher *c, const unsigned char *in, size_t len) size_t produced = 0; bool ok = true; switch (c->mode) { - case SC_CBC: { + case SC_CBC: + case SC_ECB: { long n = sc_cbc_update(c, in, len, out->data); ok = n >= 0; produced = ok ? (size_t)n : 0; @@ -786,6 +995,17 @@ static ScrBytes *sc_transform(ScCipher *c, const unsigned char *in, size_t len) ok = len == 0 || sc_chacha_update(c, in, len, out->data); produced = len; break; + case SC_CFB: + case SC_CFB8: + case SC_CFB1: + case SC_OFB: + ok = sc_feedback(c, in, len, out->data); + produced = len; + break; + case SC_CHACHA20: + ok = len == 0 || sc_chacha20_update(c, in, len, out->data); + produced = len; + break; } if (!ok) { mbedtls_platform_zeroize(out->data, room); @@ -926,7 +1146,8 @@ static ScrBytes *sc_final_bytes(ScCipher *c) { out->len = 0; bool ok = true, backend = true; switch (c->mode) { - case SC_CBC: { + case SC_CBC: + case SC_ECB: { long produced = sc_cbc_final(c, out->data); if (produced == -1) { scr_bytes_release(out); @@ -937,6 +1158,11 @@ static ScrBytes *sc_final_bytes(ScCipher *c) { break; } case SC_CTR: + case SC_CFB: + case SC_CFB8: + case SC_CFB1: + case SC_OFB: + case SC_CHACHA20: break; case SC_GCM: { unsigned char full[16]; diff --git a/packages/runtime/src/scr_crypto.h b/packages/runtime/src/scr_crypto.h index 546e3d75b..0e6c6e07f 100644 --- a/packages/runtime/src/scr_crypto.h +++ b/packages/runtime/src/scr_crypto.h @@ -108,6 +108,14 @@ ScrDyn *scr_crypto_ecdh_convert_key(ScrDyn *key, ScrDyn *curve, ScrDyn *in_enc, * Node's error pending. */ ScrDyn *scr_crypto_dh_new(ScrDyn *size_or_key, ScrDyn *key_encoding, ScrDyn *generator, ScrDyn *generator_encoding); ScrDyn *scr_crypto_dh_group_new(ScrDyn *name); +/* crypto.checkPrimeSync, checkPrime, generatePrimeSync and generatePrime + * (scr_dh.c): checked-dynamic arguments, borrowed; the sync forms answer + * +1 or NULL with the error pending. The callbacks receive undefined as + * the error, as Node passes it, or null when `null_error`. */ +ScrDyn *scr_crypto_check_prime_sync(ScrDyn *candidate, ScrDyn *options); +void scr_crypto_check_prime_async(ScrDyn *candidate, ScrDyn *options, ScrDyn *callback, bool null_error); +ScrDyn *scr_crypto_generate_prime_sync(ScrDyn *size, ScrDyn *options); +void scr_crypto_generate_prime_async(ScrDyn *size, ScrDyn *options, ScrDyn *callback, bool null_error); ScrBytes *scr_crypto_pbkdf2(ScrBytes *password, ScrBytes *salt, double iterations, double keylen, ScrStr *digest); ScrBytes *scr_crypto_pbkdf2_job(ScrBytes *password, ScrBytes *salt, double iterations, diff --git a/packages/runtime/src/scr_dh.c b/packages/runtime/src/scr_dh.c index cf44338f5..dfa6fd2f3 100644 --- a/packages/runtime/src/scr_dh.c +++ b/packages/runtime/src/scr_dh.c @@ -183,17 +183,17 @@ static void sd_value_too_long(void) { scr_throw_error_msg_code(SCR_ERR_ERROR, message, n < 0 ? 0 : (size_t)n, "SC2020"); } -/* validateInt32(value, name). */ -static bool sd_validate_int32(const char *name, double value) { +/* validateInt32(value, name, min). */ +static bool sd_validate_int32_min(const char *name, double value, int32_t min) { bool integer = isfinite(value) && trunc(value) == value; - if (integer && value >= INT32_MIN && value <= INT32_MAX) return true; + if (integer && value >= min && value <= INT32_MAX) return true; char received[48]; scr_num_received(value, received); char text[192]; int n = integer ? snprintf(text, sizeof text, - "The value of \"%s\" is out of range. It must be >= -2147483648 && <= 2147483647. " + "The value of \"%s\" is out of range. It must be >= %ld && <= 2147483647. " "Received %s", - name, received) + name, (long)min, received) : snprintf(text, sizeof text, "The value of \"%s\" is out of range. It must be an integer. Received %s", name, received); @@ -201,6 +201,11 @@ static bool sd_validate_int32(const char *name, double value) { return false; } +/* validateInt32(value, name). */ +static bool sd_validate_int32(const char *name, double value) { + return sd_validate_int32_min(name, value, INT32_MIN); +} + /* ── arithmetic ───────────────────────────────────────────────────────── */ /* The exponent digit width that keeps every mbedtls_mpi_exp_mod exponent @@ -630,9 +635,9 @@ static int sd_mr_rounds(size_t bits) { return bits > 2048 ? 128 : 64; } -/* BN_check_prime: trial division by the small primes, then Miller-Rabin - * rounds with random bases. */ -static bool sd_is_prime(ScDhSmallPrimes *t, const mbedtls_mpi *x) { +/* BN_is_prime_ex(x, checks): trial division by the small primes, then + * Miller-Rabin rounds with random bases, at least OpenSSL's round count. */ +static bool sd_is_prime_checks(ScDhSmallPrimes *t, const mbedtls_mpi *x, int checks) { if (mbedtls_mpi_cmp_int(x, 2) < 0) return false; if (mbedtls_mpi_get_bit(x, 0) == 0) return mbedtls_mpi_cmp_int(x, 2) == 0; if (!sd_small_residues(t, x)) return false; @@ -643,11 +648,17 @@ static bool sd_is_prime(ScDhSmallPrimes *t, const mbedtls_mpi *x) { ScDhMillerRabin m; bool prime = sd_mr_init(&m, x); int rounds = sd_mr_rounds(mbedtls_mpi_bitlen(x)); + if (checks > rounds) rounds = checks; for (int i = 0; i < rounds && prime; i++) prime = sd_mr_round(&m, x, false) == 1; sd_mr_free(&m); return prime; } +/* BN_check_prime. */ +static bool sd_is_prime(ScDhSmallPrimes *t, const mbedtls_mpi *x) { + return sd_is_prime_checks(t, x, 0); +} + /* DH_check for parameters without q, as ncrypto's CheckDhParams reports * it. */ static int sd_check_params(const mbedtls_mpi *p, const mbedtls_mpi *g) { @@ -793,8 +804,9 @@ static void sd_sieve_window(ScDhSieve *sv, unsigned add) { * when p is a strong probable prime to the base 2 and q = (p - 1) / 2 * passes OpenSSL's Miller-Rabin round count; a prime q then proves p prime * (Pocklington's criterion with 2^(p-1) ≡ 1 and gcd(2^2 - 1, p) = 1). - * Candidates past `bits` bits take a new start. */ -static bool sd_generate_safe_prime(mbedtls_mpi *p, size_t bits, unsigned add, unsigned rem) { + * Candidates past `bits` bits take a new start. With `top_two`, starts + * also set the second-highest bit, as BN_RAND_TOP_TWO does. */ +static bool sd_generate_safe_prime(mbedtls_mpi *p, size_t bits, unsigned add, unsigned rem, bool top_two) { ScDhSieve *sv = sd_sieve_new(bits, add); int rounds = sd_mr_rounds(bits); mbedtls_mpi start, q; @@ -803,7 +815,8 @@ static bool sd_generate_safe_prime(mbedtls_mpi *p, size_t bits, unsigned add, un int ret = 0; while (ret == 0) { mbedtls_mpi_uint r; - if (!sd_random_bits(&start, bits, true) || mbedtls_mpi_mod_int(&r, &start, add) != 0 || + if (!sd_random_bits(&start, bits, true) || (top_two && mbedtls_mpi_set_bit(&start, bits - 2, 1) != 0) || + mbedtls_mpi_mod_int(&r, &start, add) != 0 || mbedtls_mpi_sub_int(&start, &start, (mbedtls_mpi_sint)r) != 0 || mbedtls_mpi_add_int(&start, &start, rem) != 0 || (mbedtls_mpi_bitlen(&start) < bits && mbedtls_mpi_add_int(&start, &start, add) != 0)) { @@ -900,7 +913,7 @@ static ScrDyn *sd_generate(double bits, const ScrBytes *generator_bytes, double if (generator == 2) add = 24; else if (generator == 5) add = 60; ScDh *d = sd_alloc(); - if (!sd_generate_safe_prime(&d->p, (size_t)bits, add, add - 1) || mbedtls_mpi_lset(&d->g, (mbedtls_mpi_sint)generator) != 0) { + if (!sd_generate_safe_prime(&d->p, (size_t)bits, add, add - 1, false) || mbedtls_mpi_lset(&d->g, (mbedtls_mpi_sint)generator) != 0) { sd_release(d); sd_throw(SCR_ERR_TYPE, "ERR_INVALID_ARG_VALUE", "Invalid DH parameters"); return NULL; @@ -1034,6 +1047,505 @@ ScrDyn *scr_crypto_dh_group_new(ScrDyn *name) { return sd_box(d); } +/* ── checkPrime and generatePrime ───────────────────────────────────────── + * crypto.checkPrime(Sync) and generatePrime(Sync) over the primality test + * and prime search above, with random.js's argument checks and ncrypto's + * RandomPrimeConfig and BN_generate_prime_ex2 errors. The callback forms + * compute at once and call back in a later macrotask. */ + +/* The longest candidate the Miller-Rabin rounds take: sd_mont_init's R^2 + * has twice the candidate's limbs, within MBEDTLS_MPI_MAX_LIMBS, and + * mbedtls_mpi_exp_mod stops at MBEDTLS_MPI_MAX_BITS. */ +#if SD_MONT +#define SD_MAX_PRIME_BITS 262144 +#else +#define SD_MAX_PRIME_BITS MBEDTLS_MPI_MAX_BITS +#endif + +static void sd_prime_too_long(const char *what) { + char message[128]; + int n = snprintf(message, sizeof message, "%s longer than %d bits have no native implementation", what, + SD_MAX_PRIME_BITS); + scr_throw_error_msg_code(SCR_ERR_ERROR, message, n < 0 ? 0 : (size_t)n, "SC2020"); +} + +/* An OpenSSL bignum error as a crypto job reports it: an Error with the + * formatted message and no other properties. */ +static void sd_throw_bignum(const char *packed, const char *reason) { + char message[96]; + int n = snprintf(message, sizeof message, "error:%s:bignum routines::%s", packed, reason); + ScrStr *text = scr_str_new(message, n < 0 ? 0 : (size_t)n); + ScrError *e = scr_error_new(SCR_ERR_ERROR, text); + scr_str_release(text); + scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg()); +} + +/* validateObject(value, name): an object that is neither null nor an + * array. */ +static bool sd_validate_object(const char *name, const ScrDyn *value) { + ScrStr *type = scr_dyn_typeof(value); + bool object = type->len == 6 && memcmp(type->data, "object", 6) == 0; + scr_str_release(type); + if (object && value->kind != SCR_DYN_NULL && value->kind != SCR_DYN_ARR) return true; + scr_dyn_arg_type_fail(name, "of type object", value); + return false; +} + +static bool sd_validate_function(const char *name, const ScrDyn *value) { + if (scr_dyn_is_callable(value)) return true; + scr_dyn_arg_type_fail(name, "of type function", value); + return false; +} + +/* options[key] (borrowed), or undefined. */ +static const ScrDyn *sd_option(const ScrDyn *options, const char *key) { + const ScrDyn *value = options->kind == SCR_DYN_OBJ ? scr_dyn_obj_get(options, key, strlen(key)) : NULL; + return value ? value : scr_dyn_undefined(); +} + +static const char sd_large_number_types[] = + "of type bigint or an instance of ArrayBuffer, TypedArray, Buffer, or DataView"; + +/* A LargeNumberLike argument as a bignum: a bigint (unsignedBigIntToBuffer, + * which rejects negative values), or the bytes of an ArrayBuffer or view. + * False with the error pending. */ +static bool sd_large_number(mbedtls_mpi *x, const char *name, bool property, const ScrDyn *value) { + if (value->kind == SCR_DYN_BIGINT) { + ScrStr *text = scr_bigint_to_string(value->v.bigint, 16); + if (!text) return false; + bool negative = text->len > 0 && text->data[0] == '-'; + if (negative) { + scr_str_release(text); + ScrStr *decimal = scr_bigint_to_string(value->v.bigint, 10); + if (!decimal) return false; + /* ERR_OUT_OF_RANGE's received value groups the digits of a bigint + * past 2^32 in threes. */ + ScrBigInt *limit = scr_bigint_from_i64(-((int64_t)1 << 32)); + bool group = scr_bigint_cmp_f64(value->v.bigint, limit) < 0; + scr_bigint_release(limit); + char digits[160]; + size_t len = decimal->len < 120 ? decimal->len : 120, out = 0; + for (size_t i = 0; i < len; i++) { + size_t rest = len - i; + if (group && i > 1 && rest % 3 == 0) digits[out++] = '_'; + digits[out++] = decimal->data[i]; + } + digits[out] = '\0'; + scr_str_release(decimal); + char message[256]; + int n = snprintf(message, sizeof message, "The value of \"%s\" is out of range. It must be >= 0. Received %sn", + name, digits); + scr_throw_error_msg_code(SCR_ERR_RANGE, message, n < 0 ? 0 : (size_t)n, "ERR_OUT_OF_RANGE"); + return false; + } + char *hex = malloc(text->len + 1); + if (!hex) scr_trap("scriptc: out of memory\n"); + memcpy(hex, text->data, text->len); + hex[text->len] = '\0'; + scr_str_release(text); + bool ok = strlen(hex) <= SD_MAX_VALUE_BYTES * 2; + if (ok && mbedtls_mpi_read_string(x, 16, hex) != 0) scr_trap("scriptc: out of memory\n"); + free(hex); + if (!ok) sd_value_too_long(); + return ok; + } + if (!sd_is_view(value)) { + if (property) scr_dyn_prop_type_fail(name, sd_large_number_types, value); + else scr_dyn_arg_type_fail(name, sd_large_number_types, value); + return false; + } + ScrBytes *bytes = scr_bytes_buffer_source(value); + if (!bytes) return false; + bool held = sd_read(x, bytes); + scr_bytes_release(bytes); + if (!held) sd_value_too_long(); + return held; +} + +/* calc_trial_divisions: how many of the first primes (2 included) the + * search divides a candidate of `bits` bits by. */ +static size_t sd_trial_divisions(size_t bits) { + return bits <= 512 ? 64 : bits <= 1024 ? 128 : bits <= 2048 ? 384 : bits <= 4096 ? 1024 : 2048; +} + +static uint64_t sd_word(const mbedtls_mpi *x) { + if (mbedtls_mpi_bitlen(x) > 64) return UINT64_MAX; + unsigned char buf[8]; + if (mbedtls_mpi_write_binary(x, buf, 8) != 0) return UINT64_MAX; + uint64_t w = 0; + for (int i = 0; i < 8; i++) w = w << 8 | buf[i]; + return w; +} + +static bool sd_add_word(mbedtls_mpi *x, uint64_t w) { + unsigned char buf[8]; + for (int i = 7; i >= 0; i--, w >>= 8) buf[i] = (unsigned char)w; + mbedtls_mpi t; + mbedtls_mpi_init(&t); + bool ok = mbedtls_mpi_read_binary(&t, buf, 8) == 0 && mbedtls_mpi_add_mpi(x, x, &t) == 0; + mbedtls_mpi_free(&t); + return ok; +} + +/* probable_prime and bn_probable_prime_dh: a random odd candidate of + * `bits` bits (the top two bits set, or with `add` the top bit, moved to + * rem modulo add), then the first one stepping by 2, by 4 for a safe + * prime, or by add, that no trial-division prime divides, nor for a safe + * prime divides (p - 1) / 2. */ +static bool sd_probable_prime(ScDhSmallPrimes *t, mbedtls_mpi *rnd, size_t bits, bool safe, const mbedtls_mpi *add, + const mbedtls_mpi *rem) { + size_t trials = sd_trial_divisions(bits) - 1; /* odd primes */ + uint64_t step = safe ? 4 : 2; + uint64_t maxdelta = UINT64_MAX - t->primes[trials - 1]; + if (add) { + step = sd_word(add); + if (maxdelta > UINT64_MAX - step) maxdelta = UINT64_MAX - step; + } + mbedtls_mpi r; + mbedtls_mpi_init(&r); + bool ok = true; + for (;;) { + if (!sd_random_bits(rnd, bits, true)) ok = false; + if (ok && !add) { + if ((bits >= 2 && mbedtls_mpi_set_bit(rnd, bits - 2, 1) != 0) || (safe && mbedtls_mpi_set_bit(rnd, 1, 1) != 0)) + ok = false; + } else if (ok) { + ok = mbedtls_mpi_mod_mpi(&r, rnd, add) == 0 && mbedtls_mpi_sub_mpi(rnd, rnd, &r) == 0 && + (rem ? mbedtls_mpi_add_mpi(rnd, rnd, rem) == 0 : mbedtls_mpi_add_int(rnd, rnd, safe ? 3 : 1) == 0); + if (ok && (mbedtls_mpi_bitlen(rnd) < bits || sd_word(rnd) < (safe ? 5u : 3u))) + ok = mbedtls_mpi_add_mpi(rnd, rnd, add) == 0; + } + if (!ok || !sd_small_residues(t, rnd)) { + ok = false; + break; + } + uint64_t delta = 0, word = sd_word(rnd); + bool again = false; + for (size_t i = 0; i < trials && !again;) { + uint64_t prime = t->primes[i]; + /* A one-word candidate needs only the primes up to its square root. */ + if (bits <= 31 && delta <= 0x7fffffff && prime * prime > word + delta) break; + uint64_t m = (t->mods[i] + delta) % prime; + if (safe ? m <= 1 : m == 0) { + delta += step; + if (delta > maxdelta) again = true; + i = 0; + continue; + } + i++; + } + if (again) continue; + if (!sd_add_word(rnd, delta)) { + ok = false; + break; + } + if (add || mbedtls_mpi_bitlen(rnd) == bits) break; + } + mbedtls_mpi_free(&r); + return ok; +} + +/* BN_generate_prime_ex2(p, bits, safe, add, rem): false with OpenSSL's + * error pending. Long safe primes without add take the sieve over + * p ≡ 11 (mod 12), which every safe prime above 7 satisfies. */ +static bool sd_generate_prime(mbedtls_mpi *p, size_t bits, bool safe, const mbedtls_mpi *add, const mbedtls_mpi *rem) { + if (bits < 2 || (!add && safe && bits < 6 && bits != 3)) { + sd_throw_bignum("01800076", "bits too small"); + return false; + } + if (add && mbedtls_mpi_cmp_int(add, 0) == 0) { + sd_throw_bignum("01800067", "div by zero"); + return false; + } + if (!add && safe && bits >= 64) { + if (!sd_generate_safe_prime(p, bits, 12, 11, true)) scr_trap("scriptc: out of memory\n"); + return true; + } + ScDhSmallPrimes *t = sd_small_primes(); + mbedtls_mpi q; + mbedtls_mpi_init(&q); + bool found = false; + while (!found) { + if (!sd_probable_prime(t, p, bits, safe, add, rem)) scr_trap("scriptc: out of memory\n"); + if (!safe) { + found = sd_is_prime(t, p); + } else { + if (mbedtls_mpi_copy(&q, p) != 0 || mbedtls_mpi_shift_r(&q, 1) != 0) scr_trap("scriptc: out of memory\n"); + found = sd_is_prime(t, p) && sd_is_prime(t, &q); + } + } + mbedtls_mpi_free(&q); + free(t); + return true; +} + +/* checkPrime's arguments after the candidate: Node's options and checks + * rules. -1 with the error pending. */ +static int sd_prime_checks(const ScrDyn *options) { + if (!sd_validate_object("options", options)) return -1; + const ScrDyn *checks = sd_option(options, "checks"); + if (checks->kind == SCR_DYN_UNDEF) return 0; + if (checks->kind != SCR_DYN_NUM) { + scr_dyn_prop_type_fail("options.checks", "of type number", checks); + return -1; + } + if (!sd_validate_int32_min("options.checks", checks->v.num, 0)) return -1; + return (int)checks->v.num; +} + +/* The candidate's verdict as a boolean dyn (+1), or NULL with the error + * pending. */ +static ScrDyn *sd_check_prime(const mbedtls_mpi *candidate, int checks) { + if (mbedtls_mpi_bitlen(candidate) > SD_MAX_PRIME_BITS) { + sd_prime_too_long("checkPrime candidates"); + return NULL; + } + ScDhSmallPrimes *t = sd_small_primes(); + bool prime = sd_is_prime_checks(t, candidate, checks); + free(t); + return scr_dyn_new_bool(prime); +} + +/* A borrowed, unboxed view of each argument (+1 each); false after a + * throw. */ +static bool sd_unbox_all(ScrDyn **out, ScrDyn *const *args, size_t count) { + for (size_t i = 0; i < count; i++) out[i] = NULL; + for (size_t i = 0; i < count; i++) { + ScrDyn *value = args[i]; + out[i] = value->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_materialize(value) : scr_dyn_retain(value); + if (!out[i]) return false; + } + return true; +} + +static void sd_release_all(ScrDyn **values, size_t count) { + for (size_t i = 0; i < count; i++) + if (values[i]) scr_dyn_release(values[i]); +} + +/* checkPrimeSync(candidate[, options]). */ +ScrDyn *scr_crypto_check_prime_sync(ScrDyn *candidate, ScrDyn *options) { + ScrDyn *args[2] = {candidate, options}; + ScrDyn *v[2]; + ScrDyn *result = NULL; + mbedtls_mpi x; + mbedtls_mpi_init(&x); + if (sd_unbox_all(v, args, 2) && sd_large_number(&x, "candidate", false, v[0])) { + ScrDyn *empty = v[1]->kind == SCR_DYN_UNDEF ? scr_dyn_new_obj() : NULL; + int checks = sd_prime_checks(empty ? empty : v[1]); + if (empty) scr_dyn_release(empty); + if (checks >= 0) result = sd_check_prime(&x, checks); + } + mbedtls_mpi_free(&x); + sd_release_all(v, 2); + return result; +} + +/* A deferred callback(...args): the callback and its one or two + * arguments, each in a box. */ +static void sd_deliver(ScrClosure *self) { + ScrDyn *callback = (ScrDyn *)scr_box_get_ref(self->caps[0]); + size_t argc = self->ncaps - 1; + ScrDyn *args[2] = {NULL, NULL}; + for (size_t i = 0; i < argc; i++) args[i] = (ScrDyn *)scr_box_get_ref(self->caps[i + 1]); + ScrDyn *result = scr_dyn_call(callback, args, argc, "callback"); + if (result) scr_dyn_release(result); + for (size_t i = 0; i < argc; i++) scr_dyn_release(args[i]); + scr_dyn_release(callback); +} + +/* Calls callback(first[, second]) in a later macrotask (moves first and + * second). */ +static void sd_defer(const ScrDyn *callback, ScrDyn *first, ScrDyn *second) { + ScrDyn *values[3] = {scr_dyn_retain((ScrDyn *)callback), first, second}; + size_t count = second ? 3 : 2; + ScrClosure *c = scr_closure_new((void *)sd_deliver, count); + for (size_t i = 0; i < count; i++) { + c->caps[i] = scr_box_new_obj(scr_dyn_retain_v, scr_dyn_release_v, NULL); + scr_box_set_ref(c->caps[i], values[i]); + } + scr_loop_defer(c); +} + +/* The callback's error argument on success (+1): Node's undefined, or + * null for a callback typed to take Error | null. */ +static ScrDyn *sd_no_error(bool null_error) { + return null_error ? scr_dyn_new_null() : scr_dyn_retain((ScrDyn *)scr_dyn_undefined()); +} + +/* The pending error, taken as a dyn value (+1). */ +static ScrDyn *sd_take_error(void) { + ScrCaught *caught = scr_exc_take(); + ScrDyn *error = scr_caught_to_dyn(caught); + scr_caught_release(caught); + return error; +} + +/* checkPrime(candidate[, options], callback): argument errors throw; the + * callback receives (undefined, verdict) in a later macrotask (null for + * undefined when `null_error`). */ +void scr_crypto_check_prime_async(ScrDyn *candidate, ScrDyn *options, ScrDyn *callback, bool null_error) { + ScrDyn *args[3] = {candidate, options, callback}; + ScrDyn *v[3]; + mbedtls_mpi x; + mbedtls_mpi_init(&x); + if (sd_unbox_all(v, args, 3) && sd_large_number(&x, "candidate", false, v[0])) { + ScrDyn *bag = v[1], *fn = v[2]; + ScrDyn *empty = NULL; + if (scr_dyn_is_callable(bag)) { + fn = bag; + bag = empty = scr_dyn_new_obj(); + } else if (bag->kind == SCR_DYN_UNDEF) { + bag = empty = scr_dyn_new_obj(); + } + int checks = sd_validate_function("callback", fn) ? sd_prime_checks(bag) : -1; + ScrDyn *verdict = checks >= 0 ? sd_check_prime(&x, checks) : NULL; + if (verdict) sd_defer(fn, sd_no_error(null_error), verdict); + if (empty) scr_dyn_release(empty); + } + mbedtls_mpi_free(&x); + sd_release_all(v, 3); +} + +/* RandomPrimeConfig: the size and options checks, then the add and rem + * bounds. False with the error pending. */ +typedef struct { + size_t bits; + bool safe, bigint, has_add, has_rem; + mbedtls_mpi add, rem; +} ScDhPrimeConfig; + +static void sd_prime_config_free(ScDhPrimeConfig *c) { + mbedtls_mpi_free(&c->add); + mbedtls_mpi_free(&c->rem); +} + +static bool sd_prime_size(const ScrDyn *size) { + if (size->kind != SCR_DYN_NUM) { + scr_dyn_arg_type_fail("size", "of type number", size); + return false; + } + return sd_validate_int32_min("size", size->v.num, 1); +} + +static bool sd_prime_config(ScDhPrimeConfig *c, double size, const ScrDyn *options) { + if (!sd_validate_object("options", options)) return false; + const ScrDyn *safe = sd_option(options, "safe"); + const ScrDyn *bigint = sd_option(options, "bigint"); + const ScrDyn *add = sd_option(options, "add"); + const ScrDyn *rem = sd_option(options, "rem"); + if (safe->kind != SCR_DYN_UNDEF && safe->kind != SCR_DYN_BOOL) { + scr_dyn_prop_type_fail("options.safe", "of type boolean", safe); + return false; + } + if (bigint->kind != SCR_DYN_UNDEF && bigint->kind != SCR_DYN_BOOL) { + scr_dyn_prop_type_fail("options.bigint", "of type boolean", bigint); + return false; + } + c->safe = safe->kind == SCR_DYN_BOOL && safe->v.b; + c->bigint = bigint->kind == SCR_DYN_BOOL && bigint->v.b; + c->has_add = add->kind != SCR_DYN_UNDEF; + c->has_rem = rem->kind != SCR_DYN_UNDEF; + if (c->has_add && !sd_large_number(&c->add, "options.add", true, add)) return false; + if (c->has_rem && !sd_large_number(&c->rem, "options.rem", true, rem)) return false; + c->bits = (size_t)size; + if (c->has_add) { + if (mbedtls_mpi_bitlen(&c->add) > c->bits) { + sd_throw(SCR_ERR_RANGE, "ERR_OUT_OF_RANGE", "invalid options.add"); + return false; + } + if (c->has_rem && mbedtls_mpi_cmp_mpi(&c->add, &c->rem) <= 0) { + sd_throw(SCR_ERR_RANGE, "ERR_OUT_OF_RANGE", "invalid options.rem"); + return false; + } + } + if (c->bits > SD_MAX_PRIME_BITS) { + sd_prime_too_long("generatePrime sizes"); + return false; + } + return true; +} + +/* The generated prime as an ArrayBuffer of its bytes, or a bigint (+1), + * or NULL with OpenSSL's error pending. */ +static ScrDyn *sd_prime_result(ScDhPrimeConfig *c) { + mbedtls_mpi p; + mbedtls_mpi_init(&p); + ScrDyn *result = NULL; + if (sd_generate_prime(&p, c->bits, c->safe, c->has_add ? &c->add : NULL, c->has_add && c->has_rem ? &c->rem : NULL)) { + if (c->bigint) { + size_t len = 0; + mbedtls_mpi_write_string(&p, 16, NULL, 0, &len); + char *hex = malloc(len + 2); + if (!hex) scr_trap("scriptc: out of memory\n"); + hex[0] = '0'; + hex[1] = 'x'; + if (mbedtls_mpi_write_string(&p, 16, hex + 2, len, &len) != 0) scr_trap("scriptc: out of memory\n"); + ScrStr *text = scr_str_new(hex, strlen(hex)); + free(hex); + ScrBigInt *value = scr_bigint_parse(text); + scr_str_release(text); + if (value) { + result = scr_dyn_new_bigint(value); + scr_bigint_release(value); + } + } else { + size_t len = mbedtls_mpi_size(&p); + ScrBytes *bytes = scr_bytes_new(SCR_BYTES_U8, (double)len); + if (mbedtls_mpi_write_binary(&p, bytes->data, len) != 0) scr_trap("scriptc: out of memory\n"); + result = scr_array_buffer_from_bytes(bytes); + scr_bytes_release(bytes); + } + } + mbedtls_mpi_free(&p); + return result; +} + +/* generatePrimeSync(size[, options]). */ +ScrDyn *scr_crypto_generate_prime_sync(ScrDyn *size, ScrDyn *options) { + ScrDyn *args[2] = {size, options}; + ScrDyn *v[2]; + ScrDyn *result = NULL; + ScDhPrimeConfig c = {0}; + mbedtls_mpi_init(&c.add); + mbedtls_mpi_init(&c.rem); + if (sd_unbox_all(v, args, 2) && sd_prime_size(v[0])) { + ScrDyn *empty = v[1]->kind == SCR_DYN_UNDEF ? scr_dyn_new_obj() : NULL; + if (sd_prime_config(&c, v[0]->v.num, empty ? empty : v[1])) result = sd_prime_result(&c); + if (empty) scr_dyn_release(empty); + } + sd_prime_config_free(&c); + sd_release_all(v, 2); + return result; +} + +/* generatePrime(size[, options], callback): argument errors throw; the + * callback receives (undefined, prime), or OpenSSL's error alone, in a + * later macrotask (null for undefined when `null_error`). */ +void scr_crypto_generate_prime_async(ScrDyn *size, ScrDyn *options, ScrDyn *callback, bool null_error) { + ScrDyn *args[3] = {size, options, callback}; + ScrDyn *v[3]; + ScDhPrimeConfig c = {0}; + mbedtls_mpi_init(&c.add); + mbedtls_mpi_init(&c.rem); + if (sd_unbox_all(v, args, 3) && sd_prime_size(v[0])) { + ScrDyn *bag = v[1], *fn = v[2]; + ScrDyn *empty = NULL; + if (scr_dyn_is_callable(bag)) { + fn = bag; + bag = empty = scr_dyn_new_obj(); + } + if (sd_validate_function("callback", fn) && sd_prime_config(&c, v[0]->v.num, bag)) { + ScrDyn *prime = sd_prime_result(&c); + if (prime) sd_defer(fn, sd_no_error(null_error), prime); + else sd_defer(fn, sd_take_error(), NULL); + } + if (empty) scr_dyn_release(empty); + } + sd_prime_config_free(&c); + sd_release_all(v, 3); +} + /* ── methods ──────────────────────────────────────────────────────────── */ static ScrDyn *sd_arg(ScrDyn *const *args, size_t argc, size_t index) { diff --git a/tests/corpus/7150-cipher-legacy-modes.ts b/tests/corpus/7150-cipher-legacy-modes.ts new file mode 100644 index 000000000..80edfd029 --- /dev/null +++ b/tests/corpus/7150-cipher-legacy-modes.ts @@ -0,0 +1,74 @@ +// createCipheriv and createDecipheriv in the legacy modes: AES in ECB, +// CFB, CFB8, CFB1 and OFB, triple DES (three- and two-key) in CBC, ECB, +// CFB, CFB8, CFB1 and OFB, and bare chacha20. Fixed keys, IVs and inputs +// give Node's exact ciphertexts; chunked updates, string encodings, +// disabled padding and chacha20's 64-bit counter carry round-trip. +import { createCipheriv, createDecipheriv } from "node:crypto"; + +function bytes(length: number, seed: number): Buffer { + const out = Buffer.alloc(length); + for (let i = 0; i < length; i++) out[i] = (i * 29 + seed) & 0xff; + return out; +} + +const plaintext = Buffer.from("The five boxing wizards jump quickly; sphinx of black quartz, judge my vow."); + +function encrypt(name: string, key: Buffer, iv: Buffer | null, data: Buffer, chunk: number): Buffer { + const cipher = createCipheriv(name, key, iv); + const parts: Buffer[] = []; + for (let off = 0; off < data.length; off += chunk) parts.push(cipher.update(data.subarray(off, off + chunk))); + parts.push(cipher.final()); + return Buffer.concat(parts); +} + +function decrypt(name: string, key: Buffer, iv: Buffer | null, data: Buffer, chunk: number): Buffer { + const decipher = createDecipheriv(name, key, iv); + const parts: Buffer[] = []; + for (let off = 0; off < data.length; off += chunk) parts.push(decipher.update(data.subarray(off, off + chunk))); + parts.push(decipher.final()); + return Buffer.concat(parts); +} + +const cases: [string, number, number][] = []; +for (const bits of [128, 192, 256]) + for (const mode of ["ecb", "cfb", "cfb8", "cfb1", "ofb"]) cases.push([`aes-${bits}-${mode}`, bits / 8, mode === "ecb" ? 0 : 16]); +for (const name of ["des-ede3-cbc", "des3", "des-ede3", "des-ede3-ecb", "des-ede3-cfb", "des-ede3-cfb8", "des-ede3-cfb1", "des-ede3-ofb"]) + cases.push([name, 24, name === "des-ede3" || name === "des-ede3-ecb" ? 0 : 8]); +for (const name of ["des-ede-cbc", "des-ede", "des-ede-ecb", "des-ede-cfb", "des-ede-ofb"]) + cases.push([name, 16, name === "des-ede" || name === "des-ede-ecb" ? 0 : 8]); +cases.push(["chacha20", 32, 16]); + +for (const [name, keyLength, ivLength] of cases) { + const key = bytes(keyLength, keyLength + 3); + const iv = ivLength ? bytes(ivLength, 11) : null; + const sealed = encrypt(name, key, iv, plaintext, plaintext.length); + const chunked = encrypt(name, key, iv, plaintext, 7); + const opened = decrypt(name, key, iv, sealed, 5); + console.log(name.padEnd(14), sealed.length, sealed.toString("hex").slice(0, 48), chunked.equals(sealed), opened.equals(plaintext)); +} + +// String input and output encodings through a stream mode. +const ofb = createCipheriv("aes-128-ofb", bytes(16, 1), bytes(16, 2)); +const encoded = ofb.update("68656c6c6f20776f726c64", "hex", "base64") + ofb.final("base64"); +const unofb = createDecipheriv("aes-128-ofb", bytes(16, 1), bytes(16, 2)); +console.log(encoded, unofb.update(encoded, "base64", "utf8") + unofb.final("utf8")); + +// ECB and triple-DES CBC without padding over whole blocks. +for (const [name, keyLength, ivLength, block] of [["aes-256-ecb", 32, 0, 16], ["des-ede3-cbc", 24, 8, 8]] as const) { + const cipher = createCipheriv(name, bytes(keyLength, 5), ivLength ? bytes(ivLength, 6) : null); + cipher.setAutoPadding(false); + const sealed = Buffer.concat([cipher.update(bytes(block * 3, 7)), cipher.final()]); + const decipher = createDecipheriv(name, bytes(keyLength, 5), ivLength ? bytes(ivLength, 6) : null); + decipher.setAutoPadding(false); + const opened = Buffer.concat([decipher.update(sealed), decipher.final()]); + console.log(name, "unpadded", sealed.length, sealed.toString("hex").slice(0, 32), opened.equals(bytes(block * 3, 7))); +} + +// chacha20's counter is the IV's first 8 bytes, little-endian: the low +// word carries into the high word, which wraps. +const chachaKey = bytes(32, 9); +for (const counter of ["ffffffff00000000", "ffffffffffffffff", "fffffffe01000000"]) { + const iv = Buffer.from(counter + "0102030405060708", "hex"); + const stream = encrypt("chacha20", chachaKey, iv, Buffer.alloc(200), 50); + console.log("chacha20", counter, stream.toString("hex").slice(120, 152), stream.subarray(64, 96).toString("hex")); +} diff --git a/tests/corpus/7151-cipher-legacy-errors.cjs b/tests/corpus/7151-cipher-legacy-errors.cjs new file mode 100644 index 000000000..fe9c59bcc --- /dev/null +++ b/tests/corpus/7151-cipher-legacy-errors.cjs @@ -0,0 +1,83 @@ +// createCipheriv errors for the legacy modes, in Node's order: the IV +// length each mode takes (none for ECB), the key length, OpenSSL's +// "unsupported" for the ciphers its legacy provider holds, and the block +// modes' final-block and padding failures; the AEAD-only methods throw +// Node's invalid-state errors on the stream modes. +const crypto = require("crypto"); + +function attempt(label, run) { + try { + const value = run(); + console.log(label, "ok", Buffer.isBuffer(value) ? value.toString("hex") : value); + } catch (e) { + console.log(label, e.name, e.code, e.message, e.library, e.reason, JSON.stringify(e.opensslErrorStack)); + } +} + +const k16 = Buffer.alloc(16, 1), k24 = Buffer.alloc(24, 1), k32 = Buffer.alloc(32, 1); +attempt("ecb null iv", () => crypto.createCipheriv("aes-128-ecb", k16, null).final()); +attempt("ecb empty iv", () => crypto.createCipheriv("aes-128-ecb", k16, Buffer.alloc(0)).final()); +attempt("ecb 16-byte iv", () => crypto.createCipheriv("aes-128-ecb", k16, Buffer.alloc(16))); +attempt("cfb 15-byte iv", () => crypto.createCipheriv("aes-128-cfb", k16, Buffer.alloc(15))); +attempt("cfb null iv", () => crypto.createCipheriv("aes-128-cfb", k16, null)); +attempt("ofb key 15", () => crypto.createCipheriv("aes-128-ofb", Buffer.alloc(15), Buffer.alloc(16))); +attempt("des3 16-byte iv", () => crypto.createCipheriv("des-ede3-cbc", k24, Buffer.alloc(16))); +attempt("des3 16-byte key", () => crypto.createCipheriv("des-ede3-cbc", k16, Buffer.alloc(8))); +attempt("des-ede 24-byte key", () => crypto.createCipheriv("des-ede-cbc", k24, Buffer.alloc(8))); +attempt("des-ede3 ecb with iv", () => crypto.createCipheriv("des-ede3", k24, Buffer.alloc(8))); +attempt("chacha20 12-byte iv", () => crypto.createCipheriv("chacha20", k32, Buffer.alloc(12))); +attempt("chacha20 authTagLength ignored", () => crypto.createCipheriv("chacha20", k32, Buffer.alloc(16), { authTagLength: 16 }).update("x")); +attempt("upper-case name", () => crypto.createCipheriv("DES-EDE3-CBC", k24, Buffer.alloc(8)).final()); +attempt("des-cbc", () => crypto.createCipheriv("des-cbc", Buffer.alloc(8), Buffer.alloc(8))); +attempt("des-cbc bad iv", () => crypto.createCipheriv("des-cbc", Buffer.alloc(8), Buffer.alloc(3))); +attempt("des-cbc bad key", () => crypto.createCipheriv("des-cbc", Buffer.alloc(3), Buffer.alloc(8))); +attempt("bf-cbc", () => crypto.createDecipheriv("bf-cbc", k16, Buffer.alloc(8))); +attempt("rc4", () => crypto.createCipheriv("rc4", k16, null)); +attempt("rc4 with iv", () => crypto.createCipheriv("rc4", k16, Buffer.alloc(8))); +attempt("seed-ecb", () => crypto.createCipheriv("seed-ecb", k16, null)); +attempt("unknown cipher", () => crypto.createCipheriv("aes-128-xyz", k16, Buffer.alloc(16))); + +attempt("cfb getAuthTag", () => { + const c = crypto.createCipheriv("aes-128-cfb", k16, Buffer.alloc(16)); + c.update("x"); + c.final(); + return c.getAuthTag(); +}); +attempt("ofb setAAD", () => crypto.createCipheriv("aes-128-ofb", k16, Buffer.alloc(16)).setAAD(Buffer.alloc(1))); +attempt("chacha20 setAuthTag", () => crypto.createDecipheriv("chacha20", k32, Buffer.alloc(16)).setAuthTag(Buffer.alloc(16))); +attempt("cfb update sizes", () => { + const c = crypto.createCipheriv("aes-128-cfb", k16, Buffer.alloc(16)); + return [c.update("abc").length, c.update("defghijklmnopqrstu").length, c.final().length].join(","); +}); +attempt("cfb1 setAutoPadding(false)", () => { + const c = crypto.createCipheriv("aes-128-cfb1", k16, Buffer.alloc(16)); + c.setAutoPadding(false); + return Buffer.concat([c.update("abc"), c.final()]); +}); +attempt("ecb unpadded short", () => { + const c = crypto.createCipheriv("aes-128-ecb", k16, null); + c.setAutoPadding(false); + c.update(Buffer.alloc(31, 7)); + return c.final(); +}); +attempt("des3 unpadded short", () => { + const c = crypto.createCipheriv("des-ede3-cbc", k24, Buffer.alloc(8)); + c.setAutoPadding(false); + c.update(Buffer.alloc(7)); + return c.final(); +}); +attempt("des3 bad decrypt", () => { + const d = crypto.createDecipheriv("des-ede3-cbc", k24, Buffer.alloc(8)); + d.update(Buffer.alloc(16, 9)); + return d.final(); +}); +attempt("ecb decrypt 15 bytes", () => { + const d = crypto.createDecipheriv("aes-128-ecb", k16, null); + d.update(Buffer.alloc(15)); + return d.final(); +}); +attempt("ofb update after final", () => { + const c = crypto.createCipheriv("aes-128-ofb", k16, Buffer.alloc(16)); + c.final(); + return c.update("x"); +}); diff --git a/tests/corpus/7152-crypto-prime.ts b/tests/corpus/7152-crypto-prime.ts new file mode 100644 index 000000000..79edcc502 --- /dev/null +++ b/tests/corpus/7152-crypto-prime.ts @@ -0,0 +1,96 @@ +// checkPrimeSync, checkPrime, generatePrimeSync and generatePrime: known +// primes, composites and strong pseudoprimes as bigints, Buffers, typed +// arrays, ArrayBuffers and DataViews, the checks option, and generated +// primes' length, top bits, primality, residues and safety, as +// ArrayBuffers and bigints, synchronously and through the callbacks (whose +// error parameter, typed Error | null, receives null where Node passes +// undefined). The small sizes and the add and rem forms have one possible +// result. +import { checkPrime, checkPrimeSync, generatePrime, generatePrimeSync } from "node:crypto"; + +const mersenne61 = 2n ** 61n - 1n; +const mersenne127 = 2n ** 127n - 1n; +const mersenne521 = 2n ** 521n - 1n; +const known: [string, bigint][] = [ + ["0", 0n], + ["1", 1n], + ["2", 2n], + ["3", 3n], + ["4", 4n], + ["9", 9n], + ["17863", 17863n], + ["17881", 17881n], + ["561 (Carmichael)", 561n], + ["2047 (strong pseudoprime to 2)", 2047n], + ["3215031751 (strong pseudoprime to 2, 3, 5 and 7)", 3215031751n], + ["2^61 - 1", mersenne61], + ["2^61 + 1", mersenne61 + 2n], + ["2^127 - 1", mersenne127], + ["(2^61 - 1)(2^127 - 1)", mersenne61 * mersenne127], + ["2^521 - 1", mersenne521], + ["2^521 + 1", mersenne521 + 2n], +]; +for (const [label, value] of known) console.log(label, checkPrimeSync(value)); + +console.log("Buffer 13", checkPrimeSync(Buffer.from([0, 0, 13]))); +console.log("Uint8Array 15", checkPrimeSync(new Uint8Array([15]))); +const words = new ArrayBuffer(8); +new DataView(words).setBigUint64(0, mersenne61); +console.log("ArrayBuffer 2^61 - 1", checkPrimeSync(words)); +console.log("DataView 2^61 - 1", checkPrimeSync(new DataView(words))); +console.log("empty", checkPrimeSync(new Uint8Array(0))); +console.log("checks 1", checkPrimeSync(97n, { checks: 1 })); +console.log("checks 200", checkPrimeSync(3215031751n, { checks: 200 })); + +const bitLength = (n: bigint): number => n.toString(2).length; +const fromBuffer = (buffer: ArrayBuffer): bigint => BigInt("0x" + Buffer.from(buffer).toString("hex")); + +for (const bits of [2, 3, 4]) console.log("size", bits, generatePrimeSync(bits, { bigint: true })); +const five = generatePrimeSync(5, { bigint: true }); +console.log("size 5", five === 29n || five === 31n); +for (const bits of [8, 16, 31, 32, 33, 64, 127, 256, 512]) { + const p = generatePrimeSync(bits, { bigint: true }); + console.log("size", bits, bitLength(p) === bits, p >> BigInt(bits - 2), checkPrimeSync(p)); +} +const buffer = generatePrimeSync(96); +console.log("ArrayBuffer", buffer instanceof ArrayBuffer, buffer.byteLength, checkPrimeSync(buffer), bitLength(fromBuffer(buffer))); +console.log("bigint false", generatePrimeSync(40, { bigint: false }).byteLength); + +for (const bits of [3, 6, 7]) console.log("safe", bits, generatePrimeSync(bits, { safe: true, bigint: true })); +for (const bits of [16, 64, 128]) { + const p = generatePrimeSync(bits, { safe: true, bigint: true }); + console.log("safe", bits, bitLength(p) === bits, p >> BigInt(bits - 2), checkPrimeSync(p), checkPrimeSync((p - 1n) / 2n)); +} + +console.log("add 200 rem 1", generatePrimeSync(8, { add: 200n, rem: 1n, bigint: true })); +console.log("add 128", generatePrimeSync(8, { add: 128n, bigint: true })); +console.log("add 16 rem 3", generatePrimeSync(5, { add: 16n, rem: 3n, bigint: true })); +const safe4 = generatePrimeSync(5, { add: 4n, safe: true, bigint: true }); +console.log("add 4 safe", safe4 === 23n || safe4 === 47n); +for (const [label, add, rem] of [ + ["add 12 rem 11", 12n, 11n], + ["add 6", 6n, undefined], + ["add 1000 rem 7", 1000n, 7n], +] as const) { + const p = generatePrimeSync(48, rem === undefined ? { add, bigint: true } : { add, rem, bigint: true }); + console.log(label, p % add, checkPrimeSync(p), bitLength(p) >= 48); +} +const viaBuffer = generatePrimeSync(64, { add: Buffer.from([0x01, 0x00]), rem: new Uint8Array([0x0f]), bigint: true }); +console.log("add and rem as bytes", viaBuffer % 256n, checkPrimeSync(viaBuffer)); +const safeAdd = generatePrimeSync(64, { add: 24n, rem: 23n, safe: true, bigint: true }); +console.log("safe add 24 rem 23", safeAdd % 24n, checkPrimeSync((safeAdd - 1n) / 2n)); +console.log("rem without add", generatePrimeSync(16, { rem: 5n, bigint: true }) < 65536n); + +generatePrime(64, (err, prime) => { + console.log("callback", err ?? "no error", prime instanceof ArrayBuffer, prime.byteLength, checkPrimeSync(prime)); + generatePrime(128, { safe: true, bigint: true }, (err2, safe) => { + console.log("callback safe", err2 ?? "no error", bitLength(safe), checkPrimeSync((safe - 1n) / 2n)); + checkPrime(safe, (err3, result) => { + console.log("checkPrime", err3 ?? "no error", result); + checkPrime(Buffer.from([1, 1]), { checks: 3 }, (err4, result2) => { + console.log("checkPrime 257", err4 ?? "no error", result2); + }); + }); + }); +}); +console.log("sync done"); diff --git a/tests/corpus/7153-crypto-prime-errors.cjs b/tests/corpus/7153-crypto-prime-errors.cjs new file mode 100644 index 000000000..ff32e6e09 --- /dev/null +++ b/tests/corpus/7153-crypto-prime-errors.cjs @@ -0,0 +1,80 @@ +// checkPrime, checkPrimeSync, generatePrime and generatePrimeSync errors from +// JavaScript: argument types and ranges, the options bag, add and rem, and +// OpenSSL's generation failures, synchronously and through the callbacks. +const crypto = require("crypto"); + +function attempt(label, run) { + try { + const value = run(); + console.log(label, "ok", typeof value === "bigint" ? `${value}n` : value instanceof ArrayBuffer ? `ArrayBuffer(${value.byteLength})` : value); + } catch (e) { + console.log(label, e.name, e.code, e.message, JSON.stringify(Object.keys(e))); + } +} + +attempt("check string", () => crypto.checkPrimeSync("7")); +attempt("check number", () => crypto.checkPrimeSync(7)); +attempt("check negative", () => crypto.checkPrimeSync(-7n)); +attempt("check large negative", () => crypto.checkPrimeSync(-(2n ** 40n))); +attempt("check options null", () => crypto.checkPrimeSync(7n, null)); +attempt("check options array", () => crypto.checkPrimeSync(7n, [])); +attempt("check options string", () => crypto.checkPrimeSync(7n, "x")); +attempt("check checks string", () => crypto.checkPrimeSync(7n, { checks: "1" })); +attempt("check checks fraction", () => crypto.checkPrimeSync(7n, { checks: 1.5 })); +attempt("check checks -1", () => crypto.checkPrimeSync(7n, { checks: -1 })); +attempt("check checks 2^31", () => crypto.checkPrimeSync(7n, { checks: 2 ** 31 })); +attempt("check checks -0", () => crypto.checkPrimeSync(7n, { checks: -0 })); +attempt("check checks 10", () => crypto.checkPrimeSync(7n, { checks: 10 })); +attempt("check no callback", () => crypto.checkPrime(7n)); +attempt("check callback string", () => crypto.checkPrime(7n, {}, "cb")); +attempt("check async string", () => crypto.checkPrime("7", () => {})); +attempt("check async options null", () => crypto.checkPrime(7n, null, () => {})); + +attempt("size string", () => crypto.generatePrimeSync("8")); +attempt("size fraction", () => crypto.generatePrimeSync(8.5)); +attempt("size 0", () => crypto.generatePrimeSync(0)); +attempt("size 2^31", () => crypto.generatePrimeSync(2 ** 31)); +attempt("size NaN", () => crypto.generatePrimeSync(NaN)); +attempt("size 1", () => crypto.generatePrimeSync(1)); +attempt("size 2 safe", () => crypto.generatePrimeSync(2, { safe: true })); +attempt("size 4 safe", () => crypto.generatePrimeSync(4, { safe: true })); +attempt("size 5 safe", () => crypto.generatePrimeSync(5, { safe: true })); +attempt("options null", () => crypto.generatePrimeSync(8, null)); +attempt("options number", () => crypto.generatePrimeSync(8, 1)); +attempt("safe string", () => crypto.generatePrimeSync(8, { safe: "yes" })); +attempt("bigint number", () => crypto.generatePrimeSync(8, { bigint: 1 })); +attempt("add number", () => crypto.generatePrimeSync(8, { add: 6 })); +attempt("add string", () => crypto.generatePrimeSync(8, { add: "6" })); +attempt("add negative", () => crypto.generatePrimeSync(8, { add: -6n })); +attempt("rem number", () => crypto.generatePrimeSync(8, { add: 6n, rem: 1 })); +attempt("rem negative", () => crypto.generatePrimeSync(8, { add: 6n, rem: -1n })); +attempt("add too long", () => crypto.generatePrimeSync(8, { add: 1024n })); +attempt("add zero", () => crypto.generatePrimeSync(8, { add: 0n })); +attempt("add zero bytes", () => crypto.generatePrimeSync(8, { add: new Uint8Array(0) })); +attempt("rem equal add", () => crypto.generatePrimeSync(8, { add: 6n, rem: 6n })); +attempt("rem above add", () => crypto.generatePrimeSync(8, { add: 6n, rem: 7n })); +attempt("rem without add", () => crypto.generatePrimeSync(8, { rem: 1000n, bigint: true }) < 256n); +attempt("add 1 bigint", () => crypto.generatePrimeSync(8, { add: 1n, bigint: true }) < 256n); +attempt("gen no callback", () => crypto.generatePrime(8)); +attempt("gen options callback", () => crypto.generatePrime(8, {})); +attempt("gen size string", () => crypto.generatePrime("8", () => {})); +attempt("gen add too long", () => crypto.generatePrime(8, { add: 1024n }, () => {})); +attempt("gen options null", () => crypto.generatePrime(8, null, () => {})); + +// The callback forms' generation errors and results, one after another. +crypto.generatePrime(1, function (err, prime) { + console.log("gen 1 callback", arguments.length, err.name, err.code, err.message, JSON.stringify(Object.keys(err)), prime); + crypto.generatePrime(8, { add: 0n }, function (err2, prime2) { + console.log("gen add 0 callback", arguments.length, err2.message, prime2); + crypto.generatePrime(3, { safe: true, bigint: true }, function (err3, prime3) { + console.log("gen 3 safe callback", arguments.length, err3, prime3); + crypto.checkPrime(7n, function (err4, result) { + console.log("check 7 callback", arguments.length, err4, result); + crypto.checkPrime(new Uint8Array([0, 0, 9]), { checks: 3 }, function (err5, result2) { + console.log("check 9 callback", arguments.length, err5, result2); + }); + }); + }); + }); +}); +console.log("sync end"); diff --git a/tests/fixtures/node-types/fenced.ts b/tests/fixtures/node-types/fenced.ts index 644e901f4..27e68a618 100644 --- a/tests/fixtures/node-types/fenced.ts +++ b/tests/fixtures/node-types/fenced.ts @@ -70,12 +70,12 @@ http2.createSecureServer({ allowHTTP1: true, cert: "pem", key: "pem", streamRese http2.connect("https://localhost"); /* The crypto surface beyond the lowered slice (randomness, the hash * chain, the introspection statics): RSA encryption names the lowered - * asymmetric surface, symmetric ciphers the missing cipher stack, prime - * checks theirs, and setFips the FIPS truth (getFips() lowers to 0). */ -import { checkPrimeSync, createCipheriv, publicEncrypt, setFips } from "node:crypto"; + * asymmetric surface, symmetric ciphers the missing cipher stack, the + * secure heap the generic hint, and setFips the FIPS truth (getFips() lowers to 0). */ +import { createCipheriv, publicEncrypt, secureHeapUsed, setFips } from "node:crypto"; publicEncrypt("key", Buffer.alloc(1)); createCipheriv("aes-128-ccm", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); -checkPrimeSync(7n); +secureHeapUsed(); setFips(false); fetch("https://example.invalid/", { integrity: "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", diff --git a/tests/harness/__snapshots__/node-types-fenced.txt b/tests/harness/__snapshots__/node-types-fenced.txt index 133978b5e..cabce49c4 100644 --- a/tests/harness/__snapshots__/node-types-fenced.txt +++ b/tests/harness/__snapshots__/node-types-fenced.txt @@ -117,7 +117,7 @@ fenced.ts:69:71 - error SC2020: 'createSecureServer option 'streamResetBurst' wi fenced.ts:76:1 - error SC2020: 'crypto.publicEncrypt' is typed by @types/node but has no scriptc lowering yet - 75 | import { checkPrimeSync, createCipheriv, publicEncrypt, setFips } from "node:crypto"; + 75 | import { createCipheriv, publicEncrypt, secureHeapUsed, setFips } from "node:crypto"; 76 | publicEncrypt("key", Buffer.alloc(1)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 77 | createCipheriv("aes-128-ccm", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); @@ -129,22 +129,22 @@ fenced.ts:77:16 - error SC2020: 'crypto.createCipheriv with cipher 'aes-128-ccm' 76 | publicEncrypt("key", Buffer.alloc(1)); 77 | createCipheriv("aes-128-ccm", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); | ^~~~~~~~~~~~~ - 78 | checkPrimeSync(7n); + 78 | secureHeapUsed(); - hint: the supported ciphers are aes-128-cbc, aes-192-cbc, aes-256-cbc, aes-128-ctr, aes-192-ctr, aes-256-ctr, aes-128-gcm, aes-192-gcm, aes-256-gcm, and chacha20-poly1305 + hint: the supported ciphers are aes-128, aes-192 and aes-256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1 and ofb modes, 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.checkPrimeSync' is typed by @types/node but has no scriptc lowering yet +fenced.ts:78:1 - error SC2020: 'crypto.secureHeapUsed' is typed by @types/node but has no scriptc lowering yet 77 | createCipheriv("aes-128-ccm", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); - 78 | checkPrimeSync(7n); - | ^~~~~~~~~~~~~~~~~~ + 78 | secureHeapUsed(); + | ^~~~~~~~~~~~~~~~ 79 | 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 - 78 | checkPrimeSync(7n); + 78 | secureHeapUsed(); 79 | setFips(false); | ^~~~~~~~~~~~~~ 80 | fetch("https://example.invalid/", { diff --git a/tests/harness/corpus-costs/7150-cipher-legacy-modes.ts.json b/tests/harness/corpus-costs/7150-cipher-legacy-modes.ts.json new file mode 100644 index 000000000..40196decf --- /dev/null +++ b/tests/harness/corpus-costs/7150-cipher-legacy-modes.ts.json @@ -0,0 +1 @@ +{ "plain": 6099, "san": 8251 } diff --git a/tests/harness/corpus-costs/7151-cipher-legacy-errors.cjs.json b/tests/harness/corpus-costs/7151-cipher-legacy-errors.cjs.json new file mode 100644 index 000000000..6a82dd081 --- /dev/null +++ b/tests/harness/corpus-costs/7151-cipher-legacy-errors.cjs.json @@ -0,0 +1 @@ +{ "plain": 7845, "san": 9581 } diff --git a/tests/harness/corpus-costs/7152-crypto-prime.ts.json b/tests/harness/corpus-costs/7152-crypto-prime.ts.json new file mode 100644 index 000000000..4df2be436 --- /dev/null +++ b/tests/harness/corpus-costs/7152-crypto-prime.ts.json @@ -0,0 +1 @@ +{ "plain": 7273, "san": 10284 } diff --git a/tests/harness/corpus-costs/7153-crypto-prime-errors.cjs.json b/tests/harness/corpus-costs/7153-crypto-prime-errors.cjs.json new file mode 100644 index 000000000..d20dc198a --- /dev/null +++ b/tests/harness/corpus-costs/7153-crypto-prime-errors.cjs.json @@ -0,0 +1 @@ +{ "plain": 5893, "san": 5691 } diff --git a/tests/harness/errors.test.ts b/tests/harness/errors.test.ts index b5fb028f9..c8b0b51b8 100644 --- a/tests/harness/errors.test.ts +++ b/tests/harness/errors.test.ts @@ -847,8 +847,9 @@ try { expect(r.exitCode).toBe(0); expect(r.stdout).toBe( "Error SC2020 The cipher 'aes-128-ccm' has no native implementation; the supported ciphers are " + - "aes-128-cbc, aes-192-cbc, aes-256-cbc, aes-128-ctr, aes-192-ctr, aes-256-ctr, aes-128-gcm, " + - "aes-192-gcm, aes-256-gcm and chacha20-poly1305\n" + + "aes-128, aes-192 and aes-256 in cbc, ctr, gcm, ecb, cfb, cfb8, cfb1 and ofb modes, des-ede3 in " + + "cbc, ecb, cfb, cfb8, cfb1 and ofb modes, des-ede in cbc, ecb, cfb and ofb modes, chacha20 and " + + "chacha20-poly1305\n" + "Error ERR_CRYPTO_UNKNOWN_CIPHER Unknown cipher\n", ); expect(r.stderr).toBe(""); From 091f280ceced8d2df2e7e1745f6e3527b797a1c4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:32:19 -0500 Subject: [PATCH 17/45] Read the union payload inline when comparing it with a number or boolean `u === 0`, `u !== true` and `Object.is(u, x)` against a scalar arm tested the union's tag inline but read its payload through scr_union_get_f64 or scr_union_get_bool. The call passed the union's stack box to the runtime, so LLVM could not promote the box to registers, and an element read of a `number[]` compared with a number kept its value, tag and box in memory. The comparison now loads the payload slot directly, as other union extractions already do, and the box no longer escapes. --- .../compiler/src/backend/llvm/expr-dynamic.ts | 8 +-- .../corpus/7322-union-scalar-equality.ts.json | 6 ++ .../union-scalar-equality-emission.test.ts | 45 ++++++++++++ tests/corpus/7322-union-scalar-equality.ts | 68 +++++++++++++++++++ .../7322-union-scalar-equality.ts.json | 1 + 5 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7322-union-scalar-equality.ts.json create mode 100644 packages/compiler/test/union-scalar-equality-emission.test.ts create mode 100644 tests/corpus/7322-union-scalar-equality.ts create mode 100644 tests/harness/corpus-costs/7322-union-scalar-equality.ts.json diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index 563a900f8..819358aad 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -1282,9 +1282,7 @@ function emitUnionEqWrappedScalar( B.startBlock(same); const eq = B.tmp(); if (arm.kind === "f64") { - host.declare(`declare double @scr_union_get_f64(ptr)`); - const v = B.tmp(); - B.line(`${v} = call double @scr_union_get_f64(ptr ${union.name})`); + const v = host.unionGetF64(union.name); if (e.sameValue) { host.declare(`declare zeroext i1 @scr_num_same_value(double, double)`); B.line(`${eq} = call zeroext i1 @scr_num_same_value(double ${v}, double ${plain.name})`); @@ -1292,9 +1290,7 @@ function emitUnionEqWrappedScalar( B.line(`${eq} = fcmp oeq double ${v}, ${plain.name}`); } } else { - host.declare(`declare zeroext i1 @scr_union_get_bool(ptr)`); - const v = B.tmp(); - B.line(`${v} = call zeroext i1 @scr_union_get_bool(ptr ${union.name})`); + const v = host.unionGetBool(union.name); B.line(`${eq} = icmp eq i1 ${v}, ${plain.name}`); } B.line(`store i1 ${eq}, ptr ${slot}`); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7322-union-scalar-equality.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7322-union-scalar-equality.ts.json new file mode 100644 index 000000000..73257a3f4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7322-union-scalar-equality.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7322-union-scalar-equality.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/union-scalar-equality-emission.test.ts b/packages/compiler/test/union-scalar-equality-emission.test.ts new file mode 100644 index 000000000..62d59e258 --- /dev/null +++ b/packages/compiler/test/union-scalar-equality-emission.test.ts @@ -0,0 +1,45 @@ +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-union-scalar-eq-")); + 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 }); + } +} + +const source = ` +function zeros(a: number[], at: number[]): number { + let n = 0; + for (const i of at) if (a[i] === 0) n++; + return n; +} +function flags(a: (boolean | undefined)[]): number { + let n = 0; + for (let i = 0; i < a.length; i++) if (a[i] === true) n++; + return n; +} +console.log(zeros([0, 1, 0], [0, 1, 2, 5]), flags([true, undefined, false])); +`; + +test("comparing a union with a number or boolean reads its payload inline", async () => { + const llvm = await emitLlvm(source); + for (const name of ["zeros", "flags"]) { + const fn = new RegExp(`^define internal double @sc_bf_${name}\\([^]*?^}`, "m").exec(llvm)?.[0]; + expect(fn, name).toBeDefined(); + // The tag test and the payload load stay in the function, so the + // union's stack box has no escaping use. + expect(fn).not.toMatch(/@scr_union_get_(f64|bool)\(/); + expect(fn).toMatch(/getelementptr inbounds %ScrUnion, ptr %\S+, i64 0, i32 5/); + } +}); diff --git a/tests/corpus/7322-union-scalar-equality.ts b/tests/corpus/7322-union-scalar-equality.ts new file mode 100644 index 000000000..82e0564fc --- /dev/null +++ b/tests/corpus/7322-union-scalar-equality.ts @@ -0,0 +1,68 @@ +// Strict equality and inequality between a `number | undefined` or +// `boolean | undefined` value and a number or boolean: element reads of +// holes, past the end and of present undefined, NaN, -0 and +0, and +// Object.is, in branches, loops and expressions. + +function zeros(a: number[], at: number[]): string { + const hits: string[] = []; + for (const i of at) { + const v = a[i]; + hits.push(`${i}:${v === 0 ? "eq" : "ne"}${v !== 0 ? "!" : ""}${0 === v ? "r" : ""}`); + } + return hits.join(" "); +} + +const holey: number[] = [0, -0, 1]; +holey[5] = 0; +console.log(zeros(holey, [0, 1, 2, 3, 4, 5, 6, -1])); +console.log(zeros([NaN, 0.5, -1, 0], [0, 1, 2, 3])); + +function nanAndZeros(a: (number | undefined)[]): string { + return a + .map((v) => `${v === -0}${v === 0}${Object.is(v, -0)}${Object.is(v, 0)}${Object.is(v, NaN)}`) + .join(" "); +} +console.log(nanAndZeros([0, -0, NaN, undefined, 1])); + +function flags(a: (boolean | undefined)[]): string { + let t = 0; + let f = 0; + let notTrue = 0; + for (let i = 0; i < a.length + 2; i++) { + if (a[i] === true) t++; + if (a[i] === false) f++; + if (a[i] !== true) notTrue++; + } + return `${t} ${f} ${notTrue}`; +} +const bools: (boolean | undefined)[] = [true, false, undefined, true]; +bools[7] = false; +console.log(flags(bools)); + +// A permutation walk that stops at a zero element, as the flip loops of a +// counting benchmark do. +function walk(p: number[], start: number): number { + let steps = 0; + let at = start; + while (p[at] !== 0 && steps < 20) { + at = p[at]!; + steps++; + } + return steps; +} +console.log(walk([0, 3, 1, 2], 1), walk([1, 2, 3, 0], 0), walk([2, 2, 2], 0)); + +class Slot { + value: number | undefined = undefined; + on: boolean | undefined = undefined; +} +const slots = [new Slot(), new Slot(), new Slot()]; +slots[1]!.value = 0; +slots[1]!.on = true; +slots[2]!.value = -0; +slots[2]!.on = false; +console.log( + slots + .map((s) => `${s.value === 0}${s.value !== 0}${s.on === true}${s.on === false}${s.on !== false}`) + .join(" "), +); diff --git a/tests/harness/corpus-costs/7322-union-scalar-equality.ts.json b/tests/harness/corpus-costs/7322-union-scalar-equality.ts.json new file mode 100644 index 000000000..2df20a0ed --- /dev/null +++ b/tests/harness/corpus-costs/7322-union-scalar-equality.ts.json @@ -0,0 +1 @@ +{ "plain": 2100, "san": 2800 } From 2d6ef06fcb04bcf46a1b0f789f86efb0dde5b649 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:40:22 -0500 Subject: [PATCH 18/45] Version while loops over typed arrays on their counters' bounds Typed-array loop versions applied only to for loops, so a scanner written with while loops, such as `while (pos < end && bytes[pos] === 32) pos++`, kept one bounds test per access. A while loop counter is now a number local that the loop changes only by positive integer increments (`c = c + k`, `c++`, `c = (c + k) | 0`) written as statements of its body, blocks, branches and nested while loops. An access at `counter + d` after a condition compared the counter below a loop-invariant bound, with no increment since, is in bounds for the whole loop when the guard finds the counter's entry value an exact integer of at least -d and the bound at most the length minus the access's extent. A counter with a `| 0` increment also needs its loops' bounds at most 2^31 minus its increments, so it never wraps. A fixed check (a statically ranged index) now needs an end below 2^31. The counter of a loop to a number[]'s length whose length the loop may change reaches 2^32 - 2, and its typed-array accesses got a guard no typed array passes and a second copy of the loop. --- .../compiler/src/backend/llvm/byte-windows.ts | 1 + .../backend/llvm/bytes-loop-versions.test.ts | 62 +++ .../src/backend/llvm/bytes-loop-versions.ts | 490 +++++++++++++++++- .../src/backend/llvm/emit-statements.ts | 81 +-- packages/compiler/src/backend/llvm/emitter.ts | 2 +- ...98-typed-array-while-loop-versions.ts.json | 6 + .../6998-typed-array-while-loop-versions.ts | 149 ++++++ ...98-typed-array-while-loop-versions.ts.json | 1 + 8 files changed, 746 insertions(+), 46 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6998-typed-array-while-loop-versions.ts.json create mode 100644 tests/corpus/6998-typed-array-while-loop-versions.ts create mode 100644 tests/harness/corpus-costs/6998-typed-array-while-loop-versions.ts.json diff --git a/packages/compiler/src/backend/llvm/byte-windows.ts b/packages/compiler/src/backend/llvm/byte-windows.ts index 5fffa1428..9741cc547 100644 --- a/packages/compiler/src/backend/llvm/byte-windows.ts +++ b/packages/compiler/src/backend/llvm/byte-windows.ts @@ -43,6 +43,7 @@ export function findInitializedByteLoopBindings( if (stmt.init) list([stmt.init], inner); list(stmt.body, inner); } + if (stmt.kind === "while") entries.set(stmt, new Set(known)); if (stmt.kind === "while" || stmt.kind === "doWhile") list(stmt.body, new Set(known)); } } 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 ace8f294c..2d70e9014 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts @@ -177,6 +177,11 @@ test("statically ranged indices compare one constant with the length", () => { ]); expect(version.affine).toEqual([]); expect(version.counted).toBeNull(); + // A uint32 index (an array counter's range) gets no guard: no typed array + // in practice has 2^31 elements. + const wide = bin(">>>", bin("^", ref("i"), ref("k")), num(0)); + const unbounded = counted([set(ref("out", f64s), num(0), get(ref("table", i32s), wide))]); + expect(match(fn([unbounded]), unbounded)!.fixed).toEqual([{ receiver: 0, end: 0 }]); }); test("scaled counters and body temps resolve to their receiver and index", () => { @@ -358,6 +363,63 @@ test("index temps of a version's counter are integers in the fast copy", () => { expect(fast).not.toContain("bytes.index"); }); +test("while loop counters below a bound version their accesses", () => { + // while (i < n) { out[i] = src[i + 1]; i = i + 1 } + const step: IrStmt = { kind: "assign", localId: "i", value: bin("+", ref("i"), num(1)), loc }; + const whileLoop = (body: IrStmt[]): IrStmt & { kind: "while" } => ({ + kind: "while", + cond: { kind: "bin", op: "<", left: ref("i"), right: ref("n"), type: BOOL, loc }, + body, + loc, + }); + const copy = whileLoop([ + set(ref("out", f64s), ref("i"), get(ref("src", f64s), bin("+", ref("i"), num(1)))), + step, + ]); + const declared = (loop: IrStmt): IrFunction => + fn([{ kind: "varDecl", localId: "i", init: ref("k"), loc }, loop]); + const versionOf = (loop: IrStmt & { kind: "while" }): BytesLoopVersion | null => { + const f = declared(loop); + const ranges = analyzeIntegerRanges(f); + return matchBytesLoopVersion(loop, null, { + locals: new Map(f.locals.map((l) => [l.id, l])), + invariantGlobals: new Set(), + captured: new Set(), + ranges, + initialized: findInitializedByteLoopBindings(f).get(loop) ?? new Set(), + proven: new Set(), + workers: false, + owned: new Set(), + }); + }; + const version = versionOf(copy)!; + expect(version.bounds.size).toBe(2); + expect(version.bounded.map((c) => [version.receivers[c.receiver]!.ref, c.slack])).toEqual([ + [ref("out", f64s), 0], + [ref("src", f64s), 1], + ]); + // `out[i]` needs `i` to start at 0 or above (`src[i + 1]` only at -1). + expect(version.counters.map((c) => [c.ref.kind === "varRef" && c.ref.localId, c.min])).toEqual([ + ["i", 0], + ]); + // An access after the counter advances in the same pass stays checked. + const advanced = whileLoop([step, set(ref("out", f64s), ref("i"), num(0))]); + expect(versionOf(advanced)).toBeNull(); + const mod: IrModule = { + irVersion: 17, + sourceFile: loc.file, + entry: "__main", + functions: [ + { name: "__main", params: [], returnType: VOID, locals: [], body: [], loc }, + declared(copy), + ], + }; + const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; + const fast = /^bytes\.version\.fast\d+:$[^]*?^bytes\.version\.done\d+:$/m.exec(body)![0]; + expect(fast).not.toContain("bytes.index"); + expect(body.slice(0, body.indexOf(fast))).toContain("bytes.index.invalid"); +}); + test("Float16Array accesses version in elements and share the element tag", () => { const f16s: IrType = { kind: "bytes", elem: "f16" }; const withHalves = (body: IrStmt[]): IrFunction => { diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index c3cee3feb..81f0e9eee 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -1,4 +1,4 @@ -import type { IrExpr, IrLocal, IrStmt } from "../../ir/ir.js"; +import { F64, type IrExpr, type IrLocal, type IrStmt } from "../../ir/ir.js"; import type { IntegerRange, IntegerRanges } from "../../ir/integer-ranges.js"; import type { IntegerCountedForLoop } from "../../ir/integer-loops.js"; import type { LlvmEmitterContext } from "./expr-context.js"; @@ -23,6 +23,24 @@ interface KeyedTerm extends Term { key: string; } +/** Every access of `receiver` at a while loop counter `c + d` happens while + * `c < bound` (`c <= bound` when `inclusive`) holds and before the counter + * advances, so it is in bounds when `bound + slack <= length`. */ +interface BoundedCheck { + receiver: number; + bound: IrExpr; + slack: number; +} + +/** A while loop counter whose entry value the guard tests: an exact + * integer of at least `min`. A counter that `| 0` wraps also needs every + * bound of its loops at most `wrapLimit`, so that it never reaches 2^31. */ +interface CounterCheck { + ref: VarRef; + min: number; + wrapBounds: { bound: IrExpr; limit: number }[]; +} + /** Every access of `receiver` at a static index range ends below `end + 1`. */ interface FixedCheck { receiver: number; @@ -51,6 +69,9 @@ export interface BytesLoopVersion { ownedReceivers: number[]; fixed: FixedCheck[]; affine: AffineCheck[]; + /** While loops: accesses at a counter below a loop-invariant bound. */ + bounded: BoundedCheck[]; + counters: CounterCheck[]; /** Keys of affine terms the guard tests at run time: exact integers * within GUARDED_TERM. */ guarded: ReadonlySet; @@ -83,7 +104,7 @@ export interface BytesLoopFacts { } const MAX_COST = 400; -const MAX_FIXED_END = 2 ** 32; +const MAX_FIXED_END = 2 ** 31; const MAX_CHECKS = 8; const MAX_OFFSET = 2 ** 31; const SAFE = Number.MAX_SAFE_INTEGER; @@ -116,7 +137,7 @@ const INVARIANT_OPS = new Set(["+", "-", "*", "&", "|", "^", "<<", ">>", ">>>"]) * whenever the guard fails, and keeps every out-of-bounds read, ignored * write and NaN-index behavior. */ export function matchBytesLoopVersion( - loop: IrStmt & { kind: "for" }, + loop: IrStmt & { kind: "for" | "while" }, counted: IntegerCountedForLoop | null, facts: BytesLoopFacts, ): BytesLoopVersion | null { @@ -155,10 +176,10 @@ export function matchBytesLoopVersion( // writes is not invariant either: `for (let i = (a = b, 0); ...)` must // not keep the bounds the guard proved for the old `a`. if ( - (loop.init !== null && !scanStmt(loop.init)) || + (loop.kind === "for" && loop.init !== null && !scanStmt(loop.init)) || !loop.body.every(scanStmt) || (loop.cond !== null && !scanExpr(loop.cond)) || - (loop.update !== null && !scanStmt(loop.update)) + (loop.kind === "for" && loop.update !== null && !scanStmt(loop.update)) ) return null; // A body temp stands for its initializer only when it is a constant @@ -337,6 +358,44 @@ export function matchBytesLoopVersion( return sum + Math.max(Math.abs(r.min), Math.abs(r.max)); }, 0); + const whileAccesses = loop.kind === "while" ? whileCounterAccesses(loop) : null; + function whileCounterAccesses(loop: IrStmt & { kind: "while" }) { + return findWhileCounterAccesses(loop, { + counterLocal: (id) => { + const local = facts.locals.get(id); + return ( + local?.type.kind === "f64" && + !local.boxed && + !local.tdz && + !facts.captured.has(id) && + facts.initialized.has(id) + ); + }, + boundKey: (e) => { + if (e.type.kind !== "f64") return null; + // The guard evaluates the bound before the loop: a typed array's + // length needs the binding itself, not a temp the body declares. + if ( + e.kind === "bytesIntrinsic" && + e.method === "length" && + e.receiver.kind === "varRef" && + e.receiver.type.kind === "bytes" && + invariant(e.receiver.localId) + ) + return `bytes-length:${e.receiver.localId}`; + if ( + e.kind === "strIntrinsic" && + e.method === "length" && + e.args.length === 0 && + e.receiver.kind === "varRef" && + e.receiver.type.kind === "string" && + invariant(e.receiver.localId) + ) + return `string-length:${e.receiver.localId}`; + return pureKey(e); + }, + }); + } const receivers: { ref: VarRef; global: boolean }[] = []; const receiverIndex = new Map(); const fixed = new Map(); @@ -356,6 +415,11 @@ export function matchBytesLoopVersion( // Worker programs: accesses through invariant receivers, proven or not, // become thread-owned when the guard finds no shared storage. const owned = new Map(); + // While loops: accesses at a counter below a bound, by receiver and bound. + const boundedChecks = new Map< + string, + { check: BoundedCheck; nodes: { node: Node; access: WhileAccess }[] } + >(); const access = (node: Node, array: IrExpr, index: IrExpr, width: number): void => { const ref = root(array); if (!ref) return; @@ -390,11 +454,30 @@ export function matchBytesLoopVersion( }); return; } + const bounded = whileAccesses?.accesses.get(node); + const loopCounter = bounded && whileAccesses!.counters.get(bounded.counter); + if (bounded && loopCounter && (!loopCounter.wraps || loopCounter.bounds !== null)) { + const receiver = receiverOf(ref); + const key = `${receiver}|${bounded.key}|${bounded.adj}`; + const slack = bounded.offset + width - 1 + bounded.adj; + const group = boundedChecks.get(key); + if (group) { + group.check.slack = Math.max(group.check.slack, slack); + group.nodes.push({ node, access: bounded }); + } else + boundedChecks.set(key, { + check: { receiver, bound: bounded.bound, slack }, + nodes: [{ node, access: bounded }], + }); + return; + } const range = facts.ranges.get(index); if (!range) return; const end = range.max + width - 1; - // Only a length a buffer can have: an outer loop must not pay for a - // guard that bounds an inner loop's unbounded counter. + // Only an end below 2^31: an outer loop must not pay for a guard that + // bounds an inner loop's unbounded counter, and the counter of a loop to + // an array's length reaches 2^32 - 2, a length no typed array in + // practice has. if (range.min < 0 || end >= MAX_FIXED_END) return; const receiver = receiverOf(ref); const group = fixed.get(receiver); @@ -416,6 +499,7 @@ export function matchBytesLoopVersion( return everyStmtChild(s, visitExpr, visitStmt); }; loop.body.every(visitStmt); + if (loop.kind === "while") visitExpr(loop.cond); // Bound the counter so every counter operand stays a safe integer. let bound = SAFE; const affineGroups = [...affineChecks.values()].filter((group) => { @@ -431,8 +515,18 @@ export function matchBytesLoopVersion( }); const fixedKept = [...fixed.values()].slice(0, MAX_CHECKS); const affineKept = affineGroups.slice(0, MAX_CHECKS - fixedKept.length); + const boundedKept = [...boundedChecks.values()].slice( + 0, + Math.max(0, MAX_CHECKS - fixedKept.length - affineKept.length), + ); const ownedKept = [...owned.entries()].slice(0, MAX_CHECKS); - if (fixedKept.length === 0 && affineKept.length === 0 && ownedKept.length === 0) return null; + if ( + fixedKept.length === 0 && + affineKept.length === 0 && + boundedKept.length === 0 && + ownedKept.length === 0 + ) + return null; const bounds = new Set(); const ownedNodes = new Set(); const used = new Set(); @@ -477,6 +571,39 @@ export function matchBytesLoopVersion( for (const group of affineKept) for (const term of group.check.terms) if (guardedRanges.has(term.expr)) guarded.add(term.key); for (const [node, key] of guardedNodes) if (guarded.has(key)) ranges.set(node, GUARDED_TERM); + // While loop counters of the kept checks: each entry value is an exact + // integer that no access offset takes below 0. In the fast copy each + // access's index is below its length, and its counter read at least the + // most negative offset. + const narrow = (e: IrExpr, range: IntegerRange): void => { + const known = ranges.get(e) ?? facts.ranges.get(e); + ranges.set( + e, + known ? { min: Math.max(known.min, range.min), max: Math.min(known.max, range.max) } : range, + ); + }; + const counterMins = new Map(); + for (const group of boundedKept) { + used.add(group.check.receiver); + for (const { node, access } of group.nodes) { + bounds.add(node); + const min = 0 - access.offset; + counterMins.set(access.counter, Math.max(counterMins.get(access.counter) ?? -SAFE, min)); + narrow(access.ref, { min: -MAX_OFFSET, max: SAFE }); + if (access.index !== access.ref) narrow(access.index, { min: 0, max: SAFE }); + } + } + const counterChecks: CounterCheck[] = []; + for (const [id, min] of counterMins) { + const info = whileAccesses!.counters.get(id)!; + counterChecks.push({ + ref: { kind: "varRef", localId: id, type: F64, loc: loop.loc }, + min, + wrapBounds: info.wraps + ? info.bounds!.map((b) => ({ bound: b.bound, limit: 2 ** 31 - info.sum - b.adj })) + : [], + }); + } // 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])); @@ -500,6 +627,12 @@ export function matchBytesLoopVersion( minOffset: g.check.minOffset, maxEnd: g.check.maxEnd, })), + bounded: boundedKept.map((g) => ({ + receiver: renumber.get(g.check.receiver)!, + bound: g.check.bound, + slack: g.check.slack, + })), + counters: counterChecks, guarded, counted: affineKept.length > 0 ? counted : null, counterBound: needsBound ? bound : null, @@ -507,6 +640,307 @@ export function matchBytesLoopVersion( }; } +/** A typed-array access at a while loop counter: `counter + offset`, read + * or written while `counter < bound` (`<=` when `adj` is 1) holds. */ +interface WhileAccess { + counter: string; + /** The index, and the counter's read in it. */ + index: IrExpr; + ref: IrExpr; + bound: IrExpr; + key: string; + adj: number; + offset: number; +} + +interface WhileCounter { + /** Some increment is `c = (c + k) | 0`. */ + wraps: boolean; + /** The sum of every increment literal in the loop. */ + sum: number; + /** One bound from the condition of the loop and of every nested while + * loop that advances the counter; null when one of them has none. */ + bounds: { bound: IrExpr; adj: number }[] | null; +} + +/** `counter = counter + k`, `counter = (counter + k) | 0` or `counter++`. */ +function counterStep(s: IrStmt): { id: string; k: number; wraps: boolean } | null { + if (s.kind === "exprStmt" && s.expr.kind === "incDec" && s.expr.op === "+") + return { id: s.expr.localId, k: 1, wraps: false }; + if (s.kind !== "assign") return null; + let value = s.value, + wraps = false; + if ( + value.kind === "bin" && + value.op === "|" && + value.right.kind === "numLit" && + value.right.value === 0 && + value.left.kind === "bin" + ) { + value = value.left; + wraps = true; + } + if ( + value.kind !== "bin" || + value.op !== "+" || + value.left.kind !== "varRef" || + value.left.localId !== s.localId || + value.right.kind !== "numLit" || + !Number.isSafeInteger(value.right.value) || + value.right.value <= 0 || + value.right.value > MAX_OFFSET + ) + return null; + return { id: s.localId, k: value.right.value, wraps }; +} + +/** Typed-array accesses of a while loop that happen at a counter below a + * loop-invariant bound. A counter is a number local that the loop changes + * only by positive integer increments, written as statements of the body, + * of its blocks and branches, or of nested while loops. The condition of + * the loop, an `if` or a `&&` chain that compares the counter below a bound + * (`while (pos < end && bytes[pos] === 32) pos++`) makes it below that + * bound until the next increment on the path. The counter starts at its + * entry value and only grows (a `| 0` increment never wraps when every + * bound is at most 2^31 minus the increments), so an access at `counter + + * d` is in bounds for the whole loop when the entry value is at least `-d` + * and `bound + d < length` (`+ 1` for `<=`). */ +function findWhileCounterAccesses( + loop: IrStmt & { kind: "while" }, + host: { + counterLocal: (id: string) => boolean; + /** A key for a bound expression whose value the loop never changes. */ + boundKey: (e: IrExpr) => string | null; + }, +): { accesses: Map; counters: Map } { + const steps = new Map(); + const refused = new Set(); + // Increments count only as statements of the loop's straight-line + // structure; any other write refuses the binding. + const writes = (list: readonly IrStmt[], direct: boolean): void => { + for (const s of list) { + const step = counterStep(s); + if (step && direct) { + const prior = steps.get(step.id); + steps.set(step.id, { + sum: (prior?.sum ?? 0) + step.k, + wraps: (prior?.wraps ?? false) || step.wraps, + }); + continue; + } + if (step) refused.add(step.id); + const nested = + direct && + (s.kind === "if" || s.kind === "while" || (s.kind === "block" && !s.labels?.length)); + if (s.kind === "assign" || s.kind === "varDecl" || s.kind === "forOf") refused.add(s.localId); + if (s.kind === "tryCatch" && s.catchLocalId) refused.add(s.catchLocalId); + everyStmtChild( + s, + (e) => (exprWrites(e), true), + (c) => (writes([c], nested), true), + ); + } + }; + const exprWrites = (e: IrExpr): void => { + if (e.kind === "assignExpr" || e.kind === "incDec") refused.add(e.localId); + everyExprChild( + e, + (c) => (exprWrites(c), true), + (c) => (writes([c], false), true), + ); + }; + exprWrites(loop.cond); + writes(loop.body, true); + const counter = (id: string): boolean => + steps.has(id) && !refused.has(id) && host.counterLocal(id); + + type Fact = { bound: IrExpr; key: string; adj: number }; + type Clean = ReadonlyMap; + // The bounds a condition puts on counters while it holds. + const facts = (cond: IrExpr, into: Map): void => { + if (cond.kind === "toBool") return facts(cond.operand, into); + if (cond.kind === "logical" && cond.op === "&&") { + facts(cond.left, into); + facts(cond.right, into); + return; + } + if (cond.kind !== "bin") return; + const below = cond.op === "<" || cond.op === "<=", + above = cond.op === ">" || cond.op === ">="; + const c = below ? cond.left : above ? cond.right : null, + bound = below ? cond.right : cond.left; + if (c?.kind !== "varRef" || !counter(c.localId) || into.has(c.localId)) return; + const key = host.boundKey(bound); + if (key === null) return; + into.set(c.localId, { bound, key, adj: cond.op === "<=" || cond.op === ">=" ? 1 : 0 }); + }; + // The facts that hold after either of two paths. + const meet = (a: Clean | null, b: Clean | null): Clean | null => { + if (a === null) return b; + if (b === null) return a; + const out = new Map(); + for (const [id, fact] of a) if (b.get(id) === fact) out.set(id, fact); + return out; + }; + const withFacts = (clean: Clean, cond: IrExpr): Clean => { + const out = new Map(clean); + facts(cond, out); + return out; + }; + const accesses = new Map(); + const record = (node: Node, index: IrExpr, clean: Clean): void => { + let ref: IrExpr = index, + offset = 0; + if (index.kind === "bin" && (index.op === "+" || index.op === "-")) { + const literal = + index.right.kind === "numLit" ? index.right : index.op === "+" ? index.left : null; + const other = literal === index.right ? index.left : index.right; + if (literal?.kind !== "numLit" || !Number.isSafeInteger(literal.value)) return; + if (Math.abs(literal.value) > MAX_OFFSET || Object.is(literal.value, -0)) return; + offset = index.op === "-" ? -literal.value : literal.value; + ref = other; + } + if (ref.kind !== "varRef") return; + const fact = clean.get(ref.localId); + if (fact) accesses.set(node, { counter: ref.localId, index, ref, ...fact, offset }); + }; + const expr = (e: IrExpr, clean: Clean): void => { + if (e.kind === "bytesIntrinsic") { + const numeric = byteNumberAccess(e); + const index = numeric + ? e.args[numeric.offsetArg] + : e.method === "get" + ? e.args[0] + : undefined; + if (index) record(e, index, clean); + } + if (e.kind === "logical" && e.op === "&&") { + expr(e.left, clean); + expr(e.right, withFacts(clean, e.left)); + return; + } + if (e.kind === "ternary") { + expr(e.cond, clean); + expr(e.then, withFacts(clean, e.cond)); + expr(e.else_, clean); + return; + } + everyExprChild( + e, + (c) => (expr(c, clean), true), + (c) => (stmts([c], clean), true), + ); + }; + // Walks statements in order; the result is the clean state where the + // list falls through, or null when it never does. + const stmts = (list: readonly IrStmt[], clean: Clean): Clean | null => { + let current: Clean | null = clean; + for (const s of list) { + if (current === null) return null; + const step = counterStep(s); + if (step) { + const next: Map = new Map(current); + next.delete(step.id); + current = next; + continue; + } + switch (s.kind) { + case "if": { + expr(s.cond, current); + const then = stmts(s.then, withFacts(current, s.cond)); + const otherwise = stmts(s.else_ ?? [], current); + current = meet(then, otherwise); + break; + } + case "while": { + // A pass of the nested loop may follow its own increments. + const advanced: Map = new Map(current); + for (const id of writtenCounters(s.body)) advanced.delete(id); + expr(s.cond, advanced); + stmts(s.body, withFacts(advanced, s.cond)); + current = advanced; + break; + } + case "block": + if (!s.labels?.length) { + current = stmts(s.body, current); + break; + } + everyStmtChild( + s, + (e) => (expr(e, current!), true), + (c) => (stmts([c], current!), true), + ); + break; + case "bytesSet": + record(s, s.index, current); + everyStmtChild( + s, + (e) => (expr(e, current!), true), + (c) => (stmts([c], current!), true), + ); + break; + case "break": + case "continue": + case "return": + case "throw": + everyStmtChild( + s, + (e) => (expr(e, current!), true), + (c) => (stmts([c], current!), true), + ); + current = null; + break; + default: + everyStmtChild( + s, + (e) => (expr(e, current!), true), + (c) => (stmts([c], current!), true), + ); + break; + } + } + return current; + }; + const writtenCounters = (list: readonly IrStmt[]): Set => { + const out = new Set(); + const visit = (s: IrStmt): boolean => { + const step = counterStep(s); + if (step) out.add(step.id); + return everyStmtChild(s, () => true, visit); + }; + list.every(visit); + return out; + }; + expr(loop.cond, new Map()); + stmts(loop.body, withFacts(new Map(), loop.cond)); + + // Each counter's bounds: the loop's and those of nested while loops that + // advance it. + const counters = new Map(); + const loops: (IrStmt & { kind: "while" })[] = [loop]; + const collectLoops = (s: IrStmt): boolean => { + if (s.kind === "while") loops.push(s); + return everyStmtChild(s, () => true, collectLoops); + }; + loop.body.every(collectLoops); + for (const [id, step] of steps) { + if (!counter(id)) continue; + let bounds: WhileCounter["bounds"] = []; + for (const l of loops) { + if (l !== loop && !writtenCounters(l.body).has(id)) continue; + const fact = withFacts(new Map(), l.cond).get(id); + if (!fact) { + bounds = null; + break; + } + bounds.push({ bound: fact.bound, adj: fact.adj }); + } + counters.set(id, { ...step, bounds }); + } + return { accesses, counters }; +} + /** 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 @@ -553,6 +987,27 @@ export function emitBytesLoopVersionGuard( B.line(`${ok} = icmp ugt i64 ${lengths[check.receiver]}, ${check.end}`); conditions.push(ok); } + for (const counter of version.counters) { + const value = host.emitExpr(counter.ref).name; + conditions.push(emitExactIntegerTest(host, value, counter.min, SAFE).ok); + for (const wrap of counter.wrapBounds) { + const ok = B.tmp(); + B.line(`${ok} = fcmp ole double ${host.emitExpr(wrap.bound).name}, ${f64Lit(wrap.limit)}`); + conditions.push(ok); + } + } + for (const check of version.bounded) { + // `bound <= length - slack` in doubles: both sides are exact (a length + // is below 2^53 and a slack below 2^32), and NaN fails. + const bound = host.emitExpr(check.bound).name; + const length = B.tmp(), + room = B.tmp(), + ok = B.tmp(); + B.line(`${length} = uitofp i64 ${lengths[check.receiver]} to double`); + B.line(`${room} = fsub double ${length}, ${f64Lit(check.slack)}`); + B.line(`${ok} = fcmp ole double ${bound}, ${room}`); + conditions.push(ok); + } if (counted && version.affine.length > 0) { // The first and last counter values, in ascending order. The last value // of a non-unit step is exact: `start + ⌊(limit ∓ 1 - start) / step⌋ * @@ -599,7 +1054,7 @@ export function emitBytesLoopVersionGuard( for (const term of check.terms) { const value = host.emitExpr(term.expr); if (version.guarded.has(term.key)) { - const tested = emitGuardedTerm(host, value.name); + const tested = emitExactIntegerTest(host, value.name, GUARDED_TERM.min, GUARDED_TERM.max); conditions.push(tested.ok); const sum = B.tmp(); B.line(`${sum} = ${term.sign > 0 ? "add" : "sub"} i64 ${base}, ${tested.integer}`); @@ -653,10 +1108,15 @@ export function emitBytesLoopVersionGuard( else B.condBr(valid, fast, slow); } -/** Tests that a guarded term is an exact integer within GUARDED_TERM (not - * -0; NaN fails the ordered comparisons) and gives its i64. The integer is - * frozen, so it is a fixed value even when the test fails. */ -function emitGuardedTerm(host: LlvmEmitterContext, value: string): { ok: string; integer: string } { +/** Tests that a double is an exact integer within [min, max] (not -0; NaN + * fails the ordered comparisons) and gives its i64. The integer is frozen, + * so it is a fixed value even when the test fails. */ +function emitExactIntegerTest( + host: LlvmEmitterContext, + value: string, + min: number, + max: number, +): { ok: string; integer: string } { const B = host.B; const low = B.tmp(), high = B.tmp(), @@ -668,8 +1128,8 @@ function emitGuardedTerm(host: LlvmEmitterContext, value: string): { ok: string; backBits = B.tmp(), exact = B.tmp(), ok = B.tmp(); - B.line(`${low} = fcmp oge double ${value}, ${f64Lit(GUARDED_TERM.min)}`); - B.line(`${high} = fcmp ole double ${value}, ${f64Lit(GUARDED_TERM.max)}`); + B.line(`${low} = fcmp oge double ${value}, ${f64Lit(min)}`); + B.line(`${high} = fcmp ole double ${value}, ${f64Lit(max)}`); B.line(`${inRange} = and i1 ${low}, ${high}`); B.line(`${raw} = fptosi double ${value} to i64`); B.line(`${integer} = freeze i64 ${raw}`); diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index a22de3445..4b3550756 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -51,7 +51,7 @@ import { emitCountedLoopSafety, emitPairedLoopSafety, } from "./counted-loops.js"; -import { emitBytesLoopVersionGuard } from "./bytes-loop-versions.js"; +import { emitBytesLoopVersionGuard, type BytesLoopVersion } from "./bytes-loop-versions.js"; import { mangleLocal } from "../mangle.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import type { LlValue } from "./expr-context.js"; @@ -795,6 +795,16 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { break; } case "while": { + const version = + emitter.bytesLoopVersionsEnabled && + emitter.bytesLoopVersioning.size < MAX_BYTES_LOOP_VERSION_DEPTH && + !emitter.bytesLoopVersioning.has(s) + ? emitter.matchBytesLoopVersion(s, null) + : null; + if (version) { + emitVersionedLoop(emitter, s, version); + break; + } const workerBudget = emitter.workerLoopBudget(s); const le = B.newLabel("loop.e"); emitter.emitLoopCopies(s, true, le, (exit) => { @@ -981,35 +991,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { : countedLoop; const version = versionable ? emitter.matchBytesLoopVersion(s, versionCounted) : null; if (version) { - 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 originalBounds = emitter.bytesBounds, - originalOwned = emitter.bytesOwned, - originalRanges = emitter.integerRanges; - 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) emitter.provenCountedGuards.add(s); - emitter.emitStmt(s); - B.br(done); - } finally { - emitter.bytesBounds = originalBounds; - emitter.bytesOwned = originalOwned; - emitter.integerRanges = originalRanges; - emitter.provenCountedGuards.delete(s); - emitter.bytesLoopVersioning.delete(s); - } - B.startBlock(done); + emitVersionedLoop(emitter, s, version); break; } let countedJoin: string | null = null; @@ -1896,6 +1878,45 @@ const SPECULATION_BAILS = 8; * 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 * 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). */ +function emitVersionedLoop( + emitter: LlEmitter, + s: IrStmt & { kind: "for" | "while" }, + version: BytesLoopVersion, +): void { + const B = emitter.B; + 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 originalBounds = emitter.bytesBounds, + originalOwned = emitter.bytesOwned, + originalRanges = emitter.integerRanges; + 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) emitter.provenCountedGuards.add(s); + emitter.emitStmt(s); + B.br(done); + } finally { + emitter.bytesBounds = originalBounds; + emitter.bytesOwned = originalOwned; + emitter.integerRanges = originalRanges; + emitter.provenCountedGuards.delete(s); + emitter.bytesLoopVersioning.delete(s); + } + B.startBlock(done); +} + export function emitLoopCopies( emitter: LlEmitter, loop: Extract, diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index c1cf66af4..e4e37ec4f 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -3843,7 +3843,7 @@ export class LlEmitter { /** A binding's storage: a module global, a plain local slot, or a boxed * local (the slot holds the capture BOX; access goes through it). */ matchBytesLoopVersion( - s: IrStmt & { kind: "for" }, + s: IrStmt & { kind: "for" | "while" }, counted: IntegerCountedForLoop | null, ): ReturnType { const fn = this.bytesLoopFunction; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6998-typed-array-while-loop-versions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6998-typed-array-while-loop-versions.ts.json new file mode 100644 index 000000000..f5cfba0cc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6998-typed-array-while-loop-versions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6998-typed-array-while-loop-versions.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6998-typed-array-while-loop-versions.ts b/tests/corpus/6998-typed-array-while-loop-versions.ts new file mode 100644 index 000000000..383a2437f --- /dev/null +++ b/tests/corpus/6998-typed-array-while-loop-versions.ts @@ -0,0 +1,149 @@ +// While loops that scan typed arrays with a counter below a bound: scanners +// with nested loops and `&&` conditions, `| 0` increments, look-behind and +// look-ahead reads, writes, DataView reads, string-length bounds, and +// bounds or starts past the array, fractional, negative, -0 or NaN. + +function words(bytes: Uint8Array, end: number): number { + let pos = 0; + let count = 0; + while (pos < end) { + while (pos < end && (bytes[pos] === 32 || bytes[pos] === 10)) pos++; + if (pos < end) count++; + while (pos < end && bytes[pos] !== 32 && bytes[pos] !== 10) pos++; + } + return count; +} + +function identifiers(chars: Uint16Array, start: number, end: number): string { + let pos = start; + let count = 0; + let mix = 0; + while (pos < end) { + let hash = 0x811c9dc5 | 0; + while (pos < end) { + const c = chars[pos]!; + if (!((c >= 97 && c <= 122) || c === 95)) break; + hash = Math.imul(hash ^ c, 0x01000193); + pos = (pos + 1) | 0; + } + mix = (mix + hash) | 0; + count++; + pos = (pos + 1) | 0; + } + return `${count} ${mix >>> 0} ${pos}`; +} + +function around(values: Int16Array, start: number, end: number): number[] { + const out: number[] = []; + let i = start; + while (i <= end) { + out.push(values[i - 1]! + values[i + 2]! * 2); + i += 1; + } + return out; +} + +function fill(out: Float32Array, end: number, value: number): number { + let i = 0; + while (i < end) { + out[i] = value + i; + if (i < end - 1 && out[i] > 2) { + i += 2; + continue; + } + i++; + } + return i; +} + +function afterInner(bytes: Uint8Array): number { + let pos = 0; + let sum = 0; + while (pos < bytes.length) { + while (pos < bytes.length && bytes[pos] !== 0) pos++; + // The inner loop may stop at the length: this read stays checked. + sum += bytes[pos] ?? -1; + pos++; + } + return sum; +} + +function firstAbove(samples: Float64Array, limit: number): number { + let i = 0; + while (i < samples.length) { + if (samples[i]! > limit) return i; + i = i + 1; + } + return -1; +} + +function halves(view: DataView, end: number): number { + let at = 0; + let total = 0; + while (at < end) { + total += view.getUint16(at, true); + at += 2; + } + return total; +} + +function letters(text: string, codes: Uint8Array): number { + let i = 0; + let sum = 0; + while (i < text.length) { + sum += codes[i]! * (text.charCodeAt(i) & 7); + i++; + } + return sum; +} + +function notCounters(bytes: Uint8Array): string { + let i = 1; + let doubled = 0; + while (i < bytes.length) { + doubled += bytes[i]!; + i = i * 2; + } + let j = bytes.length - 1; + let down = 0; + while (j < bytes.length && j >= 0) { + down += bytes[j]!; + j--; + } + return `${doubled} ${down}`; +} + +const text = "let alpha = beta_gamma\nreturn delta "; +const bytes = new Uint8Array(text.length); +const chars = new Uint16Array(text.length); +for (let i = 0; i < text.length; i++) { + bytes[i] = text.charCodeAt(i); + chars[i] = text.charCodeAt(i); +} +console.log("words", words(bytes, bytes.length), words(bytes, 10), words(bytes, bytes.length + 5), words(bytes, 7.5), words(bytes, NaN)); +console.log("identifiers", identifiers(chars, 0, chars.length)); +console.log("identifiers past end", identifiers(chars, 4, chars.length + 3)); +console.log("identifiers starts", identifiers(chars, -2, 9), identifiers(chars, 2.5, 12), identifiers(chars, -0, 6)); + +const values = new Int16Array([5, -6, 7, -8, 9, -10, 11]); +console.log("around", around(values, 1, 4).join(","), around(values, 0, 6).join(","), around(values, -1, 1).join(",")); + +const floats = new Float32Array(6); +console.log("fill", fill(floats, 6, 0.5), floats.join(",")); +const short = new Float32Array(3); +console.log("fill past end", fill(short, 5, 1), short.join(",")); + +console.log("after inner", afterInner(new Uint8Array([1, 2, 0, 3, 0, 4, 5]))); +console.log("first above", firstAbove(new Float64Array([0.5, 1.5, 2.5]), 1), firstAbove(new Float64Array([0.5]), 1)); + +const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); +const view = new DataView(buffer.buffer); +console.log("halves", halves(view, 8)); +try { + console.log("halves past end", halves(view, 10)); +} catch (error) { + console.log((error as Error).name, (error as Error).message); +} + +console.log("letters", letters("abcdef", new Uint8Array([1, 2, 3, 4, 5, 6])), letters("abcdefgh", new Uint8Array([1, 2, 3]))); +console.log("not counters", notCounters(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))); diff --git a/tests/harness/corpus-costs/6998-typed-array-while-loop-versions.ts.json b/tests/harness/corpus-costs/6998-typed-array-while-loop-versions.ts.json new file mode 100644 index 000000000..204a01a83 --- /dev/null +++ b/tests/harness/corpus-costs/6998-typed-array-while-loop-versions.ts.json @@ -0,0 +1 @@ +{ "plain": 3700, "san": 5000 } From c9ae4d80196eeabdacc7574f3dd216bf0422f32e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:55:30 -0500 Subject: [PATCH 19/45] Look up spawnSync commands on the replacement environment's PATH With an `env` option, spawnSync searched the parent's PATH for a command without a '/'. Node (libuv) searches the PATH of the child's environment, or the default path when that environment has none, so a command only on the child's PATH ran as ENOENT and one only on the parent's PATH ran where Node reports ENOENT. The lookup now follows libuv: each PATH entry in order, an empty entry as the current directory, and EACCES when a candidate exists but cannot run. --- packages/runtime/src/scr_child.c | 62 +++++++++++++++++++++++++++-- tests/corpus/7030-spawn-sync-env.ts | 19 +++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index 387885c42..df60fcb26 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -2907,6 +2907,7 @@ void scr_children_poll(void) { #include #include #include +#include #include #include #include @@ -3111,8 +3112,55 @@ static ScrSpawnRes *scr_spawn_res_new(bool has_status, double status, static char **scr_exec_envp(ScrArr *pairs); static void scr_exec_envp_free(char **envp); +/* The executable `file` names when `envp` replaces the child's + * environment, found as libuv finds it: a name with a '/' is used as + * given; otherwise each entry of the replacement's PATH (an empty entry + * is the current directory), or of the default path when the replacement + * has no PATH, is tried in order. Returns a malloc'd path, or NULL with + * *err set: EACCES when a candidate exists but cannot run, else ENOENT. */ +static char *scr_spawn_path_lookup(const char *file, char *const *envp, int *err) { + if (strchr(file, '/')) { + char *copy = strdup(file); + if (!copy) scr_child_oom(); + return copy; + } + const char *path = "/usr/bin:/bin"; + for (char *const *e = envp; *e; e++) { + if (strncmp(*e, "PATH=", 5) == 0) { + path = *e + 5; + break; + } + } + size_t file_len = strlen(file); + bool denied = false; + for (const char *dir = path;;) { + const char *end = strchr(dir, ':'); + size_t dir_len = end ? (size_t)(end - dir) : strlen(dir); + const char *prefix = dir_len ? dir : "."; + size_t prefix_len = dir_len ? dir_len : 1; + char *candidate = malloc(prefix_len + 1 + file_len + 1); + if (!candidate) scr_child_oom(); + memcpy(candidate, prefix, prefix_len); + candidate[prefix_len] = '/'; + memcpy(candidate + prefix_len + 1, file, file_len + 1); + struct stat st; + if (stat(candidate, &st) == 0) { + if (S_ISREG(st.st_mode) && access(candidate, X_OK) == 0) return candidate; + denied = true; + } else if (errno == EACCES) { + denied = true; + } + free(candidate); + if (!end) break; + dir = end + 1; + } + *err = denied ? EACCES : ENOENT; + return NULL; +} + /* env_pairs: NULL inherits the parent's environment; else [k,v,...] - * replaces it, as Node's `env` option does. */ + * replaces it, as Node's `env` option does, and the command is looked up + * on the replacement's PATH (scr_spawn_path_lookup). */ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeout_ms, int killsig, int in_mode, int out_mode, int err_mode, ScrArr *env_pairs) { @@ -3152,8 +3200,16 @@ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeou char **argv = scr_child_argv(cmd, args); char **envp = env_pairs != NULL ? scr_exec_envp(env_pairs) : NULL; pid_t pid = -1; - int spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, - envp != NULL ? envp : environ); + int spawn_err; + if (envp != NULL) { + char *resolved = scr_spawn_path_lookup(cmd->data, envp, &spawn_err); + if (resolved) { + spawn_err = posix_spawn(&pid, resolved, &fa, NULL, argv, envp); + free(resolved); + } + } else { + spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, environ); + } posix_spawn_file_actions_destroy(&fa); free(argv); scr_exec_envp_free(envp); diff --git a/tests/corpus/7030-spawn-sync-env.ts b/tests/corpus/7030-spawn-sync-env.ts index e613c81f0..0ab001b8f 100644 --- a/tests/corpus/7030-spawn-sync-env.ts +++ b/tests/corpus/7030-spawn-sync-env.ts @@ -1,6 +1,9 @@ // spawnSync's env option replaces the child's environment, alone or with // the other options. import { spawnSync } from "node:child_process"; +import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; const merged = spawnSync("sh", ["-c", 'echo "$GREETING $HOME_SET"'], { env: { ...process.env, GREETING: "hello", HOME_SET: process.env.HOME ? "yes" : "no" }, @@ -26,3 +29,19 @@ console.log(quiet.status, quiet.stderr.toString().trim(), quiet.stdout.toString( const missing = spawnSync("/nonexistent/tool", [], { env: { A: "1" } }); console.log(missing.status, missing.error?.message); + +// The command is found on the replacement environment's PATH, or on the +// default path when the replacement has none, not on the parent's PATH. +const dir = mkdtempSync(join(tmpdir(), "scr-spawn-path-")); +writeFileSync(join(dir, "child-only-tool"), "#!/bin/sh\necho child-only\n"); +chmodSync(join(dir, "child-only-tool"), 0o755); +writeFileSync(join(dir, "not-executable"), "#!/bin/sh\necho never\n"); +const viaPath = spawnSync("child-only-tool", [], { env: { PATH: `/nonexistent:${dir}` }, encoding: "utf8" }); +console.log(viaPath.status, viaPath.stdout.trim()); +const defaultPath = spawnSync("sh", ["-c", "echo default"], { env: { A: "1" }, encoding: "utf8" }); +console.log(defaultPath.status, defaultPath.stdout.trim()); +const notOnPath = spawnSync("sh", ["-c", "echo never"], { env: { PATH: dir }, encoding: "utf8" }); +console.log(notOnPath.status, notOnPath.error?.message); +const denied = spawnSync("not-executable", [], { env: { PATH: dir }, encoding: "utf8" }); +console.log(denied.status, denied.error?.message); +rmSync(dir, { recursive: true }); From 05acb4d24783f63cabf49cdc177d138fa5ea0f70 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:58:47 -0500 Subject: [PATCH 20/45] Update the DiffieHellman runtime test for the prime search test_dh.c includes scr_dh.c and still called sd_generate_safe_prime without its new top_two argument, so dh.test.ts failed to compile. It now passes false, as the DiffieHellman paths do, and a new case checks generatePrime's search: the sizes and add forms with one possible result, top-two-bit safe-prime starts, and checks above OpenSSL's round count. --- packages/runtime/test/test_dh.c | 54 ++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/runtime/test/test_dh.c b/packages/runtime/test/test_dh.c index aa8f175a3..f459f1047 100644 --- a/packages/runtime/test/test_dh.c +++ b/packages/runtime/test/test_dh.c @@ -199,7 +199,7 @@ static void test_generate(void) { mbedtls_mpi_lset(&g, 2); for (size_t i = 0; i < sizeof adds / sizeof adds[0]; i++) { for (int trial = 0; trial < 2; trial++) { - bool ok = sd_generate_safe_prime(&p, 512, adds[i], adds[i] - 1); + bool ok = sd_generate_safe_prime(&p, 512, adds[i], adds[i] - 1, false); mbedtls_mpi_uint r = 0; ok = ok && mbedtls_mpi_bitlen(&p) == 512 && mbedtls_mpi_mod_int(&r, &p, adds[i]) == 0 && r == adds[i] - 1; mbedtls_mpi_copy(&q, &p); @@ -217,12 +217,64 @@ static void test_generate(void) { mbedtls_mpi_free(&g); } +/* generatePrime's search: the sizes and add forms with one possible + * result, top-two-bit safe-prime starts, and checks above OpenSSL's + * round count. */ +static void test_generate_prime(void) { + static const struct { + size_t bits; + bool safe; + int add, rem; + int want; + } cases[] = { + {2, false, 0, 0, 3}, {3, false, 0, 0, 7}, {4, false, 0, 0, 13}, {3, true, 0, 0, 7}, + {6, true, 0, 0, 59}, {7, true, 0, 0, 107}, {8, false, 200, 1, 401}, {8, false, 128, 0, 257}, + {5, false, 16, 3, 19}, + }; + mbedtls_mpi p, add, rem, q; + mbedtls_mpi_init(&p); + mbedtls_mpi_init(&add); + mbedtls_mpi_init(&rem); + mbedtls_mpi_init(&q); + for (size_t i = 0; i < sizeof cases / sizeof cases[0]; i++) { + mbedtls_mpi_lset(&add, cases[i].add); + mbedtls_mpi_lset(&rem, cases[i].rem); + bool ok = sd_generate_prime(&p, cases[i].bits, cases[i].safe, cases[i].add ? &add : NULL, + cases[i].rem ? &rem : NULL) && + mbedtls_mpi_cmp_int(&p, cases[i].want) == 0; + char what[96]; + snprintf(what, sizeof what, "generatePrime(%zu, safe %d, add %d, rem %d) is %d", cases[i].bits, cases[i].safe, + cases[i].add, cases[i].rem, cases[i].want); + check(ok, what); + } + for (int trial = 0; trial < 2; trial++) { + bool ok = sd_generate_safe_prime(&p, 128, 12, 11, true) && mbedtls_mpi_bitlen(&p) == 128 && + mbedtls_mpi_get_bit(&p, 126) == 1; + mbedtls_mpi_copy(&q, &p); + mbedtls_mpi_shift_r(&q, 1); + ok = ok && mbedtls_mpi_is_prime_ext(&p, 40, sd_random, NULL) == 0 && + mbedtls_mpi_is_prime_ext(&q, 40, sd_random, NULL) == 0; + check(ok, "a 128-bit safe prime with its top two bits set"); + } + ScDhSmallPrimes *small = sd_small_primes(); + mbedtls_mpi_read_string(&q, 10, "3215031751"); + check(!sd_is_prime_checks(small, &q, 200), "200 rounds reject a strong pseudoprime to 2, 3, 5 and 7"); + mbedtls_mpi_read_string(&q, 10, "2305843009213693951"); + check(sd_is_prime_checks(small, &q, 200), "200 rounds accept 2^61 - 1"); + free(small); + mbedtls_mpi_free(&p); + mbedtls_mpi_free(&add); + mbedtls_mpi_free(&rem); + mbedtls_mpi_free(&q); +} + int main(void) { test_mont_pow(); test_is_prime(); test_check_params(); test_long_exponent(); test_generate(); + test_generate_prime(); fprintf(stderr, "%ld/%ld cases passed\n", total - failed, total); return failed ? 1 : 0; } From c43d4002e71f3c87a8b7bee79c12c02793bf1c2b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 09:59:57 -0500 Subject: [PATCH 21/45] Skip only always-throwing calls as record producers in the key-order witness The witness skipped every libCall whose signature result is VOID. VOID is also the signature of runtime calls that take their record type from the use site and build the record at run time, such as net.serverAddress (`server.address()`). A literal of the same shape then set the shape's key order, and the runtime record enumerated in the literal's order instead of Node's (`port, family, address` for `address, family, port`). The witness now skips only the calls in ALWAYS_THROW_LIB_FNS, which never produce a value. The set moves from validate.ts's result-type check to builtin-effects.ts, and both use it. --- .../lowering/key-order-witness.test.ts | 30 +++++++++++++++++++ .../frontend/lowering/key-order-witness.ts | 11 +++---- packages/compiler/src/ir/builtin-effects.ts | 22 ++++++++++++++ packages/compiler/src/ir/validate.ts | 29 ++---------------- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/key-order-witness.test.ts b/packages/compiler/src/frontend/lowering/key-order-witness.test.ts index de16e5d61..8632bad47 100644 --- a/packages/compiler/src/frontend/lowering/key-order-witness.test.ts +++ b/packages/compiler/src/frontend/lowering/key-order-witness.test.ts @@ -157,6 +157,36 @@ test("a synthesized construction pins today's table", () => { expect(f.order(ab)).toEqual(["a", "b"]); }); +test("a runtime builder typed by its use site pins today's table", () => { + const f = fixture(); + const ab = f.record( + [ + ["a", F64], + ["b", F64], + ], + ["a", "b"], + ); + // net.serverAddress's signature result is VOID: the call takes its record + // type from its use site, and the runtime builds the record in that order. + const built: IrExpr = { kind: "libCall", fn: "net.serverAddress", args: [], type: ab, loc }; + f.run([observe(f.literal(ab, ["b", "a"])), observe(built)]); + expect(f.order(ab)).toEqual(["a", "b"]); +}); + +test("an always-throwing call typed as the record leaves its literals' order", () => { + const f = fixture(); + const ab = f.record( + [ + ["a", F64], + ["b", F64], + ], + ["a", "b"], + ); + const thrown: IrExpr = { kind: "libCall", fn: "error.nodeThrow", args: [], type: ab, loc }; + f.run([observe(f.literal(ab, ["b", "a"])), observe(thrown)]); + expect(f.order(ab)).toEqual(["b", "a"]); +}); + test("a checked conversion alone pins today's table", () => { const f = fixture(); const ab = f.record( diff --git a/packages/compiler/src/frontend/lowering/key-order-witness.ts b/packages/compiler/src/frontend/lowering/key-order-witness.ts index 7ce8ae074..4adfb87ab 100644 --- a/packages/compiler/src/frontend/lowering/key-order-witness.ts +++ b/packages/compiler/src/frontend/lowering/key-order-witness.ts @@ -45,7 +45,7 @@ import type { IrExpr, IrFunction, IrRecordShape, IrStmt, IrType } from "../../ir import { shapeHasAccessorSlots, typeEquals, UNDEFINED_T } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild, everyTypeChild } from "../../ir/traverse.js"; import type { Lowerer } from "./lowerer.js"; -import { LIB_FN_SIGS } from "../../ir/builtin-signatures.js"; +import { ALWAYS_THROW_LIB_FNS } from "../../ir/builtin-effects.js"; /** One property of an object literal, in source order. */ export type KeyOrderSegment = @@ -313,10 +313,11 @@ export function applyKeyOrderWitnesses(lowerer: Lowerer, fns: readonly IrFunctio // Runtime surfaces (console, util.format, workers) that take a // record may walk its keys; runtime builders make new records. for (const arg of e.args) observedRoots.push(arg.type); - // A void runtime call typed by its use site is a throw standing in - // for a value (`error.nodeThrow` in a narrowing ternary): it never - // produces one. - if (LIB_FN_SIGS[e.fn].result.kind !== "void") producedBy(e.type, true); + // An always-throwing call stands in for a value (`error.nodeThrow` + // in a narrowing ternary) and never produces one. Other calls + // whose signature result is VOID are typed by their use site and + // build the record at run time (`server.address()`). + if (!ALWAYS_THROW_LIB_FNS.has(e.fn)) producedBy(e.type, true); return; case "intrinsic": // Intrinsics hand back values built elsewhere, except allSettled's diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 16db45b6c..c2194a13c 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -1001,3 +1001,25 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "crypto.createSign", "crypto.createVerify", ]); + +/** libCall members that always throw. Their result type is the replaced + * expression's own and is never materialized: global.undefRead's is the + * declared type of the undefined global; the others stand in for a value + * of the expression they replace. The fs Chk ladders qualify: every + * validation failure throws Node's typed error, and a full pass throws the + * trailing compiler-rendered fence. */ +export const ALWAYS_THROW_LIB_FNS: ReadonlySet = new Set([ + "global.undefRead", + "error.nodeThrow", + "error.argTypeThrow", + "error.propTypeThrow", + "fs.mkdtempChk", + "fs.readFileChk", + "fs.opendirChk", + "fs.watchFileChk", + "fs.lchmodChk", + "fs.readChk", + "fs.streamOptsChk", + "net.connectOptsChk", + "tls.caCertsChk", +]); diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index bb36c7007..163c2a41c 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -61,6 +61,7 @@ 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 { ALWAYS_THROW_LIB_FNS } from "./builtin-effects.js"; /** The promisified crypto calls' value kinds besides checked-dynamic. */ const CRYPTO_PROMISE_VALUES: Readonly> = { @@ -5345,32 +5346,8 @@ function validateFunction( const callback = e.args[e.args.length - 1]?.type; if (callback?.kind !== "func") err(`libCall ${e.fn} callback must be a function`, e.loc); } - if (e.fn === "global.undefRead") { - // Always throws — the result type is whatever the declared type - // of the undefined global mapped to (never materialized). - return true; - } - if ( - e.fn === "error.nodeThrow" || - e.fn === "error.argTypeThrow" || - e.fn === "error.propTypeThrow" || - e.fn === "fs.mkdtempChk" || - e.fn === "fs.readFileChk" || - e.fn === "fs.opendirChk" || - e.fn === "fs.watchFileChk" || - e.fn === "fs.lchmodChk" || - e.fn === "fs.readChk" || - e.fn === "fs.streamOptsChk" || - e.fn === "net.connectOptsChk" || - e.fn === "tls.caCertsChk" - ) { - // Always throws — the result type is the replaced expression's - // own (never materialized; the global.undefRead pattern). The - // fs Chk ladders qualify: every validation failure throws - // Node's typed error, and a full pass throws the trailing - // compiler-rendered fence. - return true; - } + // Always throws: the result type is never materialized. + if (ALWAYS_THROW_LIB_FNS.has(e.fn)) return true; if (e.fn === "error.new" || e.fn === "error.newOptions") { // Which builtin the runtime constructs is named by the result type. if (!isBuiltinErrorObject(e.type)) { From e4dc0900d7f451963914422228bdebc18e4b1e20 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:09:08 -0500 Subject: [PATCH 22/45] Fence arguments.length in function expressions that call themselves by name A function expression stored in a function type with more parameters folds `arguments.length` to that type's parameter count, the count every call through the slot passes. A named expression that calls itself through its own name passes only its declared parameters there, so no constant answers both calls. Such a read now reports SC1090 with the reason, and expressions that do not refer to their own name keep the fold. --- .../lowering/expressions/property-access.ts | 38 ++++++++++++++++--- .../arguments-length-self-call.ts.json | 6 +++ .../diagnostics/arguments-length-self-call.ts | 8 ++++ .../arguments-length-self-call.ts.txt | 6 +++ 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/arguments-length-self-call.ts.json create mode 100644 tests/diagnostics/arguments-length-self-call.ts create mode 100644 tests/harness/__snapshots__/arguments-length-self-call.ts.txt diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 44d38acd4..5df3c7fe0 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -669,12 +669,17 @@ export function lowerPropertyAccessExpr( const declared = (fn as ts.FunctionLikeDeclaration).parameters.nodes.filter( (p) => !isThisParameter(p), ).length; - return { - kind: "numLit", - value: Math.max(declared, contextualArgumentCount(lowerer, fn) ?? 0), - type: F64, - loc, - }; + const count = Math.max(declared, contextualArgumentCount(lowerer, fn) ?? 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)) { + lowerer.unsupported( + "SC1090", + expr, + "'arguments.length' in a function expression that is called both through its own name and through a function type with more parameters (the count varies per call)", + ); + } + return { kind: "numLit", value: count, type: F64, loc }; } lowerer.unsupported( "SC1090", @@ -4442,6 +4447,27 @@ function lowerPromiseConstructorRead( return null; } +/** Whether a named function expression refers to itself by name in its + * body (a recursive call, or the function escaping under its own name). */ +function referencesOwnName(lowerer: Lowerer, fn: ts.Node): boolean { + if (!ts.isFunctionExpression(fn) || fn.name === undefined || fn.body === undefined) return false; + const self = lowerer.checker.getSymbolAtLocation(fn.name); + if (self === undefined) return false; + const name = fn.name.text; + let found = false; + ts.walkPreorder(fn.body, (node) => { + if (found) return "stop"; + if ( + ts.isIdentifier(node) && + node.text === name && + lowerer.checker.getSymbolAtLocation(node) === self + ) + found = true; + return undefined; + }); + return found; +} + /** 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 diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/arguments-length-self-call.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/arguments-length-self-call.ts.json new file mode 100644 index 000000000..8ed5027e5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/arguments-length-self-call.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/arguments-length-self-call.ts" + ], + "diags": [] +} diff --git a/tests/diagnostics/arguments-length-self-call.ts b/tests/diagnostics/arguments-length-self-call.ts new file mode 100644 index 000000000..3afc2cb33 --- /dev/null +++ b/tests/diagnostics/arguments-length-self-call.ts @@ -0,0 +1,8 @@ +// `arguments.length` in a function expression stored in a slot with more +// parameters counts that slot's arguments, but a call through the +// expression's own name passes only the declared ones: no constant answers +// both, so the read fences. +const count: (a: number, b: number) => number = function self(a: number): number { + return a > 0 ? self(a - 1) + arguments.length : arguments.length; +}; +console.log(count(2, 0)); diff --git a/tests/harness/__snapshots__/arguments-length-self-call.ts.txt b/tests/harness/__snapshots__/arguments-length-self-call.ts.txt new file mode 100644 index 000000000..7e94b56c6 --- /dev/null +++ b/tests/harness/__snapshots__/arguments-length-self-call.ts.txt @@ -0,0 +1,6 @@ +arguments-length-self-call.ts:6:32 - error SC1090: 'arguments.length' in a function expression that is called both through its own name and through a function type with more parameters (the count varies per call) are not supported yet + + 5 | const count: (a: number, b: number) => number = function self(a: number): number { + 6 | return a > 0 ? self(a - 1) + arguments.length : arguments.length; + | ^~~~~~~~~~~~~~~~ + 7 | }; \ No newline at end of file From affe386bbf62de66812386b9fa07fbba1d8f37fd Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:09:43 -0500 Subject: [PATCH 23/45] Throw for every object on the right of an arrow instanceof, and give blocked bodies their this - An arrow function or method on the right of an untyped `instanceof` has no prototype. Node throws "Function has non-object prototype 'undefined' in instanceof check" for any object, but the runtime threw only for plain objects, arrays and functions, and answered false for typed arrays, native handles, promises and typed references. It now answers false only for primitives. - Coverage lowers the body of a signature-blocked function for its diagnostics. A declared `this` parameter now gives that body its receiver, as lowerFunction does, so `this.label` reports nothing. Before, each use reported SC1080. --- .../src/frontend/lowering/lower-functions.ts | 3 +++ packages/runtime/src/scr_json.c | 10 +++++++--- tests/corpus/7005-dyn-constructor-instanceof/main.ts | 3 ++- .../node_modules/tag-types/index.d.ts | 1 + .../node_modules/tag-types/index.js | 10 ++++++++++ tests/coverage-fixtures/blocked-signature-body.ts | 4 ++++ tests/harness/coverage.test.ts | 12 ++++++++---- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index ea7d7957b..c1cca9c64 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -893,6 +893,9 @@ export function blockedBodyDiagnostics( lowerer.fnStack.push(ctx); let internal = false; try { + // A declared `this` parameter gives the body its receiver, as + // lowerFunction declares it. + if (decl.parameters.nodes.some(isThisParameter)) declareCallReceiver(lowerer, decl, false); for (const param of decl.parameters.nodes) { if (isThisParameter(param)) continue; const declaredParam = lowersCleanly(lowerer, () => { diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 906be0ccd..fbfcade66 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -3968,10 +3968,14 @@ bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const Sc bool undefined_prototype = prototype->kind == SCR_DYN_UNDEF; scr_dyn_release(prototype); /* A function the program compiled with no prototype (an arrow function - * or a method): Node's TypeError for an object, false for a primitive. - * The runtime's own constructors carry "native:" signatures. */ + * or a method): false for a primitive, and Node's TypeError for every + * object, typed arrays, native handles, promises and typed references + * included. The runtime's own constructors carry "native:" signatures. */ if (undefined_prototype && (!callee->v.fn.sig || strncmp(callee->v.fn.sig, "native:", 7) != 0)) { - if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_ARR && value->kind != SCR_DYN_FUNC) return false; + if (value->kind == SCR_DYN_UNDEF || value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_BOOL || + value->kind == SCR_DYN_NUM || value->kind == SCR_DYN_STR || value->kind == SCR_DYN_BIGINT || + value->kind == SCR_DYN_SYMBOL) + return false; static const char message[] = "Function has non-object prototype 'undefined' in instanceof check"; scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); return false; diff --git a/tests/corpus/7005-dyn-constructor-instanceof/main.ts b/tests/corpus/7005-dyn-constructor-instanceof/main.ts index c32a820c2..21fcbbd26 100644 --- a/tests/corpus/7005-dyn-constructor-instanceof/main.ts +++ b/tests/corpus/7005-dyn-constructor-instanceof/main.ts @@ -3,9 +3,10 @@ // an ES5 constructor's prototype, at module load and in calls, and throws a // TypeError for an arrow function, which has no prototype, when the value // is an object. -import { arrowCheck, describe, rejects, tags } from "tag-types"; +import { arrowCheck, arrowObjects, describe, rejects, tags } from "tag-types"; console.log(tags()); console.log(describe("{}"), describe("[1]"), describe("null"), describe('"s"')); console.log(rejects('{"tag":"!x"}')); console.log(arrowCheck("{}"), arrowCheck("1")); +console.log(arrowObjects()); diff --git a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts index adeea728e..5b451adfa 100644 --- a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts +++ b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.d.ts @@ -2,3 +2,4 @@ export declare function describe(json: string): string; export declare function tags(): string; export declare function rejects(json: string): string; export declare function arrowCheck(json: string): string; +export declare function arrowObjects(): string; diff --git a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js index 20eee362f..81165bd58 100644 --- a/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js +++ b/tests/corpus/7005-dyn-constructor-instanceof/node_modules/tag-types/index.js @@ -59,3 +59,13 @@ module.exports.arrowCheck = function (json) { return error.name + ": " + error.message; } }; +// Every object reaches the TypeError, typed arrays, promises and Maps too. +module.exports.arrowObjects = function () { + return [new Uint8Array(2), Promise.resolve(1), new Map(), [1]].map(function (value) { + try { + return String(value instanceof make); + } catch (error) { + return error.name; + } + }).join(","); +}; diff --git a/tests/coverage-fixtures/blocked-signature-body.ts b/tests/coverage-fixtures/blocked-signature-body.ts index 7f8db4eb8..2c37484e0 100644 --- a/tests/coverage-fixtures/blocked-signature-body.ts +++ b/tests/coverage-fixtures/blocked-signature-body.ts @@ -13,3 +13,7 @@ function unused(target: WeakRef): number { return extra === undefined ? 0 : 1; } console.log(measure(new WeakRef({}), "abc")); +// A declared `this` parameter gives the body its receiver. +function described(this: { label: string }, target: WeakRef): string { + return this.label + String(target); +} diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index 40b55b078..3ed562aea 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -194,17 +194,21 @@ test("the body of a signature-blocked function reports its diagnostics", () => { "SC2020 'WeakRef' is part of the standard library types but has no scriptc lowering yet", "SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet", ]); - // Nothing calls unused: its signature and body report as unreached. + // Nothing calls unused or described: their signatures and bodies report + // as unreached. described's declared `this` is its receiver, so + // `this.label` reports nothing. expect(sites(coverage.unreached?.diagnostics ?? [])).toEqual([ "SC2004 uses of 'extra' inherit the blocker on its declaration", + "SC2004 uses of 'target' inherit the blocker on its declaration", + "SC2020 'WeakRef' is part of the standard library types but has no scriptc lowering yet", "SC2020 'WeakRef' is part of the standard library types but has no scriptc lowering yet", "SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet", ]); // The bodies' statements still count once each, as not static. const un = coverage.unreached?.stats; - expect(coverage.stats.functionsSkipped + (un?.functionsSkipped ?? 0)).toBe(2); - expect(coverage.stats.statementsTotal + (un?.statementsTotal ?? 0)).toBe(6); - expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(6); + expect(coverage.stats.functionsSkipped + (un?.functionsSkipped ?? 0)).toBe(3); + expect(coverage.stats.statementsTotal + (un?.statementsTotal ?? 0)).toBe(7); + expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(7); }); test("deferred fences in a module's top-level code report as running at startup", () => { From 0078dc2c46c93e6443fae1e3296456129ba190e0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:10:59 -0500 Subject: [PATCH 24/45] Check the elements a spread push stores into an evolving empty array The evolving-array check made the binding checked-dynamic for any spread write, so `xs.push(...values)` of an array whose elements match the binding's agreed element type turned a typed `number[]` into a checked-dynamic array, and the spread call through it was refused with SC1090 "spread arguments in calls through 'unknown' values". A spread now stores the source array's element type, or each of a tuple's element types, and the binding stays typed when they match. A spread of another iterable still makes it checked-dynamic. --- .../src/frontend/lowering/lower-stmts.ts | 27 ++++++++++++++----- tests/corpus/7006-evolving-array-aliases.ts | 9 +++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 29086d326..cc01d7401 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -4800,9 +4800,9 @@ export function lowerVarDeclList( * it, and reads inside closures as the unsettled array. When every read * with a settled element type maps to the same array type, the binding has * that type. When reads disagree, a write (`xs.push(v)`, `xs.unshift(v)`, - * `xs[i] = v`) stores a value that type's element does not hold, or the - * binding is reassigned, it is checked-dynamic, as the same binding is at - * module scope. Null for other bindings. */ + * `xs.push(...values)`, `xs[i] = v`) stores a value that type's element does + * not hold, or the binding is reassigned, it is checked-dynamic, as the same + * binding is at module scope. Null for other bindings. */ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrType | null { if (!ts.isIdentifier(decl.name) || decl.initializer === undefined) return null; let initializer: ts.Expression = decl.initializer; @@ -4870,11 +4870,24 @@ function evolvingArrayType(lowerer: Lowerer, decl: ts.VariableDeclaration): IrTy result = mapped; } if (result === null || result.kind !== "array") return DYN; + // The element types a write stores: its value's, or for a spread + // (`xs.push(...values)`) the source array's element or tuple's elements. + // Another spread source stores elements this check cannot see. + const storedTypes = (value: ts.Expression): ts.Type[] | null => { + if (!ts.isSpreadElement(value)) return [lowerer.typeOf(value)]; + const source = lowerer.typeOf(value.expression); + if (lowerer.checker.isArrayType(source) || lowerer.checker.isTupleType(source)) + return [...lowerer.checker.getTypeArguments(source as ts.TypeReference)]; + return null; + }; for (const value of written) { - if (ts.isSpreadElement(value)) return DYN; - const t = lowerer.mapTypeOf(lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(value))); - if (!t || (!typeEquals(t, result.elem) && lowerer.widthLiftPlan(t, result.elem) === null)) - return DYN; + const stored = storedTypes(value); + if (stored === null) return DYN; + for (const type of stored) { + const t = lowerer.mapTypeOf(lowerer.checker.getBaseTypeOfLiteralType(type)); + if (!t || (!typeEquals(t, result.elem) && lowerer.widthLiftPlan(t, result.elem) === null)) + return DYN; + } } return result; } diff --git a/tests/corpus/7006-evolving-array-aliases.ts b/tests/corpus/7006-evolving-array-aliases.ts index 4810c440e..215b3f3c5 100644 --- a/tests/corpus/7006-evolving-array-aliases.ts +++ b/tests/corpus/7006-evolving-array-aliases.ts @@ -68,3 +68,12 @@ console.log(chain()); console.log(viaAlias(), "|", letAlias()); console.log(nested(true), "|", nested(false), "|", elementWrite()); console.log(agreeing(), "|", passed()); + +function spreadSame(): number { + const xs = []; + xs.push(1); + const more = [2, 3]; + xs.push(...more); + return xs.reduce((sum, v) => sum + v, 0); +} +console.log(spreadSame()); From de6ef6590f6e9678797d3eacd8453ff37a780236 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:12:31 -0500 Subject: [PATCH 25/45] Read optional elements at a proven integer index without a round trip An element read that may be undefined, lowered inline from `%arr.idxOr` (`a[i]` as `T | undefined`, and the read in `a[x] = a[y]!`), took an integer index only from a loop's integer slot. Any other index, such as a double counter with a proven integer range or `k | 0`, was converted and tested for an exact integer on every read. The read now takes the same exact integer as a borrowed read does (`exactInteger`), on 64-bit targets. The loop-induction treatment above the hole-free prefix still applies only to a loop's integer slot. --- .../backend/llvm/local-array-reads.test.ts | 14 ++++ .../src/backend/llvm/local-array-reads.ts | 13 +++- .../7143-optional-read-integer-index.ts.json | 6 ++ .../7143-optional-read-integer-index.ts | 70 +++++++++++++++++++ .../7143-optional-read-integer-index.ts.json | 1 + 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7143-optional-read-integer-index.ts.json create mode 100644 tests/corpus/7143-optional-read-integer-index.ts create mode 100644 tests/harness/corpus-costs/7143-optional-read-integer-index.ts.json diff --git a/packages/compiler/src/backend/llvm/local-array-reads.test.ts b/packages/compiler/src/backend/llvm/local-array-reads.test.ts index b09029865..7af495d42 100644 --- a/packages/compiler/src/backend/llvm/local-array-reads.test.ts +++ b/packages/compiler/src/backend/llvm/local-array-reads.test.ts @@ -940,3 +940,17 @@ test("a dense read tests the hole-free prefix before the capacity", () => { expect(ir.lastIndexOf("local.array.range", firstCap)).toBeGreaterThan(firstFilled); } }); + +test("an optional read at a proven integer index skips the double round trip", () => { + const module = fixture(); + const call = module.functions[2]!.body[0]!; + if (call.kind !== "varDecl" || call.init?.kind !== "call") throw new Error("missing call"); + call.init.args[1] = { kind: "bin", op: "|", left: ref("i", F64), right: num(0), type: F64, loc }; + expect(candidates(module).get("value")?.borrow).toBe(true); + expect(validateModule(module)).toEqual([]); + // The int32 index is the dense offset on 64-bit targets; a 32-bit target + // converts the double, as a borrowed read does. + expect(workBody(module, 64)).not.toContain("local.array.exact"); + expect(workBody(module, 64)).toContain("local.array.value"); + expect(workBody(module, 32)).toContain("local.array.exact"); +}); diff --git a/packages/compiler/src/backend/llvm/local-array-reads.ts b/packages/compiler/src/backend/llvm/local-array-reads.ts index cdd00c4e7..7a593e865 100644 --- a/packages/compiler/src/backend/llvm/local-array-reads.ts +++ b/packages/compiler/src/backend/llvm/local-array-reads.ts @@ -644,8 +644,15 @@ export function emitLocalArrayRead( ): { slot: string; type: IrType } | null { const B = host.B; const array = host.emitStableReceiver(read.array, [read.index]); - const integerIndex = inline ? host.emitIntegerLoopIndex(read.index) : null; + const loopIndex = inline ? host.emitIntegerLoopIndex(read.index) : null; const index = host.emitExpr(read.index); + // A proven integer index (a counter with a known range, say) needs no + // double round trip, as in a borrowed read. + const exact = + inline && loopIndex === null && host.sizeType === "i64" + ? exactInteger(host, index, read.index) + : null; + const integerIndex = loopIndex ?? (exact ? widenInteger(host, exact) : null); const nullable = read.type.kind === "union" ? host.nullableUnions.get(read.type.unionId) : null; if (nullable) { // A nullable union is the element pointer itself: borrowed from an @@ -665,7 +672,7 @@ export function emitLocalArrayRead( array, index, integerIndex, - integerIndex !== null, + loopIndex !== null, store, no, slow, @@ -726,7 +733,7 @@ export function emitLocalArrayRead( array, index, integerIndex, - integerIndex !== null, + loopIndex !== null, storeValue, no, slow, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7143-optional-read-integer-index.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7143-optional-read-integer-index.ts.json new file mode 100644 index 000000000..ae0d1f610 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7143-optional-read-integer-index.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7143-optional-read-integer-index.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7143-optional-read-integer-index.ts b/tests/corpus/7143-optional-read-integer-index.ts new file mode 100644 index 000000000..43fd59a6e --- /dev/null +++ b/tests/corpus/7143-optional-read-integer-index.ts @@ -0,0 +1,70 @@ +// Element reads that may be undefined, at indices with a proven integer +// range: loop counters with an unknown limit, `i | 0`, `x >>> 0`, negative +// counters, -0, indices past the length and the capacity, and copies +// `a[x] = b[y]!` that meet holes. +function copy(src: number[], n: number): number[] { + const out: number[] = new Array(n); + for (let i = 0; i < n; i++) out[i] = src[i]!; + return out; +} +const src: number[] = [1, 2, 3, 4]; +const copied = copy(src, 6); +console.log(copied.length, copied.join(","), 4 in copied, copied[5] === undefined); + +const holes: number[] = new Array(5); +holes[0] = 10; +holes[3] = 13; +const fromHoles = copy(holes, 5); +console.log(fromHoles.join(","), 1 in fromHoles, 3 in fromHoles); + +function show(a: (string | undefined)[], from: number, to: number): string { + const out: string[] = []; + for (let i = from; i < to; i++) { + const v = a[i]; + out.push(v === undefined ? "_" : v); + } + return out.join(","); +} +const words: (string | undefined)[] = ["a", undefined, "c"]; +words[5] = "f"; +console.log(show(words, -3, 8)); +console.log(show(words, 0, 0), show(words, 2, 1)); + +function masked(a: number[], keys: number[]): string { + const out: string[] = []; + for (const k of keys) { + const v = a[k | 0]; + const w = a[k >>> 0]; + out.push(`${v === undefined ? "-" : v}/${w === undefined ? "-" : w}`); + } + return out.join(" "); +} +const values: number[] = [5, 6, 7]; +console.log(masked(values, [0, 1.9, 2, 3, -1, -0, 4294967297, 2 ** 31])); + +const negativeZero = -0; +console.log(values[negativeZero], values[0 * -1], Object.is(negativeZero, -0)); + +// A counter that starts below zero and one that passes the capacity. +let total = 0; +for (let i = -2; i < values.length + 3; i++) total += values[i] ?? 100; +console.log(total); +const big: number[] = []; +for (let k = 0; k < 20; k++) big.push(k); +big.length = 10; +let seen = 0; +for (let i = 0; i < 40; i++) if (big[i] !== undefined) seen++; +console.log(seen, big.length); + +// Rotations through the read, with a hole that becomes undefined. +function rotate(p: number[], r: number): void { + const first = p[0]!; + for (let i = 0; i < r; i++) p[i] = p[i + 1]!; + p[r] = first; +} +const ring: number[] = new Array(4); +ring[0] = 0; +ring[1] = 1; +ring[3] = 3; +rotate(ring, 3); +console.log(ring.join(","), 1 in ring, ring[1] === undefined); diff --git a/tests/harness/corpus-costs/7143-optional-read-integer-index.ts.json b/tests/harness/corpus-costs/7143-optional-read-integer-index.ts.json new file mode 100644 index 000000000..16148d8ce --- /dev/null +++ b/tests/harness/corpus-costs/7143-optional-read-integer-index.ts.json @@ -0,0 +1 @@ +{ "plain": 3500, "san": 5400 } From 3a3610d12ebfaedce85f3e877338500da9e7f8dc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:15:10 -0500 Subject: [PATCH 26/45] Look up spawn and execFileSync commands on the replacement environment's PATH spawn and execFileSync with an `env` option searched the parent's PATH for a command without a '/'. They now resolve it the way spawnSync does, as Node (libuv) does: on the replacement environment's PATH, or the default path when it has none, with relative entries read from the cwd option's directory. --- .../corpus/7036-child-env-path-lookup.ts.json | 6 ++ packages/runtime/src/scr_child.c | 62 +++++++++++++------ tests/corpus/7036-child-env-path-lookup.ts | 40 ++++++++++++ .../7036-child-env-path-lookup.ts.json | 1 + 4 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7036-child-env-path-lookup.ts.json create mode 100644 tests/corpus/7036-child-env-path-lookup.ts create mode 100644 tests/harness/corpus-costs/7036-child-env-path-lookup.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7036-child-env-path-lookup.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7036-child-env-path-lookup.ts.json new file mode 100644 index 000000000..171ab060a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7036-child-env-path-lookup.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7036-child-env-path-lookup.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index df60fcb26..c1d98b35b 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -3116,9 +3116,12 @@ static void scr_exec_envp_free(char **envp); * environment, found as libuv finds it: a name with a '/' is used as * given; otherwise each entry of the replacement's PATH (an empty entry * is the current directory), or of the default path when the replacement - * has no PATH, is tried in order. Returns a malloc'd path, or NULL with - * *err set: EACCES when a candidate exists but cannot run, else ENOENT. */ -static char *scr_spawn_path_lookup(const char *file, char *const *envp, int *err) { + * has no PATH, is tried in order. Relative candidates are checked from + * `cwd`, the directory the child starts in (NULL: this process's). Returns + * a malloc'd path, or NULL with *err set: EACCES when a candidate exists + * but cannot run, else ENOENT. */ +static char *scr_spawn_path_lookup(const char *file, char *const *envp, const char *cwd, + int *err) { if (strchr(file, '/')) { char *copy = strdup(file); if (!copy) scr_child_oom(); @@ -3132,6 +3135,7 @@ static char *scr_spawn_path_lookup(const char *file, char *const *envp, int *err } } size_t file_len = strlen(file); + size_t cwd_len = cwd ? strlen(cwd) : 0; bool denied = false; for (const char *dir = path;;) { const char *end = strchr(dir, ':'); @@ -3143,13 +3147,24 @@ static char *scr_spawn_path_lookup(const char *file, char *const *envp, int *err memcpy(candidate, prefix, prefix_len); candidate[prefix_len] = '/'; memcpy(candidate + prefix_len + 1, file, file_len + 1); + char *checked = candidate; + if (cwd_len > 0 && candidate[0] != '/') { + checked = malloc(cwd_len + 1 + strlen(candidate) + 1); + if (!checked) scr_child_oom(); + memcpy(checked, cwd, cwd_len); + checked[cwd_len] = '/'; + strcpy(checked + cwd_len + 1, candidate); + } struct stat st; - if (stat(candidate, &st) == 0) { - if (S_ISREG(st.st_mode) && access(candidate, X_OK) == 0) return candidate; - denied = true; + bool runs = false; + if (stat(checked, &st) == 0) { + runs = S_ISREG(st.st_mode) && access(checked, X_OK) == 0; + if (!runs) denied = true; } else if (errno == EACCES) { denied = true; } + if (checked != candidate) free(checked); + if (runs) return candidate; free(candidate); if (!end) break; dir = end + 1; @@ -3158,6 +3173,22 @@ static char *scr_spawn_path_lookup(const char *file, char *const *envp, int *err return NULL; } +/* posix_spawnp for the child_process spawns: with `envp` (a replacement + * environment) the command resolves on that environment's PATH + * (scr_spawn_path_lookup) as Node's does; without it, on this process's + * PATH over `environ`. Returns posix_spawn's error number. */ +static int scr_spawn_command(pid_t *pid, const char *file, const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *attr, char *const *argv, + char *const *envp, const char *cwd) { + if (envp == NULL) return posix_spawnp(pid, file, fa, attr, argv, environ); + int err = 0; + char *resolved = scr_spawn_path_lookup(file, envp, cwd, &err); + if (!resolved) return err; + err = posix_spawn(pid, resolved, fa, attr, argv, envp); + free(resolved); + return err; +} + /* env_pairs: NULL inherits the parent's environment; else [k,v,...] * replaces it, as Node's `env` option does, and the command is looked up * on the replacement's PATH (scr_spawn_path_lookup). */ @@ -3200,16 +3231,7 @@ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeou char **argv = scr_child_argv(cmd, args); char **envp = env_pairs != NULL ? scr_exec_envp(env_pairs) : NULL; pid_t pid = -1; - int spawn_err; - if (envp != NULL) { - char *resolved = scr_spawn_path_lookup(cmd->data, envp, &spawn_err); - if (resolved) { - spawn_err = posix_spawn(&pid, resolved, &fa, NULL, argv, envp); - free(resolved); - } - } else { - spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, environ); - } + int spawn_err = scr_spawn_command(&pid, cmd->data, &fa, NULL, argv, envp, NULL); posix_spawn_file_actions_destroy(&fa); free(argv); scr_exec_envp_free(envp); @@ -3556,8 +3578,8 @@ ScrStr *scr_exec_sync_core(ScrStr *cmd, ScrArr *args, const ScrExecOpts *o) { char **argv = scr_child_argv(cmd, args); char **envp = o->env_pairs != NULL ? scr_exec_envp(o->env_pairs) : NULL; pid_t pid = -1; - int spawn_err = posix_spawnp(&pid, cmd->data, &fa, NULL, argv, - envp != NULL ? envp : environ); + int spawn_err = scr_spawn_command(&pid, cmd->data, &fa, NULL, argv, envp, + o->cwd != NULL ? o->cwd->data : NULL); posix_spawn_file_actions_destroy(&fa); free(argv); scr_exec_envp_free(envp); @@ -5115,8 +5137,8 @@ ScrChild *scr_spawn_opts(ScrStr *cmd, ScrArr *args, double in_mode, char **envp = has_env && env_pairs != NULL ? scr_exec_envp(env_pairs) : NULL; pid_t pid = -1; const char *file = shell ? "/bin/sh" : cmd->data; - int spawn_err = posix_spawnp(&pid, file, &fa, &at, argv, - envp != NULL ? envp : environ); + int spawn_err = scr_spawn_command(&pid, file, &fa, &at, argv, envp, + cwd != NULL && cwd->len > 0 ? cwd->data : NULL); posix_spawnattr_destroy(&at); posix_spawn_file_actions_destroy(&fa); if (!shell) free(argv); diff --git a/tests/corpus/7036-child-env-path-lookup.ts b/tests/corpus/7036-child-env-path-lookup.ts new file mode 100644 index 000000000..cac0670e9 --- /dev/null +++ b/tests/corpus/7036-child-env-path-lookup.ts @@ -0,0 +1,40 @@ +// spawn and execFileSync with an env option find the command on the +// replacement environment's PATH, or on the default path when it has +// none, as Node does; a relative PATH entry is read from the cwd option. +import { execFileSync, spawn } from "node:child_process"; +import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const dir = mkdtempSync(join(tmpdir(), "scr-child-path-")); +mkdirSync(join(dir, "tools")); +writeFileSync(join(dir, "tools", "child-tool"), "#!/bin/sh\necho child-tool $1\n"); +chmodSync(join(dir, "tools", "child-tool"), 0o755); + +const show = (e: unknown): string => { + const err = e as NodeJS.ErrnoException; + return `${err.code} ${err.message.replace(dir, "")}`; +}; + +console.log(execFileSync("child-tool", ["sync"], { env: { PATH: join(dir, "tools") }, encoding: "utf8" }).trim()); +console.log(execFileSync("sh", ["-c", "echo default"], { env: { A: "1" }, encoding: "utf8" }).trim()); +try { + execFileSync("sh", ["-c", "echo never"], { env: { PATH: "/nonexistent" }, encoding: "utf8" }); +} catch (e) { + console.log(show(e)); +} +console.log( + execFileSync("child-tool", ["relative"], { env: { PATH: "tools" }, cwd: dir, encoding: "utf8" }).trim(), +); + +const child = spawn("child-tool", ["async"], { env: { PATH: join(dir, "tools") }, stdio: ["ignore", "pipe", "ignore"] }); +let out = ""; +child.stdout!.on("data", (chunk: Buffer) => (out += chunk.toString())); +child.on("close", (code) => { + console.log(out.trim(), code); + const missing = spawn("sh", ["-c", "true"], { env: { PATH: "/nonexistent" }, stdio: "ignore" }); + missing.on("error", (e) => { + console.log("error", show(e)); + rmSync(dir, { recursive: true }); + }); +}); diff --git a/tests/harness/corpus-costs/7036-child-env-path-lookup.ts.json b/tests/harness/corpus-costs/7036-child-env-path-lookup.ts.json new file mode 100644 index 000000000..f9bfce7d9 --- /dev/null +++ b/tests/harness/corpus-costs/7036-child-env-path-lookup.ts.json @@ -0,0 +1 @@ +{ "plain": 2570, "san": 4110 } From ccfca67aecc819a66e38baafe01e213f99f1337f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:30:56 -0500 Subject: [PATCH 27/45] Fix chalk builder field calls and hot-shots send failures and tcp completion --- packages/compiler/shims/hot-shots/client.ts | 23 ++++++++++--- .../src/frontend/lowering/lower-calls.ts | 4 +++ .../npm/cases/chalk5-builder/main.ts.json | 1 + .../fixtures/npm/cases/chalk5/main.ts.json | 1 + .../npm/cases/hot-shots-buffered/main.ts.json | 2 ++ .../cases/hot-shots-send-error/main.ts.json | 8 +++++ .../npm/cases/hot-shots-tcp/main.ts.json | 8 +++++ .../npm/cases/hot-shots-udp/main.ts.json | 2 ++ packages/runtime/src/scr_dgram.h | 7 ++++ .../fixtures/npm/cases/chalk5-builder/main.ts | 5 ++- .../npm/cases/hot-shots-send-error/main.ts | 27 +++++++++++++++ .../cases/hot-shots-send-error/package.json | 1 + .../fixtures/npm/cases/hot-shots-tcp/main.ts | 33 +++++++++++++++++++ .../npm/cases/hot-shots-tcp/package.json | 1 + 14 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-send-error/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-tcp/main.ts.json create mode 100644 tests/fixtures/npm/cases/hot-shots-send-error/main.ts create mode 100644 tests/fixtures/npm/cases/hot-shots-send-error/package.json create mode 100644 tests/fixtures/npm/cases/hot-shots-tcp/main.ts create mode 100644 tests/fixtures/npm/cases/hot-shots-tcp/package.json diff --git a/packages/compiler/shims/hot-shots/client.ts b/packages/compiler/shims/hot-shots/client.ts index b407132f4..354744e7b 100644 --- a/packages/compiler/shims/hot-shots/client.ts +++ b/packages/compiler/shims/hot-shots/client.ts @@ -179,6 +179,8 @@ interface Transport { close(): void; onError(listener: (err: Error) => void): void; offError(listener: (err: Error) => void): void; + /** Emits 'error' on the socket, as hot-shots' `socket.emit('error')`. */ + emitError(err: Error): void; onClose(listener: () => void): void; } @@ -261,6 +263,9 @@ class UdpTransport implements Transport { offError(listener: (err: Error) => void): void { this.errors.remove(listener); } + emitError(err: Error): void { + this.errors.emit(err); + } onClose(listener: () => void): void { this.socket.on("close", listener); } @@ -281,10 +286,10 @@ class TcpTransport implements Transport { this.socket.on("error", (err) => errors.emit(err)); } send(buf: Buffer, callback: SendCallback): void { - // The typed socket's write takes the data alone; the completion runs - // on the next tick. - this.socket.write(addEol(buf)); - process.nextTick(() => callback(null)); + // hot-shots writes the line with the 'ascii' encoding, which encodes + // strings as 'latin1' does. The callback runs once the data is written, + // so a message held back by a full socket buffer stays in flight. + this.socket.write(Buffer.from(addEol(buf), "latin1"), (err) => callback(err ?? null)); } close(): void { this.socket.destroy(); @@ -295,6 +300,9 @@ class TcpTransport implements Transport { offError(listener: (err: Error) => void): void { this.errors.remove(listener); } + emitError(err: Error): void { + this.errors.emit(err); + } onClose(listener: () => void): void { this.socket.on("close", () => listener()); } @@ -376,6 +384,9 @@ class UdsTransport implements Transport { offError(listener: (err: Error) => void): void { this.errors.remove(listener); } + emitError(err: Error): void { + this.errors.emit(err); + } onClose(listener: () => void): void { this.closeListeners.push(listener); } @@ -999,6 +1010,10 @@ export class StatsD { handler(errFormatted); } else { console.error(String(errFormatted)); + // hot-shots also emits the error on the current socket, where the + // uds reconnection handler listens; with no listener it throws. + const current = this.transport; + if (current !== null) current.emitError(errFormatted); } } }; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index b650ca567..301670c3a 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -9250,6 +9250,10 @@ export function lowerRecordFieldCall( if (callee.type.kind === "object" && !init) { const direct = callableInstanceStringCall(lowerer, call, callee, loc); if (direct) return direct; + // Other argument counts call the %call closure through its value, as + // a call on the builder itself does (`theme.error("a", "b")`). + const closure = lowerer.hybridCallUnwrap(callee); + if (closure !== callee) return lowerCallThroughValue(lowerer, call, closure, loc); } if (callee.type.kind === "record" || callee.type.kind === "object") callee = lowerer.hybridCallUnwrap(callee); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json index 545c4d701..8f7268daf 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5-builder/main.ts.json @@ -1,5 +1,6 @@ { "order": [ + "/packages/compiler/shims/chalk/v5.ts", "/tests/fixtures/npm/cases/chalk5-builder/main.ts" ], "diags": [] diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json index 065c96347..8365d4db9 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/chalk5/main.ts.json @@ -1,5 +1,6 @@ { "order": [ + "/packages/compiler/shims/chalk/v5.ts", "/tests/fixtures/npm/cases/chalk5/main.ts" ], "diags": [] diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json index e60660c09..a48e1af78 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-buffered/main.ts.json @@ -1,5 +1,7 @@ { "order": [ + "/packages/compiler/shims/hot-shots/client.ts", + "/packages/compiler/shims/hot-shots/v8.ts", "/tests/fixtures/npm/cases/hot-shots-buffered/main.ts" ], "diags": [] diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-send-error/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-send-error/main.ts.json new file mode 100644 index 000000000..716cfe02f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-send-error/main.ts.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/packages/compiler/shims/hot-shots/client.ts", + "/packages/compiler/shims/hot-shots/v8.ts", + "/tests/fixtures/npm/cases/hot-shots-send-error/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-tcp/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-tcp/main.ts.json new file mode 100644 index 000000000..f131361e8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-tcp/main.ts.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/packages/compiler/shims/hot-shots/client.ts", + "/packages/compiler/shims/hot-shots/v8.ts", + "/tests/fixtures/npm/cases/hot-shots-tcp/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-udp/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-udp/main.ts.json index 54baff890..a3014fb9f 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-udp/main.ts.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/hot-shots-udp/main.ts.json @@ -1,5 +1,7 @@ { "order": [ + "/packages/compiler/shims/hot-shots/client.ts", + "/packages/compiler/shims/hot-shots/v8.ts", "/tests/fixtures/npm/cases/hot-shots-udp/main.ts" ], "diags": [] diff --git a/packages/runtime/src/scr_dgram.h b/packages/runtime/src/scr_dgram.h index 8396f0693..08db077df 100644 --- a/packages/runtime/src/scr_dgram.h +++ b/packages/runtime/src/scr_dgram.h @@ -55,6 +55,13 @@ double scr_dgram_addr_port(ScrDgramSocket *s); void scr_dgram_close(ScrDgramSocket *s, ScrClosure *cb /*moves, nullable*/); /* throws on closed */ void scr_dgram_unref(ScrDgramSocket *s); void scr_dgram_ref(ScrDgramSocket *s); +/* Unix datagram sockets for the hot-shots package shim (the unix-dgram + * addon's surface): each answers its result (fd, 0) or a negative errno; + * send answers 1 when the socket would block. */ +double scr_dgram_unix_socket(void); +double scr_dgram_unix_connect(double fd, ScrStr *path /*borrowed*/); +double scr_dgram_unix_send(double fd, ScrBytes *data /*borrowed*/); +double scr_dgram_unix_close(double fd); /* Socket options: Node's checks and errors (ErrnoException " * ", ERR_SOCKET_BAD_BUFFER_SIZE, ERR_SOCKET_BUFFER_SIZE, the * TypeError after close()). The TTL setters and setMulticastLoopback diff --git a/tests/fixtures/npm/cases/chalk5-builder/main.ts b/tests/fixtures/npm/cases/chalk5-builder/main.ts index 8f2623717..2a4fff61b 100644 --- a/tests/fixtures/npm/cases/chalk5-builder/main.ts +++ b/tests/fixtures/npm/cases/chalk5-builder/main.ts @@ -1,6 +1,7 @@ // chalk 5 builders used as values (the package compiles from scriptc's // built-in shim): builders in function slots and arrays, styles picked at -// run time, visible at level 0, chalkStderr, and the root's own call. +// run time, builders in record fields called with any number of arguments, +// visible at level 0, chalkStderr, and the root's own call. import chalk, { Chalk, chalkStderr, type ChalkInstance, type ForegroundColorName } from "chalk"; const show = (label: string, value: string): void => { @@ -36,6 +37,8 @@ const off = new Chalk({ level: 0 }); show("visible off", off.visible("v") + "|" + off.red.visible("v") + "|" + off.red("plain")); show("root call", c("a", 1, true) + "|" + c() + "|" + c(undefined) + "|" + c(null, "n")); show("builder args", c.red(undefined) + "|" + c.red(null) + "|" + c.red(1, 2) + "|" + c.red()); +const theme = { error: c.red, note: c.bold.blue }; +show("field args", theme.error("a", "b") + "|" + theme.note("x", 1, true) + "|" + theme.error("one") + "|" + theme.error()); show("multiline", c.cyan("one\r\ntwo\nthree")); show("stderr level", String(chalkStderr.level >= 0)); show("rgb levels", [1, 2, 3].map((level) => new Chalk({ level: level as 1 | 2 | 3 }).rgb(255, 136, 0)("o")).join("|")); diff --git a/tests/fixtures/npm/cases/hot-shots-send-error/main.ts b/tests/fixtures/npm/cases/hot-shots-send-error/main.ts new file mode 100644 index 000000000..e829c5e33 --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-send-error/main.ts @@ -0,0 +1,27 @@ +// The hot-shots StatsD client (compiled from scriptc's built-in shim) when a +// send fails: with a callback or an errorHandler the error goes there; with +// neither, the client logs it and emits it on the socket, where an 'error' +// event nobody listens for ends the process with status 1. +import { StatsD } from "hot-shots"; + +// A datagram larger than udp allows fails with EMSGSIZE before it leaves +// the host; port 9 keeps the message the same on every run. +const big = "x".repeat(70000); + +const withCallback = new StatsD({ host: "127.0.0.1", port: 9 }); +withCallback.increment(big, 1, 1, [], (err: Error | null | undefined) => { + console.log("callback:", err ? err.message : "no error"); + withCallback.close(); + + const withHandler = new StatsD({ + host: "127.0.0.1", + port: 9, + errorHandler: (error: Error) => { + console.log("errorHandler:", error.message); + withHandler.close(); + console.log("without a callback or errorHandler"); + new StatsD({ host: "127.0.0.1", port: 9 }).increment(big); + }, + }); + withHandler.increment(big); +}); diff --git a/tests/fixtures/npm/cases/hot-shots-send-error/package.json b/tests/fixtures/npm/cases/hot-shots-send-error/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-send-error/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/tests/fixtures/npm/cases/hot-shots-tcp/main.ts b/tests/fixtures/npm/cases/hot-shots-tcp/main.ts new file mode 100644 index 000000000..0812c90f1 --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-tcp/main.ts @@ -0,0 +1,33 @@ +// The hot-shots StatsD client over tcp (compiled from scriptc's built-in +// shim): a send completes once the socket has written its line, so close() +// waits for lines that a full socket buffer holds back, and the receiver +// gets every line before the connection ends. +import * as net from "node:net"; +import { StatsD } from "hot-shots"; + +const LINES = 20000; +const name = "m".repeat(1000); +let bytes = 0; +let ended: () => void = () => {}; +const serverDone = new Promise((resolve) => { + ended = resolve; +}); +const server = net.createServer((socket) => { + socket.pause(); + setTimeout(() => socket.resume(), 150); + socket.on("data", (chunk: Buffer) => { + bytes += chunk.length; + }); + socket.on("end", () => ended()); +}); + +server.listen(0, "127.0.0.1", () => { + const port = (server.address() as net.AddressInfo).port; + const client = new StatsD({ host: "127.0.0.1", port, protocol: "tcp" }); + for (let i = 0; i < LINES; i++) client.increment(name); + const closed = new Promise((resolve) => client.close(() => resolve())); + void Promise.all([closed, serverDone]).then(() => { + console.log("closed; received", bytes, "of", LINES * (name.length + 5), "bytes"); + server.close(() => console.log("server closed")); + }); +}); diff --git a/tests/fixtures/npm/cases/hot-shots-tcp/package.json b/tests/fixtures/npm/cases/hot-shots-tcp/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/tests/fixtures/npm/cases/hot-shots-tcp/package.json @@ -0,0 +1 @@ +{ "type": "module" } From 4d7de0305411bae6db0d7306d739baadbe3f906e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:46:16 -0500 Subject: [PATCH 28/45] Store arrays of ProgramLifetime instances in 4-byte slots on Linux --- docs/content/docs/contracts.mdx | 2 +- .../compiler/src/backend/llvm/array-search.ts | 37 ++-- .../compiler/src/backend/llvm/classes.test.ts | 117 ++++++++++- packages/compiler/src/backend/llvm/classes.ts | 22 +- .../src/backend/llvm/dense-array-access.ts | 88 ++++++-- .../compiler/src/backend/llvm/emit-module.ts | 4 +- .../src/backend/llvm/emit-statements.ts | 2 +- packages/compiler/src/backend/llvm/emitter.ts | 63 ++++-- .../src/backend/llvm/expr-containers.ts | 19 +- .../src/backend/llvm/expr-primitives.ts | 10 +- .../src/backend/llvm/lib-filesystem.ts | 8 +- .../src/backend/llvm/local-array-reads.ts | 36 +++- packages/compiler/src/backend/llvm/shapes.ts | 20 +- ...8-contract-program-lifetime-arrays.ts.json | 6 + packages/runtime/src/scr_array.c | 196 ++++++++++++------ packages/runtime/src/scr_array.h | 44 +++- packages/runtime/src/scr_copying.c | 2 +- packages/runtime/src/scr_lib.c | 2 +- packages/runtime/src/scr_publish.c | 20 +- .../4638-contract-program-lifetime-arrays.ts | 117 +++++++++++ ...8-contract-program-lifetime-arrays.ts.json | 1 + 21 files changed, 640 insertions(+), 176 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/4638-contract-program-lifetime-arrays.ts.json create mode 100644 tests/corpus/4638-contract-program-lifetime-arrays.ts create mode 100644 tests/harness/corpus-costs/4638-contract-program-lifetime-arrays.ts.json diff --git a/docs/content/docs/contracts.mdx b/docs/content/docs/contracts.mdx index 5af1cad2f..d3bd3c7f4 100644 --- a/docs/content/docs/contracts.mdx +++ b/docs/content/docs/contracts.mdx @@ -349,7 +349,7 @@ class Identifier extends SyntaxNode { } ``` -On Linux, except in builds with sanitizers, the instances also take less memory. An executable keeps them in one address range below 32 GiB that it reserves at startup (only the pages in use take memory), and a field typed `C`, `C | undefined` or `C | null`, where `C` is a program-lifetime class, stores the instance's address in 4 bytes instead of 8. In the example, `parent` takes 4 bytes. +On Linux, except in builds with sanitizers, the instances also take less memory. An executable keeps them in one address range below 32 GiB that it reserves at startup (only the pages in use take memory), and a field typed `C`, `C | undefined` or `C | null`, where `C` is a program-lifetime class, stores the instance's address in 4 bytes instead of 8, as does each element of an array of such a type. In the example, `parent` takes 4 bytes. scriptc checks that the promise cannot change what the program computes (SC7008): diff --git a/packages/compiler/src/backend/llvm/array-search.ts b/packages/compiler/src/backend/llvm/array-search.ts index d61d91e5c..41b64d418 100644 --- a/packages/compiler/src/backend/llvm/array-search.ts +++ b/packages/compiler/src/backend/llvm/array-search.ts @@ -10,6 +10,8 @@ * SameValueZero are both pointer identity (class instances, records, * arrays, maps, sets, typed arrays): 64-bit compares, four slots per * branch. + * - sc_arr_index_of_cref, the same over the 4-byte slots of compact class + * references (SCR_ELEM_CREF), against the needle's 32-bit reference. * - sc_arr_index_of_str, for strings: pointer identity, then the length, * then the bytes. Strings of up to 16 bytes compare as two words; a short * string's word is the eight bytes ending at its last byte, which start @@ -26,10 +28,12 @@ import type { IrType } from "../../ir/ir.js"; import { SCR_ARR_FIELD } from "./common.js"; import { FN_ATTRS } from "./shapes.js"; -export type ArraySearchKind = "ptr" | "str"; +export type ArraySearchKind = "ptr" | "cref" | "str"; -/** The inline search for arrays of `elem`, or null for the runtime search. */ -export function arraySearchKind(elem: IrType): ArraySearchKind | null { +/** The inline search for arrays of `elem`, or null for the runtime search. + * `compact`: the arrays hold compact class references (SCR_ELEM_CREF). */ +export function arraySearchKind(elem: IrType, compact: boolean): ArraySearchKind | null { + if (compact) return elem.kind === "object" ? "cref" : null; switch (elem.kind) { case "object": case "record": @@ -46,7 +50,7 @@ export function arraySearchKind(elem: IrType): ArraySearchKind | null { } export function arraySearchHelperName(kind: ArraySearchKind): string { - return kind === "ptr" ? "sc_arr_index_of_ptr" : "sc_arr_index_of_str"; + return `sc_arr_index_of_${kind}`; } /** The definitions of the helpers in `kinds`; they declare their slow paths @@ -76,9 +80,18 @@ export function emitArraySearchHelpers( ` %dp = getelementptr inbounds %ScrArr, ptr %a, i32 0, i32 ${SCR_ARR_FIELD.data}`, ` %data = load ptr, ptr %dp`, ); - if (kind === "ptr") { + if (kind === "ptr" || kind === "cref") { + // A compact reference is the address over 8 (classes.ts + // compactRefLoadLines). + const slot = kind === "ptr" ? "i64" : "i32"; defs.push( - ` %needle = ptrtoint ptr %v to i64`, + ...(kind === "ptr" + ? [` %needle = ptrtoint ptr %v to i64`] + : [ + ` %vaddr = ptrtoint ptr %v to i64`, + ` %vref = lshr i64 %vaddr, 3`, + ` %needle = trunc i64 %vref to i32`, + ]), // Four slots per step with one branch, then one at a time. ` br label %quad`, `quad:`, @@ -89,9 +102,9 @@ export function emitArraySearchHelpers( `quadbody:`, ...[0, 1, 2, 3].flatMap((k) => [ ` %qi${k} = add ${sz} %q, ${k}`, - ` %qp${k} = getelementptr inbounds i64, ptr %data, ${sz} %qi${k}`, - ` %qs${k} = load i64, ptr %qp${k}`, - ` %qh${k} = icmp eq i64 %qs${k}, %needle`, + ` %qp${k} = getelementptr inbounds ${slot}, ptr %data, ${sz} %qi${k}`, + ` %qs${k} = load ${slot}, ptr %qp${k}`, + ` %qh${k} = icmp eq ${slot} %qs${k}, %needle`, ]), ` %qh01 = or i1 %qh0, %qh1`, ` %qh23 = or i1 %qh2, %qh3`, @@ -107,9 +120,9 @@ export function emitArraySearchHelpers( ` %done = icmp eq ${sz} %i, %len`, ` br i1 %done, label %miss, label %body`, `body:`, - ` %sp = getelementptr inbounds i64, ptr %data, ${sz} %i`, - ` %s = load i64, ptr %sp`, - ` %hit = icmp eq i64 %s, %needle`, + ` %sp = getelementptr inbounds ${slot}, ptr %data, ${sz} %i`, + ` %s = load ${slot}, ptr %sp`, + ` %hit = icmp eq ${slot} %s, %needle`, ` br i1 %hit, label %found, label %cont`, ); } else { diff --git a/packages/compiler/src/backend/llvm/classes.test.ts b/packages/compiler/src/backend/llvm/classes.test.ts index 2d95e942c..f921900a3 100644 --- a/packages/compiler/src/backend/llvm/classes.test.ts +++ b/packages/compiler/src/backend/llvm/classes.test.ts @@ -1,5 +1,14 @@ import { expect, test } from "vitest"; -import { DYN, F64, STRING, VOID, type IrModule } from "../../ir/ir.js"; +import { + DYN, + F64, + STRING, + VOID, + type IrExpr, + type IrFunction, + type IrModule, + type IrType, +} from "../../ir/ir.js"; import { assignCompactLayouts, buildClassGraph, @@ -222,12 +231,13 @@ test("ProgramLifetime classes pack their fields after a 32-bit header", () => { contracts: { programLifetime: ["Node"] }, }; const llvm = emitLlvmModule(mod, { pointerBits: 64 }); - // Fields go widest first, each at the first offset that fits it. Node's - // weight (an int32 slot: nothing stores a fraction) takes the word the - // header shares (24 bytes, not 32); Leaf keeps Node's offsets and puts its - // bool next to Node's (32 bytes, not 48). - expect(llvm).toContain(`%${mangleClassStruct("Node")} = type { i32, i32, ptr, i8 }`); - expect(llvm).toContain(`%${mangleClassStruct("Leaf")} = type { i32, i32, ptr, i8, i8, ptr }`); + // Scalars narrower than 8 bytes go first, then the rest, widest first, + // each at the first offset that fits it. Node's weight (an int32 slot: + // nothing stores a fraction) takes the word the header shares and its + // flag the next one (24 bytes, not 32); Leaf keeps Node's offsets and puts + // its bool next to Node's (32 bytes, not 48). + expect(llvm).toContain(`%${mangleClassStruct("Node")} = type { i32, i32, i8, ptr }`); + expect(llvm).toContain(`%${mangleClassStruct("Leaf")} = type { i32, i32, i8, i8, ptr, ptr }`); // Without the contract, the layout is the declared one. const mortal = emitLlvmModule({ ...mod, contracts: {} }, { pointerBits: 64 }); expect(mortal).toContain(`%${mangleClassStruct("Leaf")} = type { i64, ptr, i8, i32, ptr, i8 }`); @@ -332,6 +342,99 @@ test("references between ProgramLifetime instances are 32-bit indexes into their expect(classFieldIndex(leafMeta, "label").compressed).toBe(false); }); +test("arrays of ProgramLifetime instances keep 32-bit references in 4-byte slots", () => { + const node = { kind: "object" as const, className: "Node" }; + const nodes = { kind: "array" as const, elem: node }; + const ref = (localId: string, type: IrType): IrExpr => ({ kind: "varRef", localId, type, loc }); + const fn = (name: string, body: IrExpr, returnType: IrType): IrFunction => ({ + name, + params: [ + { name: "a", localId: "a", type: nodes }, + { name: "v", localId: "v", type: node }, + ], + returnType, + locals: [ + { id: "a", name: "a", type: nodes, mutable: false }, + { id: "v", name: "v", type: node, mutable: false }, + ], + body: [{ kind: "return", value: body, loc }], + loc, + }); + const mod: IrModule = { + irVersion: 17, + sourceFile: loc.file, + entry: "main", + functions: [ + { name: "main", params: [], returnType: VOID, locals: [], body: [], loc }, + fn( + "first", + { + kind: "arrayGet", + arr: ref("a", nodes), + index: { kind: "numLit", value: 0, type: F64, loc }, + type: node, + loc, + }, + node, + ), + fn( + "add", + { + kind: "arrIntrinsic", + method: "push", + receiver: ref("a", nodes), + args: [ref("v", node)], + type: F64, + loc, + }, + F64, + ), + fn("make", { kind: "arrayLit", elems: [ref("v", node)], type: nodes, loc }, nodes), + fn( + "find", + { + kind: "arrIntrinsic", + method: "indexOf", + receiver: ref("a", nodes), + args: [ref("v", node)], + type: F64, + loc, + }, + F64, + ), + ], + classes: [{ name: "Node", fields: [{ name: "kids", type: nodes }], methods: [], loc }], + contracts: { programLifetime: ["Node"] }, + }; + const body = (llvm: string, name: string): string => + llvm.split(/^define /m).find((f) => f.includes(`; ${name}\n`)) ?? ""; + const llvm = emitLlvmModule(mod, { pointerBits: 64, objectAudit: false, lowRegion: true }); + // The element type's ops say so (SCR_ARR_OPS_COMPACT), so the runtime makes + // the arrays SCR_ELEM_CREF. + expect(llvm).toMatch( + /^@sc_arrops\.\S+\.c = internal global \{ ptr, ptr, ptr, i32, i32 \} \{ [^}]*, i32 0, i32 1 \}$/m, + ); + // A read loads the 32-bit reference and shifts it; an append stores one. + const first = body(llvm, "first"); + expect(first).toMatch(/getelementptr inbounds i32, ptr %\S+, i64 \S+\n\s+%\S+ = load i32/); + // The states follow 4-byte slots. + expect(first).toContain("getelementptr inbounds [5 x i8]"); + expect(first).toMatch(/= inttoptr i64 %\S+ to ptr/); + expect(body(llvm, "add")).toMatch( + /= lshr i64 %\S+, 3\n\s+%\S+ = trunc i64 %\S+ to i32\n\s+store i32/, + ); + // indexOf scans the 4-byte slots for the needle's reference. + expect(llvm).toMatch(/call double @sc_arr_index_of_cref\(ptr %\S+, ptr %\S+\)/); + expect(/^define internal double @sc_arr_index_of_cref[^]*?^}/m.exec(llvm)?.[0]).toContain( + "load i32, ptr %qp0", + ); + // Elsewhere the arrays keep 8-byte slots. + const elsewhere = emitLlvmModule(mod, { pointerBits: 64, objectAudit: false }); + expect(elsewhere).not.toMatch(/sc_arrops\.\S+\.c /); + expect(body(elsewhere, "first")).not.toContain("inttoptr"); + expect(elsewhere).not.toContain("sc_arr_index_of_cref"); +}); + test("a recycled block is cleared from the end of a ProgramLifetime instance's 32-bit header", () => { const BOOL = { kind: "bool" as const }; const mod: IrModule = { diff --git a/packages/compiler/src/backend/llvm/classes.ts b/packages/compiler/src/backend/llvm/classes.ts index 3073bd1bd..8f179828d 100644 --- a/packages/compiler/src/backend/llvm/classes.ts +++ b/packages/compiler/src/backend/llvm/classes.ts @@ -703,11 +703,13 @@ export function classFieldTypes(host: ShapeHost, cls: IrClassDef, int32?: Int32S /** Gives the classes `compact` admits (whole hierarchies: the test is the * root's) the 32-bit header and packed fields. A class keeps its base's - * field offsets, and places each of its own fields, widest first, at the - * first offset after the header that fits it: in a hole another field's - * alignment left, in the base's tail padding, or at the end. So 32-bit and - * smaller fields share 8-byte words. The struct lists the header and the - * fields by offset, which LLVM's layout of the type reproduces (checked). */ + * field offsets, and places each of its own fields at the first offset + * after the header that fits it: in a hole another field's alignment left, + * in the base's tail padding, or at the end. Scalars narrower than 8 bytes + * (flags, ids, counts) go first, widest first, so they share the header's + * cache line; then the other fields, widest first. So 32-bit and smaller + * fields share 8-byte words. The struct lists the header and the fields by + * offset, which LLVM's layout of the type reproduces (checked). */ export function assignCompactLayouts( metaMap: ReadonlyMap, compact: (root: LlClassMeta) => boolean, @@ -751,10 +753,12 @@ export function assignCompactLayouts( ); return COMPACT_REF; }); + const smallScalar = (f: { type: string; field: number; size: number }): number => + f.size < 8 && f.type !== "ptr" && !compressed[f.field] ? 0 : 1; const own = types .map((type, field) => ({ type, field, ...fieldStorage(type) })) .slice(baseCount) - .sort((a, b) => b.size - a.size || a.field - b.field); + .sort((a, b) => smallScalar(a) - smallScalar(b) || b.size - a.size || a.field - b.field); for (const f of own) { const sorted = [...elems].sort((a, b) => a.offset - b.offset); let at = -1; @@ -860,9 +864,9 @@ export function emitClassShapes( nullable?: NullableRefFields, int32?: Int32Slots, ): { typeDefs: string[]; defs: string[] } { - // Whether compact instances live in the program-lifetime region (any - // field holds a 32-bit reference to one; emitter.ts assignCompactLayouts). - const regionRefs = [...metaMap.values()].some((m) => m.compressed.some(Boolean)); + // Whether compact instances live in the program-lifetime region, where + // fields and arrays can refer to them in 32 bits (LlEmitter.compactRegion). + const regionRefs = host.compactRegion?.() === true; const typeDefs: string[] = []; const defs: string[] = []; const emitted = (mod.classes ?? []).filter((c) => !c.runtime); diff --git a/packages/compiler/src/backend/llvm/dense-array-access.ts b/packages/compiler/src/backend/llvm/dense-array-access.ts index 4488f90cb..0ea014059 100644 --- a/packages/compiler/src/backend/llvm/dense-array-access.ts +++ b/packages/compiler/src/backend/llvm/dense-array-access.ts @@ -27,6 +27,8 @@ import { storeArrCount, } from "./common.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; +import { compactRefLoadLines, compactRefStoreLines } from "./classes.js"; +import { elemAccess } from "./shapes.js"; import { exactInteger, widenInteger } from "./integer-values.js"; const SCR_ARR_VALUE = 1; @@ -209,26 +211,40 @@ function statePointer( return statePtr; } -/** The dense slot type: boolean arrays store one byte per element, every - * other element kind an 8-byte slot. */ -function slotType(acc: ArrayAccess): "i8" | "i64" { - return acc === "bool" ? "i8" : "i64"; +/** How an array's dense slots hold its elements: the access kind, or + * `cref` for references to compact class instances (SCR_ELEM_CREF: a 4-byte + * slot holding the address over 8; LlEmitter.compactArrayElem). */ +type SlotKind = ArrayAccess | "cref"; + +function slotKind(host: LlvmEmitterContext, acc: ArrayAccess, element: IrType): SlotKind { + return acc === "ref" && host.compactArrayElem(element) ? "cref" : acc; +} + +/** The dense slot type: boolean arrays store one byte per element, compact + * references four, every other element kind an 8-byte slot. */ +function slotType(kind: SlotKind): "i8" | "i32" | "i64" { + return kind === "bool" ? "i8" : kind === "cref" ? "i32" : "i64"; } /** Bytes per dense slot (scr_arr_slot_width). */ -export function slotWidth(acc: ArrayAccess): number { - return acc === "bool" ? 1 : 8; +function slotWidth(kind: SlotKind): number { + return kind === "bool" ? 1 : kind === "cref" ? 4 : 8; +} + +/** Bytes per dense slot of an array of `element` (scr_arr_slot_width). */ +export function denseSlotWidth(host: LlvmEmitterContext, element: IrType): number { + return slotWidth(slotKind(host, elemAccess(element), element)); } function valuePointer( host: LlvmEmitterContext, guard: Pick, - acc: ArrayAccess, + kind: SlotKind, ): string { const B = host.B; const valuePtr = B.tmp(); B.line( - `${valuePtr} = getelementptr inbounds ${slotType(acc)}, ptr ${guard.data}, ${host.sizeType} ${guard.offset}`, + `${valuePtr} = getelementptr inbounds ${slotType(kind)}, ptr ${guard.data}, ${host.sizeType} ${guard.offset}`, ); host.markMemoryPointer(valuePtr, "array:elements"); return valuePtr; @@ -300,6 +316,7 @@ export function emitDenseArrayGet( const B = host.B; const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; const ret = acc === "bool" ? "zeroext i1" : ty; + const kind = slotKind(host, acc, element); host.declare(`declare ${ret} @${getter}(ptr, double)`); if (acc === "ref" && retain && !isRefCounted(element)) { const t = B.tmp(); @@ -322,7 +339,7 @@ export function emitDenseArrayGet( slow, true, valueLabel, - slotWidth(acc), + slotWidth(kind), proven, induction, ); @@ -333,7 +350,7 @@ export function emitDenseArrayGet( B.condBr(present, valueLabel, slow); } B.startBlock(valueLabel); - const ptr = valuePointer(host, guard, acc); + const ptr = valuePointer(host, guard, kind); let fast: string; let fastLabel = valueLabel; if (acc === "f64") { @@ -347,7 +364,13 @@ export function emitDenseArrayGet( } else { const raw = B.tmp(), nonnull = B.tmp(); - B.line(`${raw} = load ptr, ptr ${ptr}${host.fieldAliasAttachment(ptr)}`); + if (kind === "cref") { + const ref = B.tmp(); + B.line(`${ref} = load i32, ptr ${ptr}${host.fieldAliasAttachment(ptr)}`); + for (const line of compactRefLoadLines(ref, raw, `${raw}.r`)) B.line(line.trimStart()); + } else { + B.line(`${raw} = load ptr, ptr ${ptr}${host.fieldAliasAttachment(ptr)}`); + } B.line(`${nonnull} = icmp ne ptr ${raw}, null`); fastLabel = B.newLabel("arr.get.ref"); B.condBr(nonnull, fastLabel, slow); @@ -448,6 +471,7 @@ export function emitDenseArraySet( ): void { const B = host.B; const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; + const kind = slotKind(host, acc, element); const setter = `scr_arr_set_${acc}`; host.declare(`declare void @${setter}(ptr, double, ${acc === "bool" ? "i1 zeroext" : ty})`); const call = (attrs: string): void => @@ -467,7 +491,7 @@ export function emitDenseArraySet( slow, false, filledLabel, - slotWidth(acc), + slotWidth(kind), proven, ); const { offset, len } = guard; @@ -478,15 +502,20 @@ export function emitDenseArraySet( const bits = B.tmp(); B.line(`${bits} = zext i1 ${value} to i8`); B.line(`store i8 ${bits}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + } else if (kind === "cref") { + const ref = B.tmp(); + for (const line of compactRefStoreLines(value, ref, `${ref}.r`)) B.line(line.trimStart()); + B.line(`store i32 ${ref}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); } else { B.line(`store ptr ${value}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); } }; const statePtr = statePointer(host, guard); - const valuePtr = valuePointer(host, guard, acc); + const valuePtr = valuePointer(host, guard, kind); let oldState: string | null = null; let old: string | null = null; - if (acc === "ref") { + // Compact instances are never released: a replaced one needs nothing. + if (kind === "ref") { oldState = B.tmp(); old = B.tmp(); B.line(`${oldState} = load i8, ptr ${statePtr}${host.fieldAliasAttachment(statePtr)}`); @@ -537,7 +566,7 @@ export function emitDenseArraySet( storeArrCount(host, nextLen, lenPtr, host.fieldAliasAttachment(lenPtr)); B.br(storedLabel); B.startBlock(storedLabel); - if (acc === "ref" && oldState && old) { + if (kind === "ref" && oldState && old) { const hadValue = B.tmp(); B.line(`${hadValue} = icmp eq i8 ${oldState}, ${SCR_ARR_VALUE}`); const releaseLabel = B.newLabel("arr.set.release"); @@ -549,9 +578,9 @@ export function emitDenseArraySet( // Below the bound the slot holds a present value: replace it, leaving // the state alone, and release a replaced reference after the store. B.startBlock(filledLabel); - const filledValuePtr = valuePointer(host, guard, acc); + const filledValuePtr = valuePointer(host, guard, kind); let filledOld: string | null = null; - if (acc === "ref") { + if (kind === "ref") { filledOld = B.tmp(); B.line( `${filledOld} = load ptr, ptr ${filledValuePtr}${host.fieldAliasAttachment(filledValuePtr)}`, @@ -578,10 +607,12 @@ export function emitDenseArrayPop( host: LlvmEmitterContext, array: string, acc: ArrayAccess, + element: IrType, empty: string, slow: string, ): string { const B = host.B; + const kind = slotKind(host, acc, element); const size = host.sizeType; const header = (field: number): string => { const ptr = B.tmp(); @@ -615,16 +646,23 @@ export function emitDenseArrayPop( states = B.tmp(); B.line(`${data} = load ptr, ptr ${dataPtr}${host.fieldAliasAttachment(dataPtr)}`); loadArrCount(host, cap, capPtr, host.fieldAliasAttachment(capPtr)); - scrArrStates(host, states, data, cap, slotWidth(acc)); - const valuePtr = valuePointer(host, { offset: last, data }, acc); + scrArrStates(host, states, data, cap, slotWidth(kind)); + const valuePtr = valuePointer(host, { offset: last, data }, kind); const statePtr = statePointer(host, { offset: last, states }); - const slotTy = slotType(acc); + const slotTy = slotType(kind); let raw = B.tmp(); B.line(`${raw} = load ${slotTy}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); if (slotTy === "i8") { const wide = B.tmp(); B.line(`${wide} = zext i8 ${raw} to i64`); raw = wide; + } else if (slotTy === "i32") { + // The 8-byte slot of a compact reference is its address. + const wide = B.tmp(), + address = B.tmp(); + B.line(`${wide} = zext i32 ${raw} to i64`); + B.line(`${address} = shl nuw nsw i64 ${wide}, 3`); + raw = address; } B.line(`store ${slotTy} 0, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); B.line(`store i8 0, ptr ${statePtr}${host.fieldAliasAttachment(statePtr)}`); @@ -648,10 +686,12 @@ export function emitDenseArrayPush( host: LlvmEmitterContext, array: string, acc: ArrayAccess, + element: IrType | null, value: string, ): string { const B = host.B; const size = host.sizeType; + const kind = element === null ? acc : slotKind(host, acc, element); const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; const pusher = `scr_arr_push_${acc}`; host.declare(`declare double @${pusher}(ptr, ${acc === "bool" ? "i1 zeroext" : ty})`); @@ -685,16 +725,20 @@ export function emitDenseArrayPush( B.line(`${spare} = sub nuw ${size} ${cap}, ${len}`); B.line(`${near} = getelementptr inbounds i8, ptr ${data}, ${size} ${spare}`); B.line( - `${statePtr} = getelementptr inbounds [${slotWidth(acc)} x i8], ptr ${near}, ${size} ${cap}, ${size} -1`, + `${statePtr} = getelementptr inbounds [${slotWidth(kind)} x i8], ptr ${near}, ${size} ${cap}, ${size} -1`, ); host.markMemoryPointer(statePtr, "array:present"); - const valuePtr = valuePointer(host, { offset: len, data }, acc); + const valuePtr = valuePointer(host, { offset: len, data }, kind); if (acc === "f64") { B.line(`store double ${value}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); } else if (acc === "bool") { const bits = B.tmp(); B.line(`${bits} = zext i1 ${value} to i8`); B.line(`store i8 ${bits}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + } else if (kind === "cref") { + const ref = B.tmp(); + for (const line of compactRefStoreLines(value, ref, `${ref}.r`)) B.line(line.trimStart()); + B.line(`store i32 ${ref}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); } else { B.line(`store ptr ${value}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); } diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 3d9d41072..a87903f3a 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -545,7 +545,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { ``, `@scr_error_vts = external ${tl}global [${RUNTIME_ERROR_CLASSES.size} x %ScrVt]`, `declare void @scr_init()`, - ...(emitter.usesCompactRefs ? [`declare void @scr_plr_init()`] : []), + ...(emitter.compactRegion ? [`declare void @scr_plr_init()`] : []), `declare void @scr_lib_init(i32, ptr)`, ...(emitter.mod.workers ? [`declare void @scr_runtime_workers_v8()`] : []), ...(emitter.stackChecks?.size ? [`declare void @scr_stack_guard_init()`] : []), @@ -840,7 +840,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { ` call void @scr_init()`, // Compressed fields hold addresses in the program-lifetime region, which // is reserved below 32 GiB before compiled code runs. - ...(emitter.usesCompactRefs ? [` call void @scr_plr_init()`] : []), + ...(emitter.compactRegion ? [` call void @scr_plr_init()`] : []), // Each context (the main thread, every worker) installs its stack // guard before running compiled code that checks it. ...(emitter.stackChecks?.size ? [` call void @scr_stack_guard_init()`] : []), diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index dc91da2fb..d90a1deac 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -473,7 +473,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.startBlock(pop); const elem = s.arr.type.elem; const acc = elemAccess(elem); - const raw = emitDenseArrayPop(emitter, arr.name, acc, call, call); + const raw = emitDenseArrayPop(emitter, arr.name, acc, elem, call, call); if (acc === "ref" && isRefCounted(elem)) { const old = B.tmp(); B.line(`${old} = inttoptr i64 ${raw} to ptr`); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index bfde59a30..410db0371 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -641,9 +641,11 @@ export class LlEmitter { * 32-bit references to compact class instances (LlClassMeta.compressed): * loadField/loadRef decode them and storeField/storeRef encode them. */ readonly compressedFieldPtrs = new Set(); - /** Whether a class has compressed fields: main reserves the region before - * compiled code runs (scr_plr_init). */ - usesCompactRefs = false; + /** Compact class instances live in the program-lifetime region below + * 32 GiB (LlvmTargetOptions.lowRegion, and the program has compact + * classes): main reserves it before compiled code runs (scr_plr_init), and + * fields and arrays of compactRefType hold 32-bit references. */ + compactRegion = false; /** Native class fields with different property names cannot occupy the * same slot of one object. Inherited views of the same property share a @@ -1476,6 +1478,8 @@ export class LlEmitter { } } this.shapeHost = { + compactArrayElem: (elem) => this.compactArrayElem(elem), + compactRegion: () => this.compactRegion, sizeType: this.sizeType, cycleBufOffset: this.cycleBufOffset, tracedShapes: this.tracedShapes, @@ -1605,22 +1609,19 @@ export class LlEmitter { ? (cls, i, isCompact) => { const f = cls.fields[i]!; if (this.inlineUnions.classField(cls.name, f.name)) return false; - const t = f.type; - if (t.kind === "object") return isCompact(t.className); - if (t.kind !== "union") return false; - const single = this.nullableUnions.single(t.unionId); - if (single !== null) - return ( - single.nullTag < 0 && - single.arm.kind === "object" && - isCompact(single.arm.className) - ); - const nullable = this.nullableFields.get(cls.name, f.name); + if (this.compactRefType(f.type, isCompact)) return true; + const nullable = + f.type.kind === "union" && this.nullableUnions.single(f.type.unionId) === null + ? this.nullableFields.get(cls.name, f.name) + : null; return nullable !== null && isCompact(nullable.arm.className); } : undefined, ); - this.usesCompactRefs = [...this.classMeta.values()].some((m) => m.compressed.some(Boolean)); + this.compactRegion = + mod.lib === undefined && + options.lowRegion === true && + [...this.classMeta.values()].some((m) => m.compact); for (const [name, rec] of RUNTIME_ERROR_CLASSES) { const meta = this.classMeta.get(name); if (!meta) break; // hand-written IR without the builtin defs: no stamps @@ -2232,7 +2233,7 @@ export class LlEmitter { B.condBr(thrown, rejected, clean); B.startBlock(clean); if (acc === "ref") this.toHeap(value); - this.arrPush(values, acc, value.name); + this.arrPush(values, acc, value.name, elem); B.br(next); B.startBlock(rejected); const promise = B.tmp(); @@ -3585,6 +3586,30 @@ export class LlEmitter { return { ptr: p, type, inline: this.inlineUnions.classField(className, field), compressed }; } + /** Whether values of `t` are NULL or a compact class instance: `C`, + * `C | undefined` or `C | null` for a compact class `C`. `C | null | + * undefined` is not: its null is a sentinel outside the region. */ + compactRefType( + t: IrType, + isCompact: (className: string) => boolean = (name) => + this.classMeta.get(name)?.compact === true, + ): boolean { + if (t.kind === "object") return isCompact(t.className); + if (t.kind !== "union") return false; + const single = this.nullableUnions.single(t.unionId); + return ( + single !== null && + single.nullTag < 0 && + single.arm.kind === "object" && + isCompact(single.arm.className) + ); + } + + /** Whether arrays of `elem` hold 32-bit references (SCR_ELEM_CREF). */ + compactArrayElem(elem: IrType): boolean { + return this.compactRegion && this.compactRefType(elem); + } + /** Loads the reference a field pointer addresses: a pointer, or the * decoded 32-bit reference of a compressed field (compressedFieldPtrs). * `tagged`: the load carries the field's alias tags. */ @@ -4032,7 +4057,7 @@ export class LlEmitter { const acc = boxAccess(t); const cell = B.tmp(); B.line(`${cell} = ${arrNewCall(this.shapeHost, t, "1")} ; TDZ cell`); - this.arrPush(cell, acc === "bool" ? "bool" : "f64", value); + this.arrPush(cell, acc === "bool" ? "bool" : "f64", value, null); this.declare(`declare void @scr_box_set_ref(ptr, ptr)`); B.line(`call void @scr_box_set_ref(ptr ${box}, ptr ${cell})`); } @@ -6182,8 +6207,8 @@ export class LlEmitter { return tagInSet(this, uName, unionId, tags); } - arrPush(arr: string, acc: "f64" | "bool" | "ref", value: string): string { - return arrPush(this, arr, acc, value); + arrPush(arr: string, acc: "f64" | "bool" | "ref", value: string, element: IrType | null): string { + return arrPush(this, arr, acc, value, element); } emitArrayCopyLoop(dst: string, src: string, acc: "f64" | "bool" | "ref"): void { diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 8970aa3be..4ddb5e75d 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -102,13 +102,17 @@ export function tagInSet( return acc; } +/** `element`: the array's element type, or null for arrays whose + * elements are not compact class references (dense-array-access.ts + * slotKind). */ export function arrPush( host: LlvmEmitterContext, arr: string, acc: "f64" | "bool" | "ref", value: string, + element: IrType | null, ): string { - return emitDenseArrayPush(host, arr, acc, value); + return emitDenseArrayPush(host, arr, acc, element, value); } /** Move evaluated values through one bounded slot buffer per call site. */ @@ -116,6 +120,7 @@ export function emitArrayValues( host: LlvmEmitterContext, arr: string, acc: "f64" | "bool" | "ref", + element: IrType, values: LlValue[], prepend = false, sharedBuffer?: string, @@ -129,7 +134,7 @@ export function emitArrayValues( return result; } if (values.length === 1) { - if (!prepend) return arrPush(host, arr, acc, values[0]!.name); + if (!prepend) return arrPush(host, arr, acc, values[0]!.name, element); const ty = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr"; host.declare( `declare double @scr_arr_unshift_${acc}(ptr, ${ty}${acc === "bool" ? " zeroext" : ""})`, @@ -628,7 +633,7 @@ export function emitArrIntrinsic( // no-op zero-argument call. const vs = e.args.map((a) => host.emitExpr(a)); host.emitPublishedArrayGuard(r.name, e.receiver.type, 1, f64Lit(0), f64Lit(vs.length)); - return { name: emitArrayValues(host, r.name, acc, vs), type: e.type }; + return { name: emitArrayValues(host, r.name, acc, elem, vs), type: e.type }; } case "pushSpread": { // `a.push(...src)`: append src's elements in order (borrowed src, @@ -660,7 +665,7 @@ export function emitArrIntrinsic( // from right to left so the final front order is source order. const vs = e.args.map((a) => host.emitExpr(a)); host.emitPublishedArrayGuard(r.name, e.receiver.type, 4, f64Lit(0), f64Lit(vs.length)); - return { name: emitArrayValues(host, r.name, acc, vs, true), type: e.type }; + return { name: emitArrayValues(host, r.name, acc, elem, vs, true), type: e.type }; } case "unshiftSpread": { // The runtime snapshots the borrowed source and handles self-spread. @@ -702,7 +707,7 @@ export function emitArrIntrinsic( let slowLabel = ""; if (method === "pop") { slowLabel = B.newLabel("remove.slow"); - denseRaw = emitDenseArrayPop(host, r.name, acc, la, slowLabel); + denseRaw = emitDenseArrayPop(host, r.name, acc, elem, la, slowLabel); denseLabel = B.currentLabel(); B.br(lp); B.startBlock(slowLabel); @@ -771,7 +776,7 @@ export function emitArrIntrinsic( // by content, everything else by pointer). Strict equality. Arrays of // objects and strings scan inline (array-search.ts). const v = host.emitExpr(e.args[0]!); - const search = acc === "ref" ? arraySearchKind(elem) : null; + const search = acc === "ref" ? arraySearchKind(elem, host.compactArrayElem(elem)) : null; if (search !== null) { host.arraySearchKinds.add(search); const t = B.tmp(); @@ -789,7 +794,7 @@ export function emitArrIntrinsic( // Borrowed needle, SameValueZero (NaN matches NaN). For the inline // searches SameValueZero is strict equality. const v = host.emitExpr(e.args[0]!); - const search = acc === "ref" ? arraySearchKind(elem) : null; + const search = acc === "ref" ? arraySearchKind(elem, host.compactArrayElem(elem)) : null; if (search !== null) { host.arraySearchKinds.add(search); const at = B.tmp(), diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 354004e9e..02a9f971f 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -32,7 +32,7 @@ import { emitPowerOfTwoRemainder, emitSignedIntegerRemainder, } from "./integer-remainder.js"; -import { emitDenseArrayGet, emitDenseArrayState, slotWidth } from "./dense-array-access.js"; +import { denseSlotWidth, emitDenseArrayGet, emitDenseArrayState } from "./dense-array-access.js"; import { emitWrappingSum, markWrappingOperands } from "./wrapping-sums.js"; export function emitLiteralExpr( @@ -879,7 +879,7 @@ export function emitContainerExpr( buffer = B.tmp(); B.entryAllocas.push(`${buffer} = alloca [${Math.min(e.elems.length, 64)} x i64]`); } - if (pending.length > 0) emitArrayValues(host, arr, acc, pending, false, buffer); + if (pending.length > 0) emitArrayValues(host, arr, acc, elem, pending, false, buffer); pending = []; }; e.elems.forEach((el, i) => { @@ -924,7 +924,7 @@ export function emitContainerExpr( } const bound = B.tmp(); B.line(`${bound} = fsub double ${n.name}, ${f64Lit(1)}`); - B.countedLoop(bound, () => host.arrPush(arr, acc, fill), "ole"); + B.countedLoop(bound, () => host.arrPush(arr, acc, fill, elem), "ole"); return out; } case "arrayGet": { @@ -962,7 +962,7 @@ export function emitContainerExpr( idx, e.index, "has", - slotWidth(elemAccess(e.arr.type.elem)), + denseSlotWidth(host, e.arr.type.elem), ); return { name: t, type: e.type }; } @@ -977,7 +977,7 @@ export function emitContainerExpr( idx, e.index, "state", - slotWidth(elemAccess(e.arr.type.elem)), + denseSlotWidth(host, e.arr.type.elem), ); return { name: t, type: e.type }; } diff --git a/packages/compiler/src/backend/llvm/lib-filesystem.ts b/packages/compiler/src/backend/llvm/lib-filesystem.ts index 6d5fe652d..7d9be632d 100644 --- a/packages/compiler/src/backend/llvm/lib-filesystem.ts +++ b/packages/compiler/src/backend/llvm/lib-filesystem.ts @@ -163,7 +163,7 @@ function emitObjEntryPairs(host: LlvmEmitterContext, e: LibCallExpr): LlValue { B.line(`${row} = call ptr @${mangleRecordNew(rowT.shapeId)}()`); host.storeField(host.recordFieldPtr(row, rowT.shapeId, "0").ptr, STRING, key, false); host.storeField(host.recordFieldPtr(row, rowT.shapeId, "1").ptr, DYN, item, false); - host.arrPush(arr, "ref", row); // push takes ownership of the row + host.arrPush(arr, "ref", row, null); // push takes ownership of the row const next = B.tmp(); B.line(`${next} = add ${size} ${i}, 1`); B.line(`store ${size} ${next}, ptr ${iSlot}`); @@ -536,7 +536,7 @@ export function emitFilesystemLibCall(host: LlvmEmitterContext, e: LibCallExpr): const parent = B.tmp(); B.line(`${parent} = call ptr @scr_fs_glob_parent(ptr ${snap}, ${host.sizeType} ${i}) ; +1`); B.line(`store ptr ${parent}, ptr ${host.recordFieldPtr(row, recT.shapeId, "parentPath").ptr}`); - host.arrPush(arr, "ref", row); // push takes ownership of the row + host.arrPush(arr, "ref", row, null); // push takes ownership of the row const i2 = B.tmp(); B.line(`${i2} = add ${host.sizeType} ${i}, 1`); B.line(`store ${host.sizeType} ${i2}, ptr ${iSlot}`); @@ -620,7 +620,7 @@ export function emitFilesystemLibCall(host: LlvmEmitterContext, e: LibCallExpr): B.line( `store ptr ${host.retainHeap(path.name, STRING)}, ptr ${host.recordFieldPtr(row, recT.shapeId, "parentPath").ptr}`, ); - host.arrPush(arr, "ref", row); // push takes ownership of the row + host.arrPush(arr, "ref", row, null); // push takes ownership of the row const i2 = B.tmp(); B.line(`${i2} = add ${host.sizeType} ${i}, 1`); B.line(`store ${host.sizeType} ${i2}, ptr ${iSlot}`); @@ -955,7 +955,7 @@ export function emitPathUrlLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll B.startBlock(lj); const rows = B.tmp(); B.line(`${rows} = load ptr, ptr ${rowsSlot}`); - host.arrPush(rows, "ref", row); // push takes ownership of the row + host.arrPush(rows, "ref", row, null); // push takes ownership of the row B.line(`call void @scr_arr_release(ptr ${rows})`); B.line(`call void @scr_str_release(ptr ${nm})`); const i2 = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/local-array-reads.ts b/packages/compiler/src/backend/llvm/local-array-reads.ts index cdd00c4e7..223d45540 100644 --- a/packages/compiler/src/backend/llvm/local-array-reads.ts +++ b/packages/compiler/src/backend/llvm/local-array-reads.ts @@ -15,6 +15,13 @@ import { ReferenceEffects } from "./reference-effects.js"; import { SCR_ARR_FIELD, loadArrCount, scrArrStateAt } from "./common.js"; import { exactInteger, widenInteger } from "./integer-values.js"; import { READ_FALLBACK } from "./dense-array-access.js"; +import { compactRefLoadLines } from "./classes.js"; + +/** The dense slot load of a reference read from an array of type + * `arrayType`: a pointer, or a compact class reference (SCR_ELEM_CREF). */ +function referenceLoad(host: LlvmEmitterContext, arrayType: IrType): "ptr" | "cref" { + return arrayType.kind === "array" && host.compactArrayElem(arrayType.elem) ? "cref" : "ptr"; +} export interface LocalArrayRead { type: IrType; @@ -469,7 +476,7 @@ function emitDenseReferenceArrayRead( no: string, slow: string, join: string, - loadType: "ptr" | "i64" | "i8" = "ptr", + loadType: "ptr" | "cref" | "i64" | "i8" = "ptr", ): void { const B = host.B; const header = (field: number): string => { @@ -555,7 +562,14 @@ function emitDenseReferenceArrayRead( const statePtr = B.tmp(), denseState = B.tmp(), densePresent = B.tmp(); - scrArrStateAt(host, statePtr, data, cap, loadType === "i8" ? 1 : 8, offset); + scrArrStateAt( + host, + statePtr, + data, + cap, + loadType === "i8" ? 1 : loadType === "cref" ? 4 : 8, + offset, + ); host.markMemoryPointer(statePtr, "array:present"); B.line(`${denseState} = load i8, ptr ${statePtr}${host.fieldAliasAttachment(statePtr)}`); B.line(`${densePresent} = icmp eq i8 ${denseState}, 1`); @@ -564,13 +578,20 @@ function emitDenseReferenceArrayRead( B.startBlock(valueLabel); const valuePtr = B.tmp(), raw = B.tmp(); - // Boolean arrays store one byte per element; every other kind an 8-byte slot. - const slotType = loadType === "i8" ? "i8" : "i64"; + // Boolean arrays store one byte per element, compact references four, + // every other kind an 8-byte slot. + const slotType = loadType === "i8" ? "i8" : loadType === "cref" ? "i32" : "i64"; B.line( `${valuePtr} = getelementptr inbounds ${slotType}, ptr ${data}, ${host.sizeType} ${offset}`, ); host.markMemoryPointer(valuePtr, "array:elements"); - B.line(`${raw} = load ${loadType}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + if (loadType === "cref") { + const ref = B.tmp(); + B.line(`${ref} = load i32, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + for (const line of compactRefLoadLines(ref, raw, `${raw}.r`)) B.line(line.trimStart()); + } else { + B.line(`${raw} = load ${loadType}, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + } present(raw); B.br(join); } @@ -622,6 +643,7 @@ export function emitBorrowedArrayRead( slow, slow, join, + referenceLoad(host, read.arr.type), ); B.startBlock(slow); host.declare("declare ptr @scr_arr_borrow_ref(ptr, double)"); @@ -670,7 +692,7 @@ export function emitLocalArrayRead( no, slow, join, - "ptr", + referenceLoad(host, read.array.type), ); else B.br(slow); B.startBlock(slow); @@ -731,7 +753,7 @@ export function emitLocalArrayRead( no, slow, join, - !scalar ? "ptr" : read.element.kind === "bool" ? "i8" : "i64", + !scalar ? referenceLoad(host, read.array.type) : read.element.kind === "bool" ? "i8" : "i64", ); else B.br(slow); B.startBlock(slow); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index 6de92f667..22416fa8f 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -71,6 +71,12 @@ export interface ShapeHost { /** The hierarchy root of a class (a program class or a runtime base), * or undefined for classes outside the class graph. */ classRootOf?(className: string): string | undefined; + /** Whether arrays of `elem` hold 32-bit references to compact class + * instances (SCR_ELEM_CREF; LlEmitter.compactArrayElem). */ + compactArrayElem?(elem: IrType): boolean; + /** Whether compact class instances live in the program-lifetime region + * (LlEmitter.compactRegion). */ + compactRegion?(): boolean; /** Byte offset from an object pointer back to ScrCycHdr.buf. */ readonly cycleBufOffset: number; declare(decl: string): void; @@ -1076,18 +1082,30 @@ export function arrNewCall( /** The %ScrArrOps descriptor (retain, release, trace, registry id) of a REF * element type, defined once per module and shared by all its arrays. It is - * writable: the runtime stores its registry id on the first array. */ + * writable: the runtime stores its registry id on the first array. Its tail + * padding is the runtime's flags word (0); arrays of compact class + * references (ShapeHost.compactArrayElem) spell the word out as + * SCR_ARR_OPS_COMPACT. */ export function arrOps(host: ShapeHost, elem: IrType): string { const v = vAdapters(host, elem); const trace = traceArg(host, elem); const part = (sym: string): string => sym.replace(/^@/, "").replace(/[^A-Za-z0-9_.]/g, "_"); const name = `@sc_arrops.${part(v.retain)}.${part(v.release)}.${part(trace)}`; + if (host.compactArrayElem?.(elem) === true) { + host.declare( + `${name}.c = internal global { ptr, ptr, ptr, i32, i32 } { ptr ${v.retain}, ptr ${v.release}, ptr ${trace}, i32 0, i32 ${SCR_ARR_OPS_COMPACT} }`, + ); + return `${name}.c`; + } host.declare( `${name} = internal global %ScrArrOps { ptr ${v.retain}, ptr ${v.release}, ptr ${trace}, i32 0 }`, ); return name; } +/** scr_array.h SCR_ARR_OPS_COMPACT. */ +const SCR_ARR_OPS_COMPACT = 1; + /* ── capture boxes ────────────────────────────────────────────────────── */ /** Box construction call text (boxNewC's dispatch): plain-kind boxes for diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/4638-contract-program-lifetime-arrays.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/4638-contract-program-lifetime-arrays.ts.json new file mode 100644 index 000000000..a89ae97b8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/4638-contract-program-lifetime-arrays.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/4638-contract-program-lifetime-arrays.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_array.c b/packages/runtime/src/scr_array.c index c00d1b4f6..50b461614 100644 --- a/packages/runtime/src/scr_array.c +++ b/packages/runtime/src/scr_array.c @@ -60,9 +60,10 @@ static void *scr_arr_alloc_start(const ScrArr *a) { return (char *)scr_arr_block(a) - scr_arr_prefix(a); } -/* Bytes per dense slot with its state: an 8-byte value, or a boolean byte. */ +/* Bytes per dense slot with its state: an 8-byte value, a boolean byte or + * a 4-byte compact reference. */ static size_t scr_arr_slot_unit(const ScrArr *a) { - return a->elem == SCR_ELEM_BOOL ? 2 * sizeof(uint8_t) : sizeof(uint64_t) + sizeof(uint8_t); + return scr_arr_slot_width(a) + sizeof(uint8_t); } /* Bytes of dense storage (head room included) after the prefix. */ @@ -212,6 +213,11 @@ static bool scr_elem_is_ref(ScrElemKind k) { k == SCR_ELEM_REF; } +/* Whether `a`'s element type comes with element ops (scr_arr_ops). */ +static bool scr_arr_has_ops(const ScrArr *a) { + return a->elem == SCR_ELEM_REF || a->elem == SCR_ELEM_CREF; +} + /* Releases an element slot of kind `elem`, with element ops `ops` for * SCR_ELEM_REF. An array's kind and ops never change, so loops look them up * once (element releases may run teardown, which reloads anything read @@ -266,6 +272,7 @@ typedef struct { static uint64_t scr_arr_storage_get(const ScrArrStorage *s, size_t index) { if (s->elem == SCR_ELEM_BOOL) return ((const uint8_t *)s->data)[index]; + if (s->elem == SCR_ELEM_CREF) return scr_cref_decode(((const uint32_t *)s->data)[index]); return s->data[index]; } @@ -388,9 +395,17 @@ static void scr_arr_sparse_drop_prefix(ScrArr *a, size_t count) { } /* Bytes per dense slot: the value and its state byte. Boolean arrays - * store a one-byte value. */ + * store a one-byte value, compact reference arrays a 4-byte one. */ #define SCR_ARR_SLOT_BYTES (sizeof(uint64_t) + sizeof(uint8_t)) #define SCR_ARR_BOOL_SLOT_BYTES (2 * sizeof(uint8_t)) +#define SCR_ARR_CREF_SLOT_BYTES (sizeof(uint32_t) + sizeof(uint8_t)) + +/* SCR_ARR_*_SLOT_BYTES for an element kind. */ +static size_t scr_elem_slot_unit(uint8_t elem) { + return elem == SCR_ELEM_BOOL ? SCR_ARR_BOOL_SLOT_BYTES + : elem == SCR_ELEM_CREF ? SCR_ARR_CREF_SLOT_BYTES + : SCR_ARR_SLOT_BYTES; +} /* Appends to an array smaller than this grow straight to it. */ #define SCR_ARR_MIN_GROWTH ((size_t)4) @@ -469,7 +484,7 @@ static void scr_arr_drop_head(ScrArr *a) { * for storage without head room (booleans, inline slots); the caller then * moves the tail down itself. */ static bool scr_arr_drop_front(ScrArr *a, size_t count) { - if (a->elem == SCR_ELEM_BOOL || scr_arr_inline(a)) return false; + if (scr_arr_slot_width(a) != sizeof(uint64_t) || scr_arr_inline(a)) return false; if (count == 0) return true; size_t head = scr_arr_head(a); memset(scr_arr_state_run(a, 0, count), SCR_ARR_HOLE, count); @@ -504,18 +519,21 @@ static bool scr_arr_drop_front(ScrArr *a, size_t count) { #endif /* Inline capacity of a small construction with `prefix` bytes of block - * before the slots. */ -static size_t scr_arr_small_cap(size_t prefix, bool bools) { + * before the slots of `unit` bytes (SCR_ARR_*_SLOT_BYTES). */ +static size_t scr_arr_small_cap(size_t prefix, size_t unit) { #if SCR_SMALL_ALLOC /* One return per slot unit, so each folds to a constant at its callers. */ - if (bools) + if (unit == SCR_ARR_BOOL_SLOT_BYTES) return (scr_sa_class_size(scr_sa_class(prefix + SCR_ARR_SMALL_SLOTS * SCR_ARR_BOOL_SLOT_BYTES)) - prefix) / SCR_ARR_BOOL_SLOT_BYTES; + if (unit == SCR_ARR_CREF_SLOT_BYTES) + return (scr_sa_class_size(scr_sa_class(prefix + SCR_ARR_SMALL_SLOTS * SCR_ARR_CREF_SLOT_BYTES)) - prefix) / + SCR_ARR_CREF_SLOT_BYTES; return (scr_sa_class_size(scr_sa_class(prefix + SCR_ARR_SMALL_SLOTS * SCR_ARR_SLOT_BYTES)) - prefix) / SCR_ARR_SLOT_BYTES; #else (void)prefix; - (void)bools; + (void)unit; return SCR_ARR_SMALL_SLOTS; #endif } @@ -528,26 +546,27 @@ static size_t scr_arr_small_cap(size_t prefix, bool bools) { #define SCR_ARR_KNOWN_INLINE_MAX ((size_t)16) /* Inline capacity of a construction of `need` elements with `prefix` bytes - * of block before the slots, rounded up to fill the block; 0 when its slots - * stay separate. */ -static size_t scr_arr_known_cap(size_t prefix, size_t need, bool bools) { + * of block before the slots of `unit` bytes (SCR_ARR_*_SLOT_BYTES), rounded + * up to fill the block; 0 when its slots stay separate. */ +static size_t scr_arr_known_cap(size_t prefix, size_t need, size_t unit) { if (need == 0 || need > SCR_ARR_KNOWN_INLINE_MAX) return 0; #if SCR_SMALL_ALLOC - size_t unit = bools ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES; size_t bytes = prefix + need * unit; if (bytes > SCR_SA_MAX) return 0; return (scr_sa_class_size(scr_sa_class(bytes)) - prefix) / unit; #else (void)prefix; - (void)bools; + (void)unit; return need; #endif } -static void scr_arr_use_inline(ScrArr *a, size_t cap) { +/* Points `a` at `cap` inline slots of `unit` bytes (SCR_ARR_*_SLOT_BYTES), + * all holes. */ +static void scr_arr_use_inline(ScrArr *a, size_t cap, size_t unit) { a->data = (uint64_t *)((char *)a + SCR_ARR_INLINE_OFFSET); a->cap = (uint32_t)cap; - memset(scr_arr_state_run(a, 0, cap), SCR_ARR_HOLE, cap); + memset((char *)a->data + cap * (unit - 1), SCR_ARR_HOLE, cap); a->spare |= SCR_ARR_INLINE_SLOTS; } @@ -582,15 +601,15 @@ typedef enum { * reallocation. Growth keeps its own sequence (4, 8, 16, ...): rounding it * as well moves array storage into other size classes and measured * slower. */ -static size_t scr_arr_block_cap(size_t cap, bool bools) { +static size_t scr_arr_block_cap(size_t cap, size_t unit) { #if SCR_SMALL_ALLOC - size_t bytes = cap * (bools ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES); + size_t bytes = cap * unit; if (bytes <= SCR_SA_MAX) { size_t block = scr_sa_class_size(scr_sa_class((bytes + 15) & ~(size_t)15)); - return bools ? block / SCR_ARR_BOOL_SLOT_BYTES : block / SCR_ARR_SLOT_BYTES; + return block / unit; } #else - (void)bools; + (void)unit; #endif return cap; } @@ -609,14 +628,14 @@ static void scr_arr_grow_dense_slow(ScrArr *a, size_t need, ScrArrGrow mode); * paths pick the same capacity. */ static inline void scr_arr_grow_dense_to(ScrArr *a, size_t need, ScrArrGrow mode) { if (need <= a->cap) return; - if (a->elem == SCR_ELEM_BOOL || (a->spare & (SCR_ARR_INLINE_SLOTS | SCR_ARR_HEAD_ROOM | SCR_ARR_HAS_EXT)) || - need > SCR_ARR_DENSE_LIMIT) { + if (a->elem == SCR_ELEM_BOOL || a->elem == SCR_ELEM_CREF || + (a->spare & (SCR_ARR_INLINE_SLOTS | SCR_ARR_HEAD_ROOM | SCR_ARR_HAS_EXT)) || need > SCR_ARR_DENSE_LIMIT) { scr_arr_grow_dense_slow(a, need, mode); return; } size_t cap; if (mode == SCR_ARR_GROW_EXACT) { - cap = scr_arr_block_cap(need, false); + cap = scr_arr_block_cap(need, SCR_ARR_SLOT_BYTES); } else { cap = a->cap < SCR_ARR_MIN_GROWTH ? SCR_ARR_MIN_GROWTH : a->cap; while (cap < need) cap += cap; @@ -660,12 +679,11 @@ static void scr_arr_grow_dense_slow(ScrArr *a, size_t need, ScrArrGrow mode) { mode = SCR_ARR_GROW_APPEND; } } - bool bools = a->elem == SCR_ELEM_BOOL; size_t width = scr_arr_slot_width(a); - size_t unit = bools ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES; + size_t unit = scr_arr_slot_unit(a); size_t cap; if (mode == SCR_ARR_GROW_EXACT) { - cap = scr_arr_block_cap(need, bools); + cap = scr_arr_block_cap(need, unit); } else { /* Inline slots overflow into the ordinary sequence (4, 8, 16, ...). */ size_t from = scr_arr_inline(a) ? 0 : a->cap; @@ -723,7 +741,7 @@ static void scr_arr_grow_dense(ScrArr *a, size_t need) { * array's allocation. Returns false when the caller must move the elements * itself. */ static bool scr_arr_open_head(ScrArr *a, size_t count) { - if (a->elem == SCR_ELEM_BOOL || scr_arr_inline(a)) return false; + if (scr_arr_slot_width(a) != sizeof(uint64_t) || scr_arr_inline(a)) return false; size_t head = scr_arr_head(a); if (head < count) { size_t len = a->len; @@ -851,6 +869,20 @@ static inline uint8_t scr_arr_state_at(const ScrArr *a, size_t index, uint64_t * return sparse.state; } +/* scr_arr_state_at for a number[] (SCR_ELEM_F64): 8-byte slots, with no + * element-kind test. */ +static inline uint8_t scr_arr_f64_state_at(const ScrArr *a, size_t index, uint64_t *out) { + if (index < a->cap) { + uint8_t state = *scr_arr_state_in(scr_arr_states_end_w(a, 8), index); + if (state == SCR_ARR_HOLE) return SCR_ARR_HOLE; + *out = a->data[index]; + return state; + } + ScrArrStateSlot sparse = scr_arr_sparse_state_at(a, index); + if (sparse.state != SCR_ARR_HOLE) *out = sparse.slot; + return sparse.state; +} + static inline bool scr_arr_slot_at(const ScrArr *a, size_t index, uint64_t *out) { return scr_arr_state_at(a, index, out) != SCR_ARR_HOLE; } @@ -1148,9 +1180,10 @@ static void scr_arr_copy_dense(ScrArr *dst, size_t to, const ScrArr *src, if (count == 0) return; scr_arr_cut(dst, to); /* 8-byte slots: a constant slot size, and constant-width state ends. */ - bool wide = dst->elem != SCR_ELEM_BOOL; - uint8_t *dst_states = wide ? scr_arr_states_end_w(dst, 8) : scr_arr_states_end_w(dst, 1); - const uint8_t *src_states = wide ? scr_arr_states_end_w(src, 8) : scr_arr_states_end_w(src, 1); + size_t width = scr_arr_slot_width(dst); + bool wide = width == sizeof(uint64_t); + uint8_t *dst_states = wide ? scr_arr_states_end_w(dst, 8) : scr_arr_states_end_w(dst, width); + const uint8_t *src_states = wide ? scr_arr_states_end_w(src, 8) : scr_arr_states_end_w(src, width); if (!reverse && wide) { scr_arr_copy_slots(dst->data + to, src->data + from, count); /* A range below the source's hole-free prefix holds only values. */ @@ -1185,21 +1218,28 @@ static void scr_arr_copy_dense(ScrArr *dst, size_t to, const ScrArr *src, /* Store `count` 8-byte value slots into dense storage starting at `to`. */ static void scr_arr_put_slots(ScrArr *a, size_t to, size_t count, const uint64_t *slots) { - if (a->elem != SCR_ELEM_BOOL) { + if (scr_arr_slot_width(a) == sizeof(uint64_t)) { scr_arr_copy_slots(a->data + to, slots, count); return; } for (size_t i = 0; i < count; i++) scr_arr_dense_put(a, to + i, slots[i]); } +/* The slot unit of an array that scr_arr_new, scr_arr_new_small or + * scr_arr_new_inline makes. Their kinds have no element ops, so they are + * never SCR_ELEM_CREF (scr_arr_new_ops makes those). */ +static size_t scr_arr_plain_slot_unit(ScrElemKind elem) { + return elem == SCR_ELEM_BOOL ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES; +} + /* Inlined into each constructor, so `small` and the slot unit fold to * constants there. */ static inline __attribute__((always_inline)) ScrArr *scr_arr_make(ScrElemKind elem, size_t initial_cap, bool small) { - size_t unit = elem == SCR_ELEM_BOOL ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES; - size_t inline_cap = small ? scr_arr_small_cap(SCR_ARR_INLINE_OFFSET, elem == SCR_ELEM_BOOL) - : scr_arr_known_cap(SCR_ARR_INLINE_OFFSET, initial_cap, elem == SCR_ELEM_BOOL); + size_t unit = scr_arr_plain_slot_unit(elem); + size_t inline_cap = small ? scr_arr_small_cap(SCR_ARR_INLINE_OFFSET, unit) + : scr_arr_known_cap(SCR_ARR_INLINE_OFFSET, initial_cap, unit); ScrArr *a = scr_mem_alloc(inline_cap ? SCR_ARR_INLINE_OFFSET + inline_cap * unit : sizeof(ScrArr)); if (!a) scr_arr_oom(); a->rc = 1; @@ -1210,7 +1250,7 @@ static inline __attribute__((always_inline)) ScrArr *scr_arr_make(ScrElemKind el a->spare = 0; a->filled = 0; a->data = NULL; - if (inline_cap) scr_arr_use_inline(a, inline_cap); + if (inline_cap) scr_arr_use_inline(a, inline_cap, unit); else if (initial_cap > 0) scr_arr_grow_dense_to(a, initial_cap, SCR_ARR_GROW_EXACT); #ifdef SCR_RC_AUDIT scr_live_arrays++; @@ -1231,7 +1271,7 @@ ScrArr *scr_arr_new_small(ScrElemKind elem) { return scr_arr_make(elem, 0, true) ScrArr *scr_arr_new_inline(ScrElemKind elem, size_t cap) { if (cap == 0) return scr_arr_make(elem, 0, false); if (cap > SCR_ARR_MAX_LENGTH) scr_arr_oom(); - size_t unit = elem == SCR_ELEM_BOOL ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES; + size_t unit = scr_arr_plain_slot_unit(elem); ScrArr *a = scr_mem_alloc(SCR_ARR_INLINE_OFFSET + cap * unit); if (!a) scr_arr_oom(); a->rc = 1; @@ -1242,7 +1282,7 @@ ScrArr *scr_arr_new_inline(ScrElemKind elem, size_t cap) { a->spare = 0; a->filled = 0; a->data = NULL; - scr_arr_use_inline(a, cap); + scr_arr_use_inline(a, cap, unit); #ifdef SCR_RC_AUDIT scr_live_arrays++; #endif @@ -1250,9 +1290,7 @@ ScrArr *scr_arr_new_inline(ScrElemKind elem, size_t cap) { } void scr_arr_outline(ScrArr *a) { - if (scr_arr_inline(a)) - scr_arr_move_inline(a, a->cap, - a->elem == SCR_ELEM_BOOL ? SCR_ARR_BOOL_SLOT_BYTES : SCR_ARR_SLOT_BYTES); + if (scr_arr_inline(a)) scr_arr_move_inline(a, a->cap, scr_arr_slot_unit(a)); /* The swapped fields do not include `spare`: no head room either. */ if (a->spare & SCR_ARR_HEAD_ROOM) { scr_arr_drop_head(a); @@ -1329,18 +1367,20 @@ static void scr_arr_gc_free(void *a0) { scr_cyc_free_inline(a); } -/* Inlined into each constructor like scr_arr_make: with `small` and the - * count constant, scr_arr_new_ops_small's size class folds to a table - * index. */ -static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrArrOps *ops, - size_t initial_cap, - bool small) { +/* Inlined into each constructor like scr_arr_make: with `small`, the count + * and `elem` constant, scr_arr_new_ops_small's size class folds to a table + * index and the slot sizes to constants. */ +static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops_kind(const ScrArrOps *ops, + size_t initial_cap, + bool small, + uint8_t elem) { ScrArr *a; bool cyc = ops->trace != NULL; + size_t unit = scr_elem_slot_unit(elem); size_t prefix = SCR_ARR_INLINE_OFFSET + (cyc ? sizeof(ScrCycHdr) : 0); size_t inline_cap = - small ? scr_arr_small_cap(prefix, false) : scr_arr_known_cap(prefix, initial_cap, false); - size_t size = inline_cap ? SCR_ARR_INLINE_OFFSET + inline_cap * SCR_ARR_SLOT_BYTES : sizeof(ScrArr); + small ? scr_arr_small_cap(prefix, unit) : scr_arr_known_cap(prefix, initial_cap, unit); + size_t size = inline_cap ? SCR_ARR_INLINE_OFFSET + inline_cap * unit : sizeof(ScrArr); if (cyc) { static ScrCycType cyc_type = { &scr_arr_trace_v, &scr_arr_gc_free, SCR_CYC_KIND_ARRAY }; a = scr_cyc_alloc_inline(size, &cyc_type); @@ -1351,7 +1391,7 @@ static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrA a->rc = 1; a->len = 0; a->cap = 0; - a->elem = SCR_ELEM_REF; + a->elem = elem; a->cyc = cyc; /* The ops id is written with the other header fields: reading `spare` * back after scr_arr_use_inline sets its inline flag stalls the @@ -1360,7 +1400,7 @@ static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrA a->spare = (uint16_t)(id << SCR_ARR_OPS_SHIFT); a->filled = 0; a->data = NULL; - if (inline_cap) scr_arr_use_inline(a, inline_cap); + if (inline_cap) scr_arr_use_inline(a, inline_cap, unit); else if (initial_cap > 0) scr_arr_grow_dense_to(a, initial_cap, SCR_ARR_GROW_EXACT); /* After the storage: ops past the registry live in the ext, whose * pointer precedes the dense allocation, so inline slots move out first @@ -1372,6 +1412,16 @@ static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrA return a; } +/* SCR_ELEM_CREF for compact element types, SCR_ELEM_REF otherwise. Each + * branch inlines scr_arr_make_ops_kind with a constant kind. */ +static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrArrOps *ops, + size_t initial_cap, + bool small) { + if (__builtin_expect((ops->flags & SCR_ARR_OPS_COMPACT) != 0, 0)) + return scr_arr_make_ops_kind(ops, initial_cap, small, SCR_ELEM_CREF); + return scr_arr_make_ops_kind(ops, initial_cap, small, SCR_ELEM_REF); +} + ScrArr *scr_arr_new_ops(const ScrArrOps *ops, size_t initial_cap) { return scr_arr_make_ops(ops, initial_cap, false); } @@ -1676,6 +1726,7 @@ static ScrArr *scr_arr_fill_slot(ScrArr *a, uint64_t slot, uint8_t state, if (!refs && until <= a->cap) { if (state != SCR_ARR_VALUE) scr_arr_cut(a, from); if (a->elem == SCR_ELEM_BOOL) memset(scr_arr_dense_at(a, from), (int)slot, until - from); + else if (a->elem == SCR_ELEM_CREF) for (size_t i = from; i < until; i++) scr_arr_dense_put(a, i, slot); else for (size_t i = from; i < until; i++) a->data[i] = slot; memset(scr_arr_state_run(a, from, until - from), state, until - from); } else { @@ -1712,7 +1763,7 @@ double scr_math_max_arr(ScrArr *a) { double best = -INFINITY; for (size_t i = 0; i < a->len; i++) { uint64_t slot; - if (scr_arr_state_at(a, i, &slot) != SCR_ARR_VALUE) return NAN; + if (scr_arr_f64_state_at(a, i, &slot) != SCR_ARR_VALUE) return NAN; double v = scr_slot_to_f64(slot); if (isnan(v)) return v; if (v > best || (v == 0.0 && best == 0.0 && !signbit(v))) best = v; @@ -1724,7 +1775,7 @@ double scr_math_min_arr(ScrArr *a) { double best = INFINITY; for (size_t i = 0; i < a->len; i++) { uint64_t slot; - if (scr_arr_state_at(a, i, &slot) != SCR_ARR_VALUE) return NAN; + if (scr_arr_f64_state_at(a, i, &slot) != SCR_ARR_VALUE) return NAN; double v = scr_slot_to_f64(slot); if (isnan(v)) return v; if (v < best || (v == 0.0 && best == 0.0 && signbit(v))) best = v; @@ -1739,7 +1790,7 @@ double scr_math_hypot_arr(ScrArr *a) { bool has_nan = false; for (size_t i = 0; i < a->len; i++) { uint64_t slot; - if (scr_arr_state_at(a, i, &slot) != SCR_ARR_VALUE) { + if (scr_arr_f64_state_at(a, i, &slot) != SCR_ARR_VALUE) { has_nan = true; continue; } @@ -1754,7 +1805,7 @@ double scr_math_hypot_arr(ScrArr *a) { double correction = 0.0; for (size_t i = 0; i < a->len; i++) { uint64_t slot; - (void)scr_arr_state_at(a, i, &slot); + (void)scr_arr_f64_state_at(a, i, &slot); double v = scr_slot_to_f64(slot) / scale; double term = v * v - correction; double next = sum + term; @@ -1830,9 +1881,9 @@ void *scr_arr_peek_ref(const ScrArr *a, double i) { if (i >= 0 && i < (double)a->cap) { size_t idx = (size_t)i; if ((double)idx == i) { - if (idx < a->filled) return scr_slot_to_ptr(a->data[idx]); + if (idx < a->filled) return scr_slot_to_ptr(scr_arr_dense_get(a, idx)); if (idx >= a->len || *scr_arr_state_ptr(a, idx) != SCR_ARR_VALUE) return NULL; - return scr_slot_to_ptr(a->data[idx]); + return scr_slot_to_ptr(scr_arr_dense_get(a, idx)); } } uint64_t slot; @@ -1886,7 +1937,7 @@ void *scr_arr_get_ref(ScrArr *a, double i) { if (a->elem == SCR_ELEM_STR) scr_str_retain((ScrStr *)p); else if (a->elem == SCR_ELEM_BYTES) scr_bytes_retain((ScrBytes *)p); else if (a->elem == SCR_ELEM_REF) p = scr_arr_ops(a)->retain(p); - else scr_arr_retain((ScrArr *)p); + else if (a->elem == SCR_ELEM_ARR) scr_arr_retain((ScrArr *)p); return p; } @@ -2395,7 +2446,7 @@ ScrArr *scr_arr_splice(ScrArr *a, double start, double deleteCount) { * otherwise the range may be mostly holes, so the capacity is a hint. */ size_t hint = scr_arr_is_dense(a) || n <= SCR_ARR_DENSE_LIMIT ? n : SCR_ARR_DENSE_LIMIT; ScrArr *out = - a->elem == SCR_ELEM_REF + scr_arr_has_ops(a) ? scr_arr_new_ops(scr_arr_ops(a), hint ? hint : 1) : scr_arr_new(a->elem, hint ? hint : 1); out->len = n; @@ -2475,7 +2526,7 @@ ScrArr *scr_arr_splice_insert(ScrArr *a, double start, double deleteCount, * is needed only by direct self-spread runtime callers. */ ScrArr *snapshot = items == a ? scr_arr_slice(a, 0, INFINITY) : NULL; if (snapshot) items = snapshot; - ScrArr *removed = a->elem == SCR_ELEM_REF + ScrArr *removed = scr_arr_has_ops(a) ? scr_arr_new_ops(scr_arr_ops(a), n) : scr_arr_new(a->elem, n); if (n) { @@ -2521,7 +2572,7 @@ void scr_arr_splice_drop(ScrArr *a, double start, double deleteCount, size_t cou size_t next_len = a->len - n + count; bool refs = scr_elem_is_ref(a->elem); if (!scr_arr_is_dense(a) || !scr_arr_dense_ok(a, next_len, count)) { - ScrArr *items = a->elem == SCR_ELEM_REF + ScrArr *items = scr_arr_has_ops(a) ? scr_arr_new_ops(scr_arr_ops(a), count) : scr_arr_new(a->elem, count); scr_arr_push_many(items, count, slots); @@ -2636,7 +2687,8 @@ double scr_arr_index_of_bool(ScrArr *a, bool v) { double scr_arr_index_of_ref(ScrArr *a, void *v) { const uint8_t *states = scr_arr_states_end(a); for (size_t i = 0; i < a->cap && i < a->len; i++) { - if (*scr_arr_state_in(states, i) == SCR_ARR_VALUE && scr_arr_ref_eq(a, a->data[i], v)) return (double)i; + if (*scr_arr_state_in(states, i) == SCR_ARR_VALUE && scr_arr_ref_eq(a, scr_arr_dense_get(a, i), v)) + return (double)i; } for (size_t i = 0; i < SCR_AX(a)->sparse_len; i++) { if (SCR_AX(a)->sparse[i].state == SCR_ARR_VALUE && scr_arr_ref_eq(a, SCR_AX(a)->sparse[i].slot, v)) return (double)SCR_AX(a)->sparse[i].index; @@ -2727,11 +2779,12 @@ ScrArr *scr_arr_slice(ScrArr *a, double start, double end) { * sparse side store may be mostly holes, so its capacity is a hint. */ size_t hint = to <= a->cap || n <= SCR_ARR_DENSE_LIMIT ? n : SCR_ARR_DENSE_LIMIT; ScrArr *out = - a->elem == SCR_ELEM_REF + scr_arr_has_ops(a) ? scr_arr_new_ops(scr_arr_ops(a), hint ? hint : 1) : scr_arr_new(a->elem, hint ? hint : 1); out->len = n; - if (to <= a->cap && to <= a->filled && a->elem != SCR_ELEM_BOOL && !scr_elem_is_ref(a->elem)) { + if (to <= a->cap && to <= a->filled && scr_arr_slot_width(a) == sizeof(uint64_t) && + !scr_elem_is_ref(a->elem)) { /* Numbers below the source's hole-free prefix: values only. */ scr_arr_copy_slots(out->data, a->data + from, n); scr_arr_set_states(scr_arr_states_end_w(out, 8) - n, SCR_ARR_VALUE, n); @@ -3024,14 +3077,14 @@ static ScrSortCompare scr_sort_compare_for(const ScrArr *a, ScrClosure *f, uint3 bool multi = order >= 2; if (order != 0 && (arity != 2 || (order != 1 && order != -1 && !scr_sort_keys_valid(order)) || - (c.numbers ? key != NULL || multi : a->elem != SCR_ELEM_REF || key == NULL))) + (c.numbers ? key != NULL || multi : !scr_arr_has_ops(a) || key == NULL))) scr_trap("scriptc: invalid keyed sort\n"); if (!c.numbers) { c.borrowing = f->fn_borrowed != NULL; if (a->elem == SCR_ELEM_STR) c.retain = scr_sort_retain_str; else if (a->elem == SCR_ELEM_ARR) c.retain = scr_sort_retain_arr; else if (a->elem == SCR_ELEM_BYTES) c.retain = scr_sort_retain_bytes; - else if (a->elem == SCR_ELEM_REF) c.retain = scr_arr_ops(a)->retain; + else if (scr_arr_has_ops(a)) c.retain = scr_arr_ops(a)->retain; else scr_trap("scriptc: invalid comparator sort element kind\n"); } return c; @@ -4619,7 +4672,7 @@ static bool scr_arr_dense_values(const ScrArr *a) { * elements (stored in 1-byte slots). The slots are borrowed and stay valid * while nothing writes the array. */ const uint64_t *scr_arr_dense_slots(const ScrArr *a, size_t *len) { - if (a->len == 0 || a->elem == SCR_ELEM_BOOL || !scr_arr_dense_values(a)) return NULL; + if (a->len == 0 || scr_arr_slot_width(a) != sizeof(uint64_t) || !scr_arr_dense_values(a)) return NULL; *len = a->len; return a->data; } @@ -4646,7 +4699,9 @@ bool scr_arr_sort_dense(ScrArr *a, ScrClosure *f, uint32_t arity, bool owned, in ScrClosure *key) { uint8_t elem = a->elem; const ScrArrOps *ops = scr_arr_ops(a); - if (a->rc == SIZE_MAX || !scr_arr_dense_values(a)) return false; + /* Compact references sort through the snapshot path, which reads and + * writes 8-byte slots. */ + if (a->rc == SIZE_MAX || elem == SCR_ELEM_CREF || !scr_arr_dense_values(a)) return false; size_t n = a->len; if (n < 2) return true; if (n > SIZE_MAX / 2 / sizeof(uint64_t)) scr_arr_oom(); @@ -4687,12 +4742,14 @@ bool scr_arr_sort_dense(ScrArr *a, ScrClosure *f, uint32_t arity, bool owned, in } else { /* Publish each new edge before releasing the value it replaces: a * release can collect cycles. The buffer still holds the slots not - * yet written. */ + * yet written. The kind, and so the slot width, never changes. */ + size_t width = scr_arr_slot_width(a); for (size_t i = 0; i < n; i++) { - bool held = *scr_arr_state_ptr(a, i) == SCR_ARR_VALUE; + uint8_t *state = scr_arr_state_in(scr_arr_states_end_w(a, width), i); + bool held = *state == SCR_ARR_VALUE; uint64_t old = held ? a->data[i] : 0; a->data[i] = src[i]; - *scr_arr_state_ptr(a, i) = SCR_ARR_VALUE; + *state = SCR_ARR_VALUE; if (held) scr_elem_release(a, old); } } @@ -4787,6 +4844,7 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) { case SCR_ELEM_ARR: case SCR_ELEM_BYTES: case SCR_ELEM_REF: + case SCR_ELEM_CREF: /* The compiler rejects join on ref-element arrays (SC1090). */ scr_trap("scriptc: internal error: join on a ref-element array\n"); } diff --git a/packages/runtime/src/scr_array.h b/packages/runtime/src/scr_array.h index 6c41b3dbd..2fea1ef2c 100644 --- a/packages/runtime/src/scr_array.h +++ b/packages/runtime/src/scr_array.h @@ -43,6 +43,11 @@ typedef enum { * constant descriptor per element type, stored once per array; every * array is still monomorphic (one element type, one set of entry points). */ SCR_ELEM_REF, + /* An SCR_ELEM_REF type whose elements are compact class instances in the + * program-lifetime region (SCR_ARR_OPS_COMPACT): 4-byte slots holding the + * address over 8, 0 for NULL. Compact instances are never counted or + * traced, so these arrays retain, release and trace nothing. */ + SCR_ELEM_CREF, } ScrElemKind; typedef enum { @@ -63,8 +68,14 @@ typedef struct ScrArrOps { /* Registry id (scr_arr_ops_table), 0 until scr_arr_ops_register assigns * it on the first array of the type. Descriptors are writable for it. */ uint32_t id; + /* SCR_ARR_OPS_* */ + uint32_t flags; } ScrArrOps; +/* The elements are compact class instances in the program-lifetime region: + * arrays of the type are SCR_ELEM_CREF (llvm/shapes.ts arrOps). */ +#define SCR_ARR_OPS_COMPACT 1u + typedef struct ScrArr { size_t rc; /* SIZE_MAX = immortal (unused for arrays; kept per convention) */ /* Length and dense capacity are at most SCR_ARR_MAX_LENGTH (2^32 - 1); @@ -84,7 +95,7 @@ typedef struct ScrArr { /* The low SCR_ARR_OPS_SHIFT bits: storage flags (SCR_ARR_INLINE_SLOTS, * SCR_ARR_HEAD_ROOM, SCR_ARR_UNSHIFTED, SCR_ARR_HAS_EXT). The rest: the * registry id of the element type's ops (scr_arr_ops), 0 for every kind - * but SCR_ELEM_REF. */ + * but SCR_ELEM_REF and SCR_ELEM_CREF. */ uint16_t spare; /* A lower bound on the hole-free prefix: filled <= len, filled <= cap, * and every dense state below it is SCR_ARR_VALUE. Element reads below @@ -93,10 +104,12 @@ typedef struct ScrArr { * undefined) or move states below it lowers it first (scr_arr_cut); * 0 is always valid. */ uint32_t filled; - /* Dense values: `cap` 8-byte slots, or `cap` bytes for SCR_ELEM_BOOL - * (scr_arr_slot_width), followed in the same allocation by one state byte - * per slot in reverse slot order (scr_arr_states_end). Sparse entries and properties keep 8-byte - * slots for every kind; a bool slot is 0 or 1 wherever it lives. Rarely + /* Dense values: `cap` 8-byte slots, `cap` bytes for SCR_ELEM_BOOL or + * `cap` 4-byte slots for SCR_ELEM_CREF (scr_arr_slot_width), followed in + * the same allocation by one state byte per slot in reverse slot order + * (scr_arr_states_end). Sparse entries and properties keep 8-byte slots + * for every kind; a bool slot is 0 or 1 wherever it lives, and a CREF + * slot's 8-byte form is the pointer (scr_arr_dense_get). Rarely * used storage (sparse indices, noncanonical numeric properties, * match-result metadata) lives out of line, and an array that has it * (SCR_ARR_HAS_EXT) keeps a pointer to it in the word before the dense @@ -190,16 +203,24 @@ static inline uint32_t scr_arr_ops_id(const ScrArrOps *ops) { /* The element ops of an array whose ops have no registry id. */ const ScrArrOps *scr_arr_ops_overflow(const ScrArr *a); -/* The element ops of `a`: NULL for every kind but SCR_ELEM_REF. */ +/* The element ops of `a`: NULL for every kind but SCR_ELEM_REF and + * SCR_ELEM_CREF. */ static inline const ScrArrOps *scr_arr_ops(const ScrArr *a) { uint32_t id = (uint32_t)a->spare >> SCR_ARR_OPS_SHIFT; if (__builtin_expect(id == SCR_ARR_OPS_OVERFLOW, 0)) return scr_arr_ops_overflow(a); return scr_arr_ops_table[id]; } +/* Bytes per dense value slot of element kind `elem`. */ +static inline size_t scr_elem_slot_width(uint8_t elem) { + if (elem == SCR_ELEM_BOOL) return 1; + if (__builtin_expect(elem == SCR_ELEM_CREF, 0)) return sizeof(uint32_t); + return sizeof(uint64_t); +} + /* Bytes per dense value slot. */ static inline size_t scr_arr_slot_width(const ScrArr *a) { - return a->elem == SCR_ELEM_BOOL ? 1 : sizeof(uint64_t); + return scr_elem_slot_width(a->elem); } /* The dense states, one byte per slot, share the values' allocation (inline @@ -233,14 +254,23 @@ static inline uint8_t *scr_arr_state_run(const ScrArr *a, size_t from, size_t co return scr_arr_states_end(a) - from - count; } +/* A CREF slot's pointer, and the slot of a pointer (NULL or a compact + * instance below 32 GiB). */ +static inline uint64_t scr_cref_decode(uint32_t ref) { return (uint64_t)ref << 3; } +static inline uint32_t scr_cref_encode(uint64_t slot) { return (uint32_t)(slot >> 3); } + /* The dense value at `index` (< cap) as an 8-byte slot, and its store. */ static inline uint64_t scr_arr_dense_get(const ScrArr *a, size_t index) { if (a->elem == SCR_ELEM_BOOL) return ((const uint8_t *)a->data)[index]; + if (__builtin_expect(a->elem == SCR_ELEM_CREF, 0)) + return scr_cref_decode(((const uint32_t *)a->data)[index]); return a->data[index]; } static inline void scr_arr_dense_put(ScrArr *a, size_t index, uint64_t slot) { if (a->elem == SCR_ELEM_BOOL) ((uint8_t *)a->data)[index] = (uint8_t)slot; + else if (__builtin_expect(a->elem == SCR_ELEM_CREF, 0)) + ((uint32_t *)a->data)[index] = scr_cref_encode(slot); else a->data[index] = slot; } diff --git a/packages/runtime/src/scr_copying.c b/packages/runtime/src/scr_copying.c index df4da1738..ee0bb055a 100644 --- a/packages/runtime/src/scr_copying.c +++ b/packages/runtime/src/scr_copying.c @@ -22,7 +22,7 @@ static bool copying_elem_is_ref(ScrElemKind kind) { } static ScrArr *copying_arr_new_like(const ScrArr *a, size_t cap) { - ScrArr *out = a->elem == SCR_ELEM_REF + ScrArr *out = a->elem == SCR_ELEM_REF || a->elem == SCR_ELEM_CREF ? scr_arr_new_ops(scr_arr_ops(a), cap ? cap : 1) : scr_arr_new(a->elem, cap ? cap : 1); out->len = cap; diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index 4be596ab5..37ca28f16 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -13002,7 +13002,7 @@ ScrArr *scr_set_to_arr_ref(const ScrMap *s, const ScrArrOps *ops) { for (size_t i = 0; i < s->nentries; i++) { if (!scr_map_entry_live(s, i)) continue; ops->retain((void *)(uintptr_t)scr_map_entry_at(s, i)->key); - out->data[out->len] = scr_map_entry_at(s, i)->key; + scr_arr_dense_put(out, out->len, scr_map_entry_at(s, i)->key); *scr_arr_state_in(states, out->len++) = SCR_ARR_VALUE; } return out; diff --git a/packages/runtime/src/scr_publish.c b/packages/runtime/src/scr_publish.c index 675a13ca9..4ec993055 100644 --- a/packages/runtime/src/scr_publish.c +++ b/packages/runtime/src/scr_publish.c @@ -199,6 +199,19 @@ static void scr_pub_slot(ScrPub *ctx, uint64_t slot, ScrPubFn fn) { if (fn) scr_pub_push(ctx, p, fn); } +/* The elements of a compact reference array (SCR_ELEM_CREF): 4-byte dense + * slots, 8-byte pointers in the sparse entries. */ +static __attribute__((noinline)) void scr_pub_cref_elems(ScrArr *a, ScrPub *ctx, ScrPubFn fn) { + size_t dense = a->len < a->cap ? a->len : a->cap; + const uint32_t *refs = (const uint32_t *)a->data; + const uint8_t *states = scr_arr_states_end_w(a, sizeof(uint32_t)); + for (size_t i = 0; i < dense; i++) + if (!states || *scr_arr_state_in(states, i)) scr_pub_slot(ctx, scr_cref_decode(refs[i]), fn); + if (scr_arr_ext_of(a)) + for (size_t i = 0; i < scr_arr_ext_of(a)->sparse_len; i++) + if (scr_arr_ext_of(a)->sparse[i].state) scr_pub_slot(ctx, scr_arr_ext_of(a)->sparse[i].slot, fn); +} + void scr_pub_arr(void *v, ScrPub *ctx, ScrPubFn elem) { ScrArr *a = v; if (scr_arr_ext_of(a) && (scr_arr_ext_of(a)->props || scr_arr_ext_of(a)->metadata)) { @@ -206,10 +219,15 @@ void scr_pub_arr(void *v, ScrPub *ctx, ScrPubFn elem) { return; } if (!scr_pub_mark(ctx, a, a->cyc != 0, SCR_PUB_KIND_ARRAY)) return; + if (__builtin_expect(a->elem == SCR_ELEM_CREF, 0)) { + scr_pub_cref_elems(a, ctx, elem); + return; + } ScrPubFn fn = a->elem == SCR_ELEM_STR ? scr_pub_str_fn : a->elem == SCR_ELEM_REF ? elem : NULL; if (!fn) return; + /* String and reference elements have 8-byte slots. */ size_t dense = a->len < a->cap ? a->len : a->cap; - const uint8_t *states = scr_arr_states_end(a); + const uint8_t *states = scr_arr_states_end_w(a, sizeof(uint64_t)); for (size_t i = 0; i < dense; i++) if (!states || *scr_arr_state_in(states, i)) scr_pub_slot(ctx, a->data[i], fn); if (scr_arr_ext_of(a)) diff --git a/tests/corpus/4638-contract-program-lifetime-arrays.ts b/tests/corpus/4638-contract-program-lifetime-arrays.ts new file mode 100644 index 000000000..a50094f8b --- /dev/null +++ b/tests/corpus/4638-contract-program-lifetime-arrays.ts @@ -0,0 +1,117 @@ +import type { ProgramLifetime } from "@scriptc/types"; + +// Arrays of ProgramLifetime class instances: literals, growth, removal +// from both ends, splicing, slicing, concatenation, searching, sorting, +// filling, copying methods, holes, length changes, Sets and Maps built +// from them, arrays held in class fields, optional elements, inspection +// and JSON. Each operation sees the same instances, in the same order. + +class Sym implements ProgramLifetime { + readonly name: string; + readonly rank: number; + readonly decls: Sym[] = []; + parent: Sym | undefined = undefined; + constructor(name: string, rank: number) { + this.name = name; + this.rank = rank; + } +} + +class Scope implements ProgramLifetime { + readonly symbols: Sym[] = []; + readonly optional: (Sym | undefined)[] = []; + readonly nullable: (Sym | null)[] = []; +} + +const names = (xs: readonly (Sym | undefined | null)[]): string => + xs.map((s) => (s === undefined ? "u" : s === null ? "n" : s.name)).join(","); + +const a = new Sym("a", 3); +const b = new Sym("b", 1); +const c = new Sym("c", 2); +const d = new Sym("d", 5); +const e = new Sym("e", 4); + +// Literals, push, pop, shift and unshift. +const xs: Sym[] = [a, b, c]; +xs.push(d); +xs.push(e, a); +console.log(names(xs), xs.length); +console.log(xs.pop()?.name, xs.shift()?.name, names(xs)); +xs.unshift(e, d); +console.log(names(xs), xs[0] === e, xs.at(-1) === e); + +// Growth well past the inline slots, then reads by index. +const many: Sym[] = []; +for (let i = 0; i < 1000; i++) many.push(i % 2 === 0 ? a : new Sym(`s${i}`, i)); +let ranks = 0; +for (let i = 0; i < many.length; i++) ranks += many[i]!.rank; +console.log(many.length, ranks, many[999]!.name, many[998] === a); + +// Splice, slice, concat, spread and copying methods. +const ys = xs.slice(1, 4); +const removed = xs.splice(1, 2, a, b, c); +console.log(names(ys), names(removed), names(xs)); +const zs = [...ys, ...removed].concat(xs); +console.log(names(zs), zs.length); +console.log(names(zs.toReversed()), names(zs.with(0, c)), names(zs.toSpliced(1, 3))); + +// Searching by identity. +console.log(zs.indexOf(c), zs.lastIndexOf(c), zs.includes(d), zs.indexOf(new Sym("c", 2))); +console.log(zs.find((s) => s.rank > 3)?.name, zs.findIndex((s) => s === b), zs.some((s) => s === e)); +console.log(zs.every((s) => s.rank > 0), zs.filter((s) => s.rank % 2 === 1).length); + +// Sorting with comparators, reversing and filling. +const sorted = [...zs].sort((p, q) => p.rank - q.rank || p.name.localeCompare(q.name)); +console.log(names(sorted)); +console.log(names(zs.toSorted((p, q) => q.name.localeCompare(p.name)))); +sorted.reverse(); +console.log(names(sorted)); +const filled: Sym[] = new Array(5).fill(b); +filled.fill(c, 2, 4); +console.log(names(filled), filled.copyWithin(0, 3).map((s) => s.name).join("")); + +// Holes, length changes and iteration. +const holey: Sym[] = [a, b]; +holey[5] = c; +console.log(holey.length, 2 in holey, holey[5]?.name, holey.findIndex((s) => s === c)); +holey.length = 3; +console.log(holey.length, holey[5]); +let visited = ""; +for (const s of xs) visited += s.name; +xs.forEach((s, i) => { + visited += i; +}); +console.log(visited, names(xs.map((s) => s.parent ?? s))); + +// Arrays inside class instances, optional and nullable elements. +const scope = new Scope(); +for (const s of [a, b, c, d, e]) { + scope.symbols.push(s); + s.decls.push(s, a); + s.parent = scope.symbols[0]; +} +scope.optional.push(a, undefined, c); +scope.nullable.push(null, b, null); +scope.optional[3] = e; +console.log(names(scope.symbols), names(scope.optional), names(scope.nullable)); +console.log(scope.optional.indexOf(undefined), scope.nullable.indexOf(null), scope.optional.length); +console.log(c.decls.length, c.decls[1] === a, e.parent === a, names(e.decls)); + +// Sets and Maps built from arrays, and arrays built from them. +const set = new Set(zs); +console.log(set.size, set.has(d), names([...set])); +const byName = new Map(zs.map((s) => [s.name, s] as const)); +console.log(names([...byName.values()]), byName.get("b") === b); +const grouped = new Map(); +for (const s of many.slice(0, 10)) { + const list = grouped.get(s.rank % 3) ?? []; + list.push(s); + grouped.set(s.rank % 3, list); +} +console.log([...grouped.entries()].map(([k, v]) => `${k}:${v.length}`).join(" ")); + +// Inspection and JSON. +console.log(xs.slice(0, 2).map((s) => s.name)); +console.log(JSON.stringify(scope.nullable.map((s) => s?.rank ?? null))); +console.log(JSON.stringify([a, b].map((s) => ({ name: s.name, rank: s.rank })))); diff --git a/tests/harness/corpus-costs/4638-contract-program-lifetime-arrays.ts.json b/tests/harness/corpus-costs/4638-contract-program-lifetime-arrays.ts.json new file mode 100644 index 000000000..8512b117c --- /dev/null +++ b/tests/harness/corpus-costs/4638-contract-program-lifetime-arrays.ts.json @@ -0,0 +1 @@ +{ "plain": 2800, "san": 4600 } From 9aaebbab254ac0ee6359e10eca248fefab0c3559 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 11:14:27 -0500 Subject: [PATCH 29/45] Prepare v0.4.2 release --- CHANGELOG.md | 156 +++++++++++++++++- 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, 186 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31d34e8db..2bdd47363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,160 @@ All notable changes to scriptc will be documented in this file. +## 0.4.2 + +### Highlights + +- **Faster builds of large programs:** + - scriptc checks with tsc-ts 0.0.7, which answers contextual types and resolved signatures in batches, so lowering asks for them in one request per chunk instead of one per node. A native build of tsc-ts is 7% faster (110.5 → 103.5 s on 8 vCPUs, lowering 12% faster), with an identical executable. + - The native compiler is built with profile-guided optimization, so tsc-ts builds 6.9% faster cold and 10.7% faster after an edit. + - The class dispatch passes index their receivers by name instead of testing each one, and they reuse their per-function scans while a function's body is unchanged. + - Checker replies resolve objects the compiler already holds from their ids without decoding them. +- **Leaner builds:** + - The frontend of an optimized executable's first build runs in a child process, so the native code generator starts after its memory is released. The cold build of tsc-ts peaks at 2.21 GB instead of 3.30 GB. + - The compiler collects its heap as lowering and LLVM emission grow it. +- **WebCrypto:** + - The `crypto` global, `node:crypto`'s `webcrypto` and `crypto.subtle` are one object. + - `generateKey`, `importKey`, `exportKey`, `encrypt`, `decrypt`, `deriveBits`, `deriveKey`, `wrapKey` and `unwrapKey` cover HMAC, AES-GCM, AES-CBC, AES-CTR, AES-KW, PBKDF2, HKDF and JSON Web Keys. + - `crypto.subtle` signs and verifies with ECDSA, RSASSA-PKCS1-v1_5, RSA-PSS and Ed25519. + - All of it follows Node 24's argument conversion, algorithm normalization and `DOMException`s. jose's symmetric JWE paths run as in Node. +- **JSX:** `.tsx`, `.jsx` and JavaScript files with JSX compile under the project's `jsx` options. + - `react`, `react-jsx` and `react-jsxdev` lower to the factory calls TypeScript emits, with the same keys, fallbacks and source positions. + - `preserve` and `react-native` are refused with a named diagnostic. +- **Faster worker messages:** + - A message is encoded into one block sized to its contents. + - A typed record is posted from its fields. + - A `'message'` listener with a typed parameter builds it from the message, without a checked-dynamic copy. + - Messages between `MessageChannel` ports take 90 ms where they took 250 ms in 0.4.1 (Node: 337 ms), with a peak RSS of 45 MB instead of 115 MB. +- **Loops over typed arrays vectorize:** a loop to a typed array's length keeps one bounds test for every typed array it indexes. + - Index temporaries such as `const j = i * 4` are computed as integers. + - Uint8ClampedArray stores convert inline. + - Row-major index terms such as `r * cols + j` are tested once before the loop. + - Typed-array callback methods call a literal callback directly on an integer counter. + - An 896 × 896 matrix-vector product with four accumulators takes 55 ms instead of 396 ms (Node: 275 ms). `Uint8Array.map` is 4.5 times as fast and `Int32Array.some` 7.8 times as fast as in 0.4.1. + +### Features + +- **Asymmetric keys and signatures in `node:crypto`:** + - `generateKeyPair`, `generateKeyPairSync`, `createPrivateKey` and `createPublicKey` handle RSA, EC and Ed25519 keys in PEM, DER and JWK. + - `sign`, `verify`, `createSign` and `createVerify` sign and verify with those keys, with Node's output and errors. + - Ed25519 verification matches Node on 2,083 test vectors, including small-order and mixed-order keys. +- **`crypto.createDiffieHellman`, `crypto.getDiffieHellman` and `crypto.createDiffieHellmanGroup`:** + - The modp1, modp2 and modp5 to modp18 groups, explicit primes and generators, and generated safe primes are supported, with Node 24's key widths, `verifyError` bits, key range checks and errors. + - Secrets of 0, 1 and p − 1 are rejected, and so are peer keys outside the RFC 5114 subgroups. + - Primes longer than 8192 bits are refused. +- **TLS:** + - `tls.connect` and `tls.createServer` negotiate `ALPNProtocols`, and both sockets report `alpnProtocol`. `minVersion` and `maxVersion` bound the handshake, and `getProtocol()` reports the version it picked. + - `tls.createServer` takes an `SNICallback` that answers a `SecureContext` synchronously or later. + - `new tls.TLSSocket(socket, { isServer: true, ... })` and `tls.connect({ socket })` run the handshake on an open socket, such as an HTTP `CONNECT` tunnel. + - A client whose peer closes before the handshake completes fails with Node's `ECONNRESET`. +- **Streams:** + - Readable, Writable, Duplex, Transform and PassThrough streams take `objectMode`, `readableObjectMode` and `writableObjectMode`, and an object-mode side carries any value through `push`, `write`, `pipe`, `pipeline`, `for await` and `'data'` listeners. + - `_write` and `_transform` receive the encoding argument as Node passes it. + - `Cipheriv` and `Decipheriv` are Transforms: they can be piped, used as `pipeline()` stages, read and iterated. + - `pipeline()` accepts function stages anywhere among its streams, and an array, a string or a synchronous generator as its source. +- **Packages compiled from their JavaScript:** + - js-yaml and smol-toml compile statically and match Node: ES5 error constructors (`Object.create(Error.prototype)`, `Error.call(this)`, `Error.captureStackTrace`) and classes extending `Date` behave as in Node. + - TypeScript's UMD module wrapper compiles as the module body, and tsc's `__importDefault` and `__importStar` helpers around builtin modules compile as plain `require()` calls. + - Interfaces, type aliases and enums that only a package's `.d.ts` declares keep their types. +- **JavaScript sources:** + - Error constructors can be read as values, so `err.constructor === TypeError` works. + - `workerData` can be destructured. + - Unary `+` converts unions of strings, numbers, booleans, `null` and `undefined` as `Number()` does, so `+process.argv[2]` compiles. + - These compile and behave as in Node: + - chained readline listener registration; + - `Number.parseInt` without a radix; + - `match` and `search` with a possibly undefined regular expression; + - `Buffer.from` over an untyped `ArrayBuffer`, with its byte offset; + - Atomics on untyped arrays. + - Buffer methods run on Buffers held as untyped values. +- **`fs`:** + - The synchronous functions (`readFileSync`, `writeFileSync`, `statSync`, `readdirSync`, `mkdirSync`, `rmSync`, `openSync` and the others) accept `file:` URLs wherever they accept a path, with Node's conversion errors. + - `fs.promises.rm` takes `recursive`, `force`, `maxRetries` and `retryDelay`, and removing a directory without `recursive` throws Node's `ERR_FS_EISDIR`. +- **`TypedArray.of`** creates a typed array of its arguments, and a dynamic iterable spread into `Array.of`, `push` or `TypedArray.of` is drained through the iterator protocol. +- **Global `isFinite` converts its argument with ToNumber,** as `isNaN` does. The Math functions and `String.fromCharCode` evaluate every argument before converting any. +- **`Object.freeze`, `Object.seal` and `Object.preventExtensions` of a function** act on its own properties, and `Object.isFrozen`, `Object.isSealed` and `Object.isExtensible` answer for functions. @noble/hashes' frozen hashers work. +- **EventEmitters used through both typed and untyped references** share one listener list. An untyped `emit` reaches typed listeners, an untyped `emit('error')` follows Node's contract, and `listenerCount`, `eventNames`, `listeners`, `rawListeners`, `removeAllListeners`, `setMaxListeners` and `getMaxListeners` work on untyped values. +- **Template literals, `join`, `Array.prototype.toString` and the default `sort()`** call an object's own or inherited `toString`, as `String()` does, instead of printing `[object Object]`. +- **Classes and generics:** + - A generic factory declared to return a constructor type can return one of its local classes, including an anonymous class expression, and `class X extends factory(...)` extends it. + - Static methods of a function-local class compile. + - Constructor types declared in the program (`new () => unknown`, types that also name static members, construct overloads) hold class values. + - Members typed by a conditional type over a literal class type argument (`Field`) resolve. + - Object literals under an erased generic member may hold callbacks with optional or defaulted parameters. +- **Assignment and update targets wrapped in parentheses or non-null assertions** (`(x) = 1`, `h.sums[k]! += 10`) compile. +- **Untyped values keep what JavaScript code adds:** + - Properties that untyped code adds to a typed object literal stay on it. + - Named properties written to an array through an `unknown` view stay on the array, and `for...in` visits them after the indices. + - An `unknown` value asserted to a structural type with methods keeps its class's methods. + - The type inferred from an empty object literal holds any non-nullish value, as TypeScript's `{}` does. +- **A WebAssembly module the build finds but does not translate** rejects with a `CompileError` that names the reason, for example a proposal outside the translated feature set. +- **SC6101 names the functions that likely run often and use untyped values:** + - It shows up to five, most likely hot first, with why their values are untyped: an `any`, an untyped `JSON.parse` result or an untyped JavaScript file. + - `scriptc coverage --fail-on=dynamic` fails on it, and `--no-dynamic-tier-warning` leaves it out. + +### Performance + +- **Regular expressions skip start positions that their leading character sets rule out,** testing 16 positions at once. Searching 50 MB of text for nine case-insensitive alternations takes 0.83 s instead of 3.88 s (Node: 4.38 s). +- **Loop counters stay integers in more loops:** + - Counters that step beside a counted loop's counter (`for (let i = 0, p = 0; i < n; i++, p += 4)`) stay integers: a pixel-stride loop takes 114 ms instead of 340 ms (Node: 190 ms). + - So do two counters that close in on each other (`lo++, hi--`), 17% faster on a permutation-reversal loop. + - So do counters of loops bounded by a string's length or by an invariant limit other than an array's length, and while-loop counters that nested scans advance. A non-ASCII lexer is 9.5% faster. +- **Loops that call a known callback** test its closure once before the loop and call the function directly, so captured `let` bindings stay in registers. `forEach` sums with a captured accumulator are 25 to 55% faster. +- **A speculative integer loop whose check fails** finishes the iteration outside the ordinary loop, which stays optimizable, and a loop site that keeps failing stops trying. With the hole-free-prefix test that element reads now take first, a pairwise loop over an array of class instances with number fields is about 1.25 times as fast as in 0.4.1. +- **Typed arrays over a SharedArrayBuffer** read and write elements inline as relaxed atomic accesses. A numeric kernel over shared `Float64Array`s takes 0.78 s instead of 1.56 s (Node: 0.84 s). +- **`Math.pow(2, n)` for integer exponents** builds the result from its bits. A counter that masks with `Math.pow(2, length)` takes 11.0 s instead of 20.4 s. +- **Async calls that never suspend run in place,** and so does `await Promise.all` of such calls, with Node's microtask turns and rejection handling. An async pipeline takes 5.5 ms instead of 9.7 ms. +- **Strings:** + - `Number()` of a short integer string returns the integer directly. + - `split` builds its result in one inline block, and `indexOf` and `slice` on ASCII strings skip the UTF-16 index map. A log summary is 20% faster. + - `charAt` and `s[i]` on ASCII strings read the character from a table. + - Chains of one-character `replace` calls (the HTML-escape idiom) replace a block of 16 bytes at a time, 12.8% faster on a template renderer. +- **`JSON.parse` and `JSON.stringify`** scan whole words and append parsed typed arrays in bulk, 22% faster to parse and 10% faster to stringify records. +- **Smaller arrays, maps and program-lifetime instances:** + - The array header is 32 bytes instead of 48. + - Arrays of up to 16 known elements keep their slots in their own block. + - Arrays of a known final length get exactly that capacity. + - Small map entry arrays grow in finer steps. + - On Linux, `ProgramLifetime` instances take a 32-bit header and are referenced in 4 bytes. + - They lower the peak memory of a large TypeScript type checker: the 4-byte references alone take a large project's check from 4.13 GB to 3.75 GB, and the 32-bit header saves a further 5%. +- **Worker messages queued together are delivered in one batch** before immediates run. 20,000 messages interleaved with a worker's output drain in 0.5 s instead of 5.6 s (Node: 0.57 s). +- **The cycle collector** never buffers instances of classes whose fields hold nothing cycle-capable, and its per-object paths are shorter. A workload of cyclic graphs is about 5% faster. +- **Array helpers specialized for a callback that cannot throw** skip the pending-exception test, 4.5% faster on a functional pipeline. +- **Compile time:** + - A file's function declarations are walked once for their references, so lowering a 10 MB single-module bundle takes 69 s instead of 219 s. + - LLVM emission computes its module facts once, 6.9% faster on tsc-ts. + - AST walks visit subtrees by their node ranges and read node words through a `Uint32Array`. + - Program builds no longer import runtime bitcode, so builds through Node and through the native compiler produce identical executables. + +### Fixes + +- **Member reads and method calls on an array hole** held in a binding narrowed to one arm of a wide union throw Node's `Cannot read properties of undefined` TypeError. +- **`AsyncLocalStorage`:** + - A store entered before an async function's first await, or in a body that never suspends, is the caller's store after the call. + - Each synchronous generator step runs in its resumer's context, as in Node. +- **Generic arrow and function-expression bindings used before their declarations** behave as in Node, including the `ReferenceError` of a `let` or `const`. +- **Assignment expressions into a module `let` declared without an initializer** (`new Promise((r) => (resolve = r))`) store the value instead of throwing a `ReferenceError`. +- **The `extends` expression of a class defined inside a function** is evaluated each time the definition runs. +- **A `super()` call that leads an `if` condition's comma chain** compiles. +- **A catch binding tests `instanceof`** correctly for values thrown as `unknown`, rejected promises and runtime errors. +- **zlib callbacks receive `undefined` as their result when the operation fails,** as in Node, and a callback may assign a fallback to it. +- **`Readable.push` and `Writable.write` with `string | null` or `Buffer | null` chunks** no longer crash. +- **Object literals keep their key order** through compiler rewrites and on shapes a typed `JSON.parse` also builds, so `JSON.stringify`, `Object.keys` and `console.log` match Node. +- **`console.log` prints class instances with their class name** in programs that test `instanceof` on unknown values. +- **`String`, `Number` and `Boolean` passed to array methods** convert as their direct calls do, and nested array literals in a recursive JSON-style union build. +- **A dynamic method call that the program also reads through a prototype** finds the method when the instance's property bag does not hold it. +- **Storing an element on `Array.prototype`** fails with SC2020, because holes in native arrays do not read inherited elements. +- **A recursive type alias in a generic signature** no longer crashes the compiler. +- **A `Buffer` view of an untyped typed array** compiles. +- **JSX programs checked with tsgo** compile as they do with tsc-ts. +- **Two programs whose entries share a name and build into one directory** no longer share a cached translation unit, so a later cache hit always relinks the right program. +- **A warm build whose cached LLVM exceeds the engine's string limit** reads it in parts instead of failing with `Invalid string length`. +- **The same program compiles to the same executable wherever it sits on disk** and whatever order its functions lower in, and edits outside a declaration do not rename the helpers and closures inside it. +- **Libraries that use untyped byte arrays** link. + + + ## 0.4.1 ### Highlights @@ -77,8 +231,6 @@ All notable changes to scriptc will be documented in this file. - **TypeScript enum exports in compiled packages stay `undefined` until they are assigned,** as in Node. - **Element writes accept a possibly undefined index** (typed-array writes, compound and update writes, element assignments used as values and destructuring targets) and convert it with ToNumber, as element reads already did. - - ## 0.4.0 ### Breaking changes diff --git a/packages/cli-darwin-arm64/package.json b/packages/cli-darwin-arm64/package.json index 482e5f1e5..23584b60a 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.1", + "version": "0.4.2", "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 b1ced2c03..d9e6dafc6 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.1", + "version": "0.4.2", "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 0aa213279..5b8cb4db2 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.1", + "version": "0.4.2", "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 4ac5434ae..0901602ec 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.1", + "version": "0.4.2", "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 7473c36bc..f01478aad 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.1", + "version": "0.4.2", "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 08e048cd1..a6986a66a 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.1", + "version": "0.4.2", "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 54e323839..6b03811b8 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.1", + "version": "0.4.2", "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 d66ba3247..034747c29 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "scriptc", - "version": "0.4.1", + "version": "0.4.2", "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 a283f821a..a1d66963d 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/compiler", - "version": "0.4.1", + "version": "0.4.2", "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 45b3edbaa..637a5f831 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1,6 +1,6 @@ { "schemaVersion": 2, - "compilerVersion": "0.4.1", + "compilerVersion": "0.4.2", "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 5b6906de6..cfb4151a4 100644 --- a/packages/experimental/package.json +++ b/packages/experimental/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/experimental", - "version": "0.4.1", + "version": "0.4.2", "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 472056c39..615fe9d81 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.1", + "version": "0.4.2", "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 7f55cb6b5..fd6caf976 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.1", + "version": "0.4.2", "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 0e1a55b22..7d66257f4 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.1", + "version": "0.4.2", "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 efdd97444..b3a01089d 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.1", + "version": "0.4.2", "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 39667d535..0b3264ec7 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.1", + "version": "0.4.2", "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 9efd41845..6c83d1cb9 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.1", + "version": "0.4.2", "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 329fa308c..9fb682f0f 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.1", + "version": "0.4.2", "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 75c54e9c3..362fbc572 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.1", + "version": "0.4.2", "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 7473b05f3..a4176ed60 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.1", + "version": "0.4.2", "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 ab8666c88..91bc4182b 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.1", + "version": "0.4.2", "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 a3a254685..2fdd68897 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.1", + "version": "0.4.2", "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 7981422b8..cbdf96d1d 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.1", + "version": "0.4.2", "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 d633ac303..e0d228925 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.1", + "version": "0.4.2", "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 460ca25fa..70eee223f 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.1", + "version": "0.4.2", "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 9c6336a04..5822fd21d 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.1", + "version": "0.4.2", "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 e9f885a5c..1db34d4a7 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.1", + "version": "0.4.2", "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 c9a40c2c0..5bbd23755 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.1", + "version": "0.4.2", "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 f7e4c9860..df4a9a109 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.1", + "version": "0.4.2", "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 1af249b9d..9232266af 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime", - "version": "0.4.1", + "version": "0.4.2", "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 2aeeb7cbb..11b8ef624 100644 --- a/packages/threads/package.json +++ b/packages/threads/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/threads", - "version": "0.4.1", + "version": "0.4.2", "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 ffbbdf4a4..689c7b72f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/types", - "version": "0.4.1", + "version": "0.4.2", "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 fd40a8c84a136cdeaa18b08d5cf4c566e32eadd7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 11:18:30 -0500 Subject: [PATCH 30/45] Try each PATH entry with exec when spawning with a replacement env The PATH lookup for spawns with an `env` option picked the first executable regular file and stopped there, so a script whose interpreter is missing ended the search with ENOENT. Node's libuv runs execvp in the child, which moves on to the next PATH entry when an exec fails with ENOENT, ENOTDIR or EACCES. Each candidate now runs through posix_spawn in order with the same rule, and relative entries are resolved by the child in its cwd. --- packages/runtime/src/scr_child.c | 76 +++++++--------------- tests/corpus/7036-child-env-path-lookup.ts | 15 ++++- 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index c1d98b35b..df7543500 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -2907,7 +2907,6 @@ void scr_children_poll(void) { #include #include #include -#include #include #include #include @@ -3112,21 +3111,23 @@ static ScrSpawnRes *scr_spawn_res_new(bool has_status, double status, static char **scr_exec_envp(ScrArr *pairs); static void scr_exec_envp_free(char **envp); -/* The executable `file` names when `envp` replaces the child's - * environment, found as libuv finds it: a name with a '/' is used as - * given; otherwise each entry of the replacement's PATH (an empty entry - * is the current directory), or of the default path when the replacement - * has no PATH, is tried in order. Relative candidates are checked from - * `cwd`, the directory the child starts in (NULL: this process's). Returns - * a malloc'd path, or NULL with *err set: EACCES when a candidate exists - * but cannot run, else ENOENT. */ -static char *scr_spawn_path_lookup(const char *file, char *const *envp, const char *cwd, - int *err) { - if (strchr(file, '/')) { - char *copy = strdup(file); - if (!copy) scr_child_oom(); - return copy; - } +/* posix_spawnp for the child_process spawns. Without `envp` the command + * resolves on this process's PATH over `environ`. With `envp` (a + * replacement environment) it resolves the way Node's libuv runs execvp + * in the child: a name with a '/' runs as given; otherwise each entry of + * the replacement's PATH (an empty entry is the current directory), or of + * the default path when the replacement has no PATH, is tried in order, + * and a candidate whose exec fails with ENOENT, ENOTDIR or EACCES (a + * missing file, or a script whose interpreter is missing) moves on to the + * next entry. The last such failure is EACCES if any candidate was denied, + * else ENOENT. Relative entries are resolved by the child, which starts in + * `cwd`. Returns posix_spawn's error number. */ +static int scr_spawn_command(pid_t *pid, const char *file, const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *attr, char *const *argv, + char *const *envp, const char *cwd) { + (void)cwd; /* the file actions change into it before the exec */ + if (envp == NULL) return posix_spawnp(pid, file, fa, attr, argv, environ); + if (strchr(file, '/')) return posix_spawn(pid, file, fa, attr, argv, envp); const char *path = "/usr/bin:/bin"; for (char *const *e = envp; *e; e++) { if (strncmp(*e, "PATH=", 5) == 0) { @@ -3135,7 +3136,6 @@ static char *scr_spawn_path_lookup(const char *file, char *const *envp, const ch } } size_t file_len = strlen(file); - size_t cwd_len = cwd ? strlen(cwd) : 0; bool denied = false; for (const char *dir = path;;) { const char *end = strchr(dir, ':'); @@ -3147,51 +3147,19 @@ static char *scr_spawn_path_lookup(const char *file, char *const *envp, const ch memcpy(candidate, prefix, prefix_len); candidate[prefix_len] = '/'; memcpy(candidate + prefix_len + 1, file, file_len + 1); - char *checked = candidate; - if (cwd_len > 0 && candidate[0] != '/') { - checked = malloc(cwd_len + 1 + strlen(candidate) + 1); - if (!checked) scr_child_oom(); - memcpy(checked, cwd, cwd_len); - checked[cwd_len] = '/'; - strcpy(checked + cwd_len + 1, candidate); - } - struct stat st; - bool runs = false; - if (stat(checked, &st) == 0) { - runs = S_ISREG(st.st_mode) && access(checked, X_OK) == 0; - if (!runs) denied = true; - } else if (errno == EACCES) { - denied = true; - } - if (checked != candidate) free(checked); - if (runs) return candidate; + int err = posix_spawn(pid, candidate, fa, attr, argv, envp); free(candidate); + if (err == EACCES) denied = true; + else if (err != ENOENT && err != ENOTDIR) return err; if (!end) break; dir = end + 1; } - *err = denied ? EACCES : ENOENT; - return NULL; -} - -/* posix_spawnp for the child_process spawns: with `envp` (a replacement - * environment) the command resolves on that environment's PATH - * (scr_spawn_path_lookup) as Node's does; without it, on this process's - * PATH over `environ`. Returns posix_spawn's error number. */ -static int scr_spawn_command(pid_t *pid, const char *file, const posix_spawn_file_actions_t *fa, - const posix_spawnattr_t *attr, char *const *argv, - char *const *envp, const char *cwd) { - if (envp == NULL) return posix_spawnp(pid, file, fa, attr, argv, environ); - int err = 0; - char *resolved = scr_spawn_path_lookup(file, envp, cwd, &err); - if (!resolved) return err; - err = posix_spawn(pid, resolved, fa, attr, argv, envp); - free(resolved); - return err; + return denied ? EACCES : ENOENT; } /* env_pairs: NULL inherits the parent's environment; else [k,v,...] * replaces it, as Node's `env` option does, and the command is looked up - * on the replacement's PATH (scr_spawn_path_lookup). */ + * on the replacement's PATH (scr_spawn_command). */ static ScrSpawnRes *scr_spawn_sync_core(ScrStr *cmd, ScrArr *args, double timeout_ms, int killsig, int in_mode, int out_mode, int err_mode, ScrArr *env_pairs) { diff --git a/tests/corpus/7036-child-env-path-lookup.ts b/tests/corpus/7036-child-env-path-lookup.ts index cac0670e9..97c93d835 100644 --- a/tests/corpus/7036-child-env-path-lookup.ts +++ b/tests/corpus/7036-child-env-path-lookup.ts @@ -11,6 +11,12 @@ mkdirSync(join(dir, "tools")); writeFileSync(join(dir, "tools", "child-tool"), "#!/bin/sh\necho child-tool $1\n"); chmodSync(join(dir, "tools", "child-tool"), 0o755); +// An earlier PATH entry holding a script whose interpreter is missing +// moves the lookup on to the next entry, as execvp does. +mkdirSync(join(dir, "broken")); +writeFileSync(join(dir, "broken", "child-tool"), "#!/nonexistent/interpreter\n"); +chmodSync(join(dir, "broken", "child-tool"), 0o755); + const show = (e: unknown): string => { const err = e as NodeJS.ErrnoException; return `${err.code} ${err.message.replace(dir, "")}`; @@ -23,11 +29,18 @@ try { } catch (e) { console.log(show(e)); } +const twoEntries = `${join(dir, "broken")}:${join(dir, "tools")}`; +console.log(execFileSync("child-tool", ["fallthrough"], { env: { PATH: twoEntries }, encoding: "utf8" }).trim()); +try { + execFileSync("child-tool", [], { env: { PATH: join(dir, "broken") }, encoding: "utf8" }); +} catch (e) { + console.log(show(e)); +} console.log( execFileSync("child-tool", ["relative"], { env: { PATH: "tools" }, cwd: dir, encoding: "utf8" }).trim(), ); -const child = spawn("child-tool", ["async"], { env: { PATH: join(dir, "tools") }, stdio: ["ignore", "pipe", "ignore"] }); +const child = spawn("child-tool", ["async"], { env: { PATH: twoEntries }, stdio: ["ignore", "pipe", "ignore"] }); let out = ""; child.stdout!.on("data", (chunk: Buffer) => (out += chunk.toString())); child.on("close", (code) => { From 972e44a11a530321cdaf38aeeffc68b9639297e3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 11:40:01 -0500 Subject: [PATCH 31/45] Hold any later value in JavaScript properties initialized to undefined or null A JavaScript object literal's property whose initializer is `undefined` or `null` (`[{ oldPos: -1, lastComponent: undefined }]`, `{ user: null }`) mapped to the unit-only union, so a later write of another value threw: the diff package's diffLines failed with "a '{ added: boolean; count: number; previousComponent: unknown; removed: boolean }' value is not representable in the target union" when it stored its first path component. Nothing checks a JavaScript file's writes, so such a property is now checked-dynamic and holds whatever the program stores. TypeScript properties keep the unit-only union, and `__proto__: null` still sets the prototype. --- packages/compiler/src/frontend/type-mapper.ts | 23 ++++++++++ .../main.ts.json | 6 +++ .../main.ts | 8 ++++ .../node_modules/edit-paths/index.d.ts | 2 + .../node_modules/edit-paths/index.js | 43 +++++++++++++++++++ .../node_modules/edit-paths/package.json | 1 + .../main.ts.json | 1 + 7 files changed, 84 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7008-js-unit-initialized-properties/main.ts.json create mode 100644 tests/corpus/7008-js-unit-initialized-properties/main.ts create mode 100644 tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.d.ts create mode 100644 tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.js create mode 100644 tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/package.json create mode 100644 tests/harness/corpus-costs/7008-js-unit-initialized-properties/main.ts.json diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 93349054a..fa8897266 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -5744,6 +5744,28 @@ function emptyNeverArrayProp(p: ts.Symbol, fieldTs: ts.Type, checker: ts.TypeChe ); } +/** A JavaScript object literal's property (`{ lastComponent: undefined }`, + * `{ user: null }`). Nothing checks a JavaScript file's later writes, which + * can store any value in it (`path.lastComponent = { ... }`), so a + * property whose only initializer is a unit holds the checked-dynamic value + * rather than the unit-only union. */ +function isUnitOnlyIr(t: IrType, ctx: TypeMapperCtx): boolean { + if (t.kind !== "union") return false; + const def = ctx.unions.get(t.unionId); + return def !== undefined && def.arms.every((arm) => isUnitType(arm)); +} + +function jsObjectLiteralProperty(p: ts.Symbol): boolean { + const d = p.valueDeclaration; + // `__proto__: null` sets the literal's prototype; it declares no property. + return ( + d !== undefined && + (ts.isPropertyAssignment(d) || ts.isShorthandPropertyAssignment(d)) && + ts.symbolName(p) !== "__proto__" && + isJsSourceFile(ts.getSourceFileOfNode(d)) + ); +} + function mapGenericAwaitedAlias(type: ts.Type, ctx: TypeMapperCtx): IrType | null { const { resolveTypeParam } = ctx; if (!resolveTypeParam) return null; @@ -7811,6 +7833,7 @@ function mapRecordTypeInner( // omits the undefined arm exactly like an omitted optional. if (pt?.kind === "void" && isUnitOnlyTsType(fieldTs, ctx.resolveTypeParam)) pt = unitOnlyUnion(ctx.unions); + if (pt !== null && isUnitOnlyIr(pt, ctx) && jsObjectLiteralProperty(p)) pt = DYN; // dyn FIELDS map now (`{ v: unknown }`, `[string, unknown]` tuples): // the slot carries a dyn value exactly like an `unknown`-valued // overflow entry — same RC adapters, same dynFrom conversion on the diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7008-js-unit-initialized-properties/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7008-js-unit-initialized-properties/main.ts.json new file mode 100644 index 000000000..85f5a6e12 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7008-js-unit-initialized-properties/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7008-js-unit-initialized-properties/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7008-js-unit-initialized-properties/main.ts b/tests/corpus/7008-js-unit-initialized-properties/main.ts new file mode 100644 index 000000000..3ac113d6a --- /dev/null +++ b/tests/corpus/7008-js-unit-initialized-properties/main.ts @@ -0,0 +1,8 @@ +// A JavaScript package whose object literals start a property as +// `undefined` or `null` and later store records, numbers and arrays in it, +// as the diff package's path list does (`{ oldPos: -1, lastComponent: +// undefined }`). Node runs the later writes; each property holds them. +import { describe, session } from "edit-paths"; + +console.log(describe()); +console.log(session()); diff --git a/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.d.ts b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.d.ts new file mode 100644 index 000000000..68e2b409b --- /dev/null +++ b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.d.ts @@ -0,0 +1,2 @@ +export declare function describe(): string; +export declare function session(): string; diff --git a/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.js b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.js new file mode 100644 index 000000000..ec3e7c4d0 --- /dev/null +++ b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/index.js @@ -0,0 +1,43 @@ +"use strict"; +// A Myers-style path list, as the diff package keeps it: each path starts +// with `lastComponent: undefined` and later holds a linked list of records, +// and a state object starts with `null` fields that later hold other values. +function addToPath(path, added, removed, oldPosInc) { + var last = path.lastComponent; + if (last && last.added === added && last.removed === removed) { + return { oldPos: path.oldPos + oldPosInc, lastComponent: { count: last.count + 1, added: added, removed: removed, previousComponent: last.previousComponent } }; + } + return { oldPos: path.oldPos + oldPosInc, lastComponent: { count: 1, added: added, removed: removed, previousComponent: last } }; +} +function extractCommon(basePath, common) { + if (common) basePath.lastComponent = { count: common, previousComponent: basePath.lastComponent, added: false, removed: false }; + basePath.oldPos += common; +} +function components(lastComponent) { + var list = []; + while (lastComponent) { + list.push(lastComponent); + var next = lastComponent.previousComponent; + delete lastComponent.previousComponent; + lastComponent = next; + } + return list.reverse(); +} +function describe() { + var bestPath = [{ oldPos: -1, lastComponent: undefined }]; + extractCommon(bestPath[0], 1); + var path = addToPath(bestPath[0], false, true, 1); + path = addToPath(path, true, false, 0); + path = addToPath(path, true, false, 0); + return components(path.lastComponent).map(function (c) { + return (c.added ? "+" : c.removed ? "-" : "=") + c.count + ("previousComponent" in c ? "!" : ""); + }).join(" "); +} +function session() { + var state = { user: null, retries: null, tags: undefined }; + state.user = { name: "ada" }; + state.retries = 3; + state.tags = ["a", "b"]; + return state.user.name + " " + state.retries + " " + state.tags.join("+") + " " + JSON.stringify(state); +} +module.exports = { describe: describe, session: session }; diff --git a/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/package.json b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/package.json new file mode 100644 index 000000000..98648c289 --- /dev/null +++ b/tests/corpus/7008-js-unit-initialized-properties/node_modules/edit-paths/package.json @@ -0,0 +1 @@ +{ "name": "edit-paths", "version": "1.0.0", "main": "./index.js", "types": "./index.d.ts" } diff --git a/tests/harness/corpus-costs/7008-js-unit-initialized-properties/main.ts.json b/tests/harness/corpus-costs/7008-js-unit-initialized-properties/main.ts.json new file mode 100644 index 000000000..3a6df58d2 --- /dev/null +++ b/tests/harness/corpus-costs/7008-js-unit-initialized-properties/main.ts.json @@ -0,0 +1 @@ +{ "plain": 3065, "san": 2623 } From 6681b9407e79d09f4be6f9e64692db6bf961f3d0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 11:46:21 -0500 Subject: [PATCH 32/45] Version functions on number parameters that bound their loops A number parameter that every call site proves an int32 reaches the function's i32 entry. One that some caller passes as an unproven number, such as a value read from a worker message or parsed from text, kept its double, so every loop it bounds compared an integer counter with a double limit and the values derived from it stayed doubles. When such a parameter bounds a numeric loop (arithmetic, element and field reads and writes, Math calls, no allocation or other calls), the function now gets a copy of its body. Its own body first tests each such parameter for an int32 that is not -0 and, when all pass, calls the copy with `p | 0`, the same double. The copy's only caller proves those parameters int32s, so it gets the i32 entry and integer loops. Other values run the body as before. Only plain synchronous functions of at most 2048 IR nodes are versioned: not class members or generated helpers, not capturing, not the entry, not dynamic-tier, not calling themselves, and at most 16 per module. A function holding the only call site of another function is kept whole unless that callee only computes a number or boolean from scalar reads: a second call site can stop LLVM from inlining the callee and leave the records it builds in memory. Library builds and modules that observe call stacks are left as they are. --- packages/compiler/src/backend/llvm/emitter.ts | 49 ++- .../compiler/src/ir/parameter-versions.ts | 307 ++++++++++++++++++ .../test/parameter-version-emission.test.ts | 71 ++++ ...7323-loop-bound-parameter-versions.ts.json | 6 + ...4-loop-bound-parameter-window-sums.ts.json | 6 + .../7323-loop-bound-parameter-versions.ts | 88 +++++ .../7324-loop-bound-parameter-window-sums.ts | 33 ++ ...7323-loop-bound-parameter-versions.ts.json | 1 + ...4-loop-bound-parameter-window-sums.ts.json | 1 + 9 files changed, 544 insertions(+), 18 deletions(-) create mode 100644 packages/compiler/src/ir/parameter-versions.ts create mode 100644 packages/compiler/test/parameter-version-emission.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7323-loop-bound-parameter-versions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7324-loop-bound-parameter-window-sums.ts.json create mode 100644 tests/corpus/7323-loop-bound-parameter-versions.ts create mode 100644 tests/corpus/7324-loop-bound-parameter-window-sums.ts create mode 100644 tests/harness/corpus-costs/7323-loop-bound-parameter-versions.ts.json create mode 100644 tests/harness/corpus-costs/7324-loop-bound-parameter-window-sums.ts.json diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index bfde59a30..19604f38c 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -72,6 +72,7 @@ import { scalarizeNumericRecords } from "../../ir/scalar-records.js"; import { addRecordResultEntries } from "./record-results.js"; import { specializeCallbackCalls } from "../../ir/callback-specialization.js"; import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js"; +import { versionLoopBoundParameters } from "../../ir/parameter-versions.js"; import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js"; import { INT32_RANGE, type IntegerRange, type IntegerRanges } from "../../ir/integer-ranges.js"; import { unshareNodes } from "../../ir/unshare.js"; @@ -442,6 +443,14 @@ export function lowRegionTarget(platform: string, sanitize: boolean): boolean { return platform === "linux" && !sanitize; } +/** Function versions on loop-bounding number parameters + * (ir/parameter-versions.ts). Library builds have no int32 entries, and a + * module that observes call stacks could see the version's frame. */ +function versionParameters(mod: IrModule): IrModule { + if (mod.lib !== undefined || observesStacks(mod)) return mod; + return versionLoopBoundParameters(mod, mangleFunction); +} + export function emitLlvmModule(input: IrModule, options: LlvmTargetOptions = {}): string { // Facts are keyed by node identity: emit the same module whether it was // lowered in memory or read back from its serialized form. @@ -449,20 +458,22 @@ export function emitLlvmModule(input: IrModule, options: LlvmTargetOptions = {}) // Keep source storage intact for debugger inspection in dev builds. return new LlEmitter( options.debugSources === undefined - ? addRecordResultEntries( - scalarizeNumericRecords( - specializeCallbackCalls( - specializeNumericCalls( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads(freezeInitOnlyGlobals(dropUnwrittenPropertyBags(mod))), + ? versionParameters( + addRecordResultEntries( + scalarizeNumericRecords( + specializeCallbackCalls( + specializeNumericCalls( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads(freezeInitOnlyGlobals(dropUnwrittenPropertyBags(mod))), + ), ), ), + mangleFunction, ), mangleFunction, ), - mangleFunction, ), ), ) @@ -481,20 +492,22 @@ export function emitLlvmModuleSource( const mod = unshareNodes(input); const parts = new LlEmitter( options.debugSources === undefined - ? addRecordResultEntries( - scalarizeNumericRecords( - specializeCallbackCalls( - specializeNumericCalls( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads(freezeInitOnlyGlobals(dropUnwrittenPropertyBags(mod))), + ? versionParameters( + addRecordResultEntries( + scalarizeNumericRecords( + specializeCallbackCalls( + specializeNumericCalls( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads(freezeInitOnlyGlobals(dropUnwrittenPropertyBags(mod))), + ), ), ), + mangleFunction, ), mangleFunction, ), - mangleFunction, ), ), ) diff --git a/packages/compiler/src/ir/parameter-versions.ts b/packages/compiler/src/ir/parameter-versions.ts new file mode 100644 index 000000000..88232251c --- /dev/null +++ b/packages/compiler/src/ir/parameter-versions.ts @@ -0,0 +1,307 @@ +import { analyzeInt32Slots } from "./int32-slots.js"; +import { BOOL, F64, type IrExpr, type IrFunction, type IrModule, type IrStmt } from "./ir.js"; +import { reparseStmt } from "./serialize.js"; +import { everyExprChild, everyStmtChild, everyStmtList } from "./traverse.js"; + +const MAX_FUNCTION_NODES = 2048; +const MAX_VERSIONS = 16; + +function size(fn: IrFunction): number { + let nodes = 0; + everyStmtList(fn.body, { + stmt: () => ++nodes <= MAX_FUNCTION_NODES, + expr: () => ++nodes <= MAX_FUNCTION_NODES, + }); + return nodes; +} + +/** The function a direct call or construction runs, if any. */ +function callee(e: IrExpr): string | null { + if (e.kind === "call") return e.callee; + if (e.kind === "new") return `%${e.className}.constructor`; + return null; +} + +/** Direct call and construction sites of each function in the module. */ +function callSites(mod: IrModule): Map { + const sites = new Map(); + for (const fn of mod.functions) + everyStmtList(fn.body, { + stmt: () => true, + expr: (e) => { + const name = callee(e); + if (name !== null) sites.set(name, (sites.get(name) ?? 0) + 1); + return true; + }, + }); + return sites; +} + +/** Expressions and statements of a callee that LLVM inlines at any number + * of call sites: scalar arithmetic and reads, no calls or allocations. */ +const SIMPLE_EXPRESSIONS = new Set([ + "varRef", + "numLit", + "boolLit", + "bin", + "unary", + "logical", + "ternary", + "toBool", + "incDec", + "assignExpr", + "arrayGet", + "fieldGet", + "recordGet", + "unionNarrow", + "unionIsTag", +]); +const SIMPLE_STATEMENTS = new Set([ + "varDecl", + "assign", + "exprStmt", + "if", + "block", + "return", +]); + +function simple(fn: IrFunction): boolean { + return ( + (fn.returnType.kind === "f64" || fn.returnType.kind === "bool") && + everyStmtList(fn.body, { + stmt: (s) => SIMPLE_STATEMENTS.has(s.kind), + expr: (e) => SIMPLE_EXPRESSIONS.has(e.kind), + }) + ); +} + +/** Whether a copy of `fn` would cost a callee its only call site. LLVM + * inlines a function called once wherever its size allows; with a second + * site, both calls can stay out of line, with the records and arguments + * they pass built in memory. A callee that only computes a number or a + * boolean from scalar reads inlines either way. A function calling itself + * would also dispatch on every call. */ +function keepsSingleBody( + fn: IrFunction, + sites: ReadonlyMap, + functions: ReadonlyMap, +): boolean { + return !everyStmtList(fn.body, { + stmt: () => true, + expr: (e) => { + const name = callee(e); + if (name === null) return true; + if (name === fn.name) return false; + if (sites.get(name) !== 1) return true; + const target = functions.get(name); + return target !== undefined && simple(target); + }, + }); +} + +/** Statements and expressions of a loop whose work is numeric: arithmetic, + * element and field reads and writes, `Math` calls and calls of simple + * functions. Loops that allocate, build strings or call other code gain + * little from an integer bound and would only grow the copy. */ +const NUMERIC_STATEMENTS = new Set([ + ...SIMPLE_STATEMENTS, + "for", + "while", + "doWhile", + "break", + "continue", + "arraySet", + "fieldSet", +]); +const NUMERIC_EXPRESSIONS = new Set([...SIMPLE_EXPRESSIONS, "arrayHas", "arrayState"]); + +function numericLoop(loop: IrStmt, functions: ReadonlyMap): boolean { + const expr = (e: IrExpr): boolean => { + let allowed = NUMERIC_EXPRESSIONS.has(e.kind); + if (e.kind === "call") { + const target = functions.get(e.callee); + allowed = target !== undefined && simple(target); + } else if (e.kind === "libCall") allowed = e.fn.startsWith("math."); + else if (e.kind === "arrIntrinsic") allowed = e.method === "length"; + return allowed && everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => + NUMERIC_STATEMENTS.has(s.kind) && everyStmtChild(s, expr, stmt); + return stmt(loop); +} + +/** Number parameters of `fn` that bound one of its numeric loops: read in + * the loop's condition or in its `for` initializer. */ +function loopBounds(fn: IrFunction, functions: ReadonlyMap): Set { + const params = new Set( + fn.params.filter((param) => param.type.kind === "f64").map((param) => param.localId), + ); + const result = new Set(); + if (params.size === 0) return result; + const reads = (e: IrExpr): boolean => { + if (e.kind === "varRef" && params.has(e.localId)) result.add(e.localId); + return everyExprChild(e, reads, readsStmt); + }; + const readsStmt = (s: IrStmt): boolean => everyStmtChild(s, reads, readsStmt); + everyStmtList(fn.body, { + stmt: (s) => { + if (s.kind !== "for" && s.kind !== "while" && s.kind !== "doWhile") return true; + if (!numericLoop(s, functions)) return true; + if (s.cond) reads(s.cond); + if (s.kind === "for" && s.init) readsStmt(s.init); + return true; + }, + expr: () => true, + }); + return result; +} + +/** Versions of functions whose number parameters bound their loops. + * + * A parameter that every call site proves an int32 already reaches the + * function's i32 entry (int32-abi.ts). One that some caller passes as an + * unproven number (a value read from a message, a field, a parse) keeps + * its double, so the loops it bounds compare a counter with a double and + * the values derived from it stay doubles. + * + * A parameter qualifies when it bounds a numeric loop (`numericLoop`). + * Such a function gets a copy of its body under a new name, and its own + * body starts by calling the copy when every such parameter holds an + * int32: `(p | 0) === p` (an integer in the int32 range, not NaN) and not + * -0 (`1 / p` is not -Infinity). The copy then receives `p | 0`, which is + * the same double, so it computes what the body would; its only caller + * proves the parameter an int32, so it gets the i32 entry. Other values + * run the body as before. + * + * Only plain synchronous functions qualify: not class members, no + * captures, not the module entry, not dynamic-tier, at most + * MAX_FUNCTION_NODES nodes, not calling themselves, and not holding the + * only call site of another function (`keepsSingleBody`). The caller + * skips modules that observe call stacks, where the copy's frame could be + * seen. */ +export function versionLoopBoundParameters( + mod: IrModule, + symbolName: (name: string) => string = (name) => name, +): IrModule { + const candidates: { fn: IrFunction; params: Set }[] = []; + const sites = callSites(mod); + const functions = new Map(mod.functions.map((fn) => [fn.name, fn])); + const members = new Set((mod.classes ?? []).flatMap((cls) => cls.methods ?? [])); + for (const fn of mod.functions) { + if ( + // Constructors, methods and accessors (`%C.m`) and generated helper + // families (`%arr.map_…`) keep their single body. + fn.name.includes(".") || + members.has(fn.name) || + fn.async || + fn.generator || + fn.captures !== undefined || + fn.classCaptures?.length || + fn.tier === "dynamic" || + fn.name === mod.entry + ) + continue; + const params = loopBounds(fn, functions); + const locals = new Map(fn.locals.map((local) => [local.id, local])); + for (const id of params) { + const local = locals.get(id); + if (!local || local.boxed || local.tdz) params.delete(id); + } + if (params.size === 0 || size(fn) > MAX_FUNCTION_NODES || keepsSingleBody(fn, sites, functions)) + continue; + candidates.push({ fn, params }); + } + if (candidates.length === 0) return mod; + const slots = analyzeInt32Slots(mod); + const names = new Set(mod.functions.map((fn) => symbolName(fn.name))); + const replaced = new Map(); + const added: IrFunction[] = []; + for (const { fn, params } of candidates) { + if (added.length >= MAX_VERSIONS) break; + const unproven = fn.params.filter( + (param) => params.has(param.localId) && !slots.hasParam(fn.name, param.localId), + ); + if (unproven.length === 0) continue; + let name = `${fn.name}.int32Params`; + while (names.has(symbolName(name))) name += "_"; + names.add(symbolName(name)); + const { ownsPrototype: _ownsPrototype, ...implementation } = fn; + added.push({ ...implementation, name, body: fn.body.map(reparseStmt) }); + const loc = fn.body[0]?.loc ?? { file: mod.sourceFile, start: 0, end: 0 }; + const read = (localId: string): IrExpr => ({ kind: "varRef", localId, type: F64, loc }); + const int32 = (localId: string): IrExpr => ({ + kind: "bin", + op: "|", + left: read(localId), + right: { kind: "numLit", value: 0, type: F64, loc }, + type: F64, + loc, + }); + let test: IrExpr | null = null; + for (const param of unproven) { + const exact: IrExpr = { + kind: "bin", + op: "===", + left: int32(param.localId), + right: read(param.localId), + type: BOOL, + loc, + }; + const notNegativeZero: IrExpr = { + kind: "bin", + op: "!==", + left: { + kind: "bin", + op: "/", + left: { kind: "numLit", value: 1, type: F64, loc }, + right: read(param.localId), + type: F64, + loc, + }, + right: { kind: "numLit", value: -Infinity, type: F64, loc }, + type: BOOL, + loc, + }; + const both: IrExpr = { + kind: "logical", + op: "&&", + left: exact, + right: notNegativeZero, + type: BOOL, + loc, + }; + test = + test === null + ? both + : { kind: "logical", op: "&&", left: test, right: both, type: BOOL, loc }; + } + const versioned = new Set(unproven.map((param) => param.localId)); + const call: IrExpr = { + kind: "call", + callee: name, + args: fn.params.map((param) => + versioned.has(param.localId) + ? int32(param.localId) + : { kind: "varRef", localId: param.localId, type: param.type, loc }, + ), + type: fn.returnType, + loc, + }; + const run: IrStmt[] = + fn.returnType.kind === "void" + ? [ + { kind: "exprStmt", expr: call, loc }, + { kind: "return", value: null, loc }, + ] + : [{ kind: "return", value: call, loc }]; + replaced.set(fn, { + ...fn, + body: [{ kind: "if", cond: test!, then: run, else_: null, loc }, ...fn.body], + }); + } + if (added.length === 0) return mod; + return { + ...mod, + functions: [...mod.functions.map((fn) => replaced.get(fn) ?? fn), ...added], + }; +} diff --git a/packages/compiler/test/parameter-version-emission.test.ts b/packages/compiler/test/parameter-version-emission.test.ts new file mode 100644 index 000000000..eb6daff56 --- /dev/null +++ b/packages/compiler/test/parameter-version-emission.test.ts @@ -0,0 +1,71 @@ +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-parameter-version-")); + 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 }); + } +} + +const versions = (llvm: string): string[] => [ + ...new Set([...llvm.matchAll(/^define [^@]*@sc_\w+?_(\w+?)_int32Params\b/gm)].map((m) => m[1]!)), +]; + +const loops = ` +function sumTo(n: number): number { + let s = 0; + for (let i = 0; i < n; i++) s += i; + return s; +} +function literal(n: number): number { + let s = 0; + for (let i = 0; i < n; i++) s += i; + return s; +} +function recursive(n: number): number { + let s = 0; + for (let i = 0; i < n; i++) s += i; + return n > 0 ? s + recursive(n - 1) : s; +} +function unbounded(n: number): number { + let s = 0; + for (let i = 0; i < 10; i++) s += n; + return s; +} +class Counter { + total(n: number): number { + let s = 0; + for (let i = 0; i < n; i++) s += i; + return s; + } +} +const n = Number(process.argv.length > 5 ? "7.5" : "6"); +console.log(sumTo(n), literal(4), literal(5), recursive(n), unbounded(n), new Counter().total(n)); +`; + +test("a loop-bounding parameter some caller passes unproven gets an int32 version", async () => { + const llvm = await emitLlvm(loops); + expect(versions(llvm)).toEqual(["sumTo"]); + // The version takes the parameter as an i32, and the body dispatches to it + // after testing for an int32 that is not -0. + expect(llvm).toMatch(/^define [^@]*@sc_\w+_sumTo_int32Params\.i32\(i32 /m); + const body = /^define [^@]*@sc_\w+?_sumTo\([^]*?^}/m.exec(llvm)?.[0] ?? ""; + expect(body).toMatch(/call [^@]*@sc_\w+_sumTo_int32Params/); + expect(body).toMatch(/fdiv double 0x3FF0000000000000, %\S+/); +}); + +test("a module that reads stacks keeps a single body", async () => { + const llvm = await emitLlvm(`${loops}\nconsole.log(typeof new Error("x").stack);\n`); + expect(versions(llvm)).toEqual([]); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7323-loop-bound-parameter-versions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7323-loop-bound-parameter-versions.ts.json new file mode 100644 index 000000000..0a79c8cdb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7323-loop-bound-parameter-versions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7323-loop-bound-parameter-versions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7324-loop-bound-parameter-window-sums.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7324-loop-bound-parameter-window-sums.ts.json new file mode 100644 index 000000000..aedd853fb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7324-loop-bound-parameter-window-sums.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7324-loop-bound-parameter-window-sums.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7323-loop-bound-parameter-versions.ts b/tests/corpus/7323-loop-bound-parameter-versions.ts new file mode 100644 index 000000000..cdbb8cfc4 --- /dev/null +++ b/tests/corpus/7323-loop-bound-parameter-versions.ts @@ -0,0 +1,88 @@ +// Functions whose number parameters bound their loops, called with values +// no caller proves to be int32s: integers, fractions, NaN, -0, infinities, +// and integers past the int32 range. Every call prints Node's result, +// including -0 read back through 1 / n, a reassigned parameter, a thrown +// error, a void result and a function passed as a value. + +function show(label: string, value: number): void { + console.log(label, Object.is(value, -0) ? "-0" : String(value)); +} + +function sumTo(n: number): number { + let s = 0; + for (let i = 0; i < n; i++) s += i; + return s; +} + +function fill(n: number, out: number[]): void { + for (let i = 0; i < n; i++) out.push(i * 2); +} + +function sign(n: number): number { + let steps = 0; + for (let i = 0; i < n && steps < 4; i++) steps++; + return 1 / n + steps; +} + +function countdown(n: number, step: number): number { + let k = 0; + while (n > 0) { + n -= step; + k++; + if (k > 100) break; + } + return k * 1000 + n; +} + +function checked(n: number, limit: number): number { + let s = 0; + let over = -1; + for (let i = 0; i <= n; i++) { + if (i > limit && over < 0) over = i; + s += i; + } + if (over >= 0) throw new RangeError(`past ${limit} at ${over}`); + return s; +} + +function fillTo(n: number, out: number[]): number { + for (let i = 0; i < n; i++) out[i] = i * 3; + return out.length; +} + +function window2(a: number[], from: number, to: number): string { + const parts: string[] = []; + for (let i = from; i < to; i++) parts.push(String(a[i])); + return parts.join(","); +} + +// Values arrive as strings and JSON, so no caller proves them int32s. +const inputs: number[] = JSON.parse("[0, 1, 5, 7.5, -3, -0, 2147483647, 2147483648, -2147483649, 1e300]"); +inputs.push(NaN, Infinity, -Infinity, Number("12"), Number.parseFloat("3.25")); + +for (const n of inputs) { + const small = Math.abs(n) > 100 ? (n > 0 ? 3 : -3) : n; + show(`sumTo ${n}`, sumTo(small)); + show(`sign ${n}`, sign(n)); + show(`countdown ${n}`, countdown(small, 2)); + const out: number[] = []; + fill(small, out); + const dense: number[] = []; + const length = fillTo(small, dense); + console.log(`fill ${n}`, out.join(" "), length, dense.join(" ")); +} + +for (const n of [3, 4.5, 6]) { + try { + show(`checked ${n}`, checked(n, 4)); + } catch (e) { + console.log(`checked ${n} threw`, (e as Error).message); + } +} + +const data = [10, 20, 30, 40, 50]; +for (const [from, to] of JSON.parse("[[0, 2], [1.5, 4], [-1, 1], [3, 9], [2, 2]]") as [number, number][]) + console.log(`window ${from}..${to}`, window2(data, from, to)); + +const fns: ((n: number) => number)[] = [sumTo, (n) => sumTo(n) * 2]; +console.log(fns.map((f) => f(Number("4"))).join(" "), [1, 2.5, 3].map(sumTo).join(" ")); diff --git a/tests/corpus/7324-loop-bound-parameter-window-sums.ts b/tests/corpus/7324-loop-bound-parameter-window-sums.ts new file mode 100644 index 000000000..094e9848c --- /dev/null +++ b/tests/corpus/7324-loop-bound-parameter-window-sums.ts @@ -0,0 +1,33 @@ +// Sliding-window sums whose length and width are number parameters read +// from JSON, so no caller proves them int32s: int32 sizes run the +// function's int32 version, and a fractional width, a length past the +// int32 range, -0 and NaN run its ordinary body. + +function windowSums(n: number, width: number, values: number[], out: number[]): number { + let total = 0; + for (let i = 0; i + width <= n; i++) { + let s = 0; + for (let k = 0; k < width; k++) s += values[i + k]!; + out[i] = s; + total += s; + } + return total; +} + +const values: number[] = []; +for (let i = 0; i < 4000; i++) values.push((i * 37) % 101); + +const runs = JSON.parse( + "[[4000, 64, 3], [4000, 1, 2], [100, 2.5, 2], [10, 0, 1], [-0, 3, 1], [4000, 3000000000, 1], [3000000000, 4, 1], [12, 20, 1]]", +) as [number, number, number][]; +runs.push([NaN, 2, 1], [Number("250"), Number("8"), 2]); +for (const [n, width, rounds] of runs) { + const out: number[] = []; + const length = Math.min(Number.isFinite(n) ? n : 0, 4000); + for (let i = 0; i < length; i++) out.push(0); + let total = 0; + // A length past the values reads holes: keep that run within them. + const limit = n > 4000 ? 4000 : n; + for (let r = 0; r < rounds; r++) total += windowSums(limit, width, values, out); + console.log(`${n} ${width} ${rounds}:`, total, out.length, out.slice(0, 3).join(",")); +} diff --git a/tests/harness/corpus-costs/7323-loop-bound-parameter-versions.ts.json b/tests/harness/corpus-costs/7323-loop-bound-parameter-versions.ts.json new file mode 100644 index 000000000..ee18f5f11 --- /dev/null +++ b/tests/harness/corpus-costs/7323-loop-bound-parameter-versions.ts.json @@ -0,0 +1 @@ +{ "plain": 2000, "san": 2800 } diff --git a/tests/harness/corpus-costs/7324-loop-bound-parameter-window-sums.ts.json b/tests/harness/corpus-costs/7324-loop-bound-parameter-window-sums.ts.json new file mode 100644 index 000000000..9622c5beb --- /dev/null +++ b/tests/harness/corpus-costs/7324-loop-bound-parameter-window-sums.ts.json @@ -0,0 +1 @@ +{ "plain": 2000, "san": 3000 } From b4a3bace6005db55355e9c9e98108ffa9b60310b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 13:08:42 -0500 Subject: [PATCH 33/45] Read compact array slots in dense loop fast copies, and their flag only on 64-bit targets --- .../src/backend/llvm/local-array-reads.ts | 12 ++++++++++++ packages/runtime/src/scr_array.c | 2 +- packages/runtime/src/scr_array.h | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/backend/llvm/local-array-reads.ts b/packages/compiler/src/backend/llvm/local-array-reads.ts index 223d45540..716d05a94 100644 --- a/packages/compiler/src/backend/llvm/local-array-reads.ts +++ b/packages/compiler/src/backend/llvm/local-array-reads.ts @@ -619,6 +619,18 @@ export function emitBorrowedArrayRead( ); host.markMemoryPointer(dataPtr, "array:header"); B.line(`${data} = load ptr, ptr ${dataPtr}${host.fieldAliasAttachment(dataPtr)}`); + if (referenceLoad(host, read.arr.type) === "cref") { + // Compact references: 4-byte slots holding the address over 8. + const ref = B.tmp(); + B.line( + `${valuePtr} = getelementptr inbounds i32, ptr ${data}, ${host.sizeType} ${loopIndex}`, + ); + host.markMemoryPointer(valuePtr, "array:elements"); + B.line(`${ref} = load i32, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); + for (const line of compactRefLoadLines(ref, value, `${value}.r`)) B.line(line.trimStart()); + B.line(`store ptr ${value}, ptr ${slot}`); + return; + } B.line(`${valuePtr} = getelementptr inbounds i64, ptr ${data}, ${host.sizeType} ${loopIndex}`); host.markMemoryPointer(valuePtr, "array:elements"); B.line(`${value} = load ptr, ptr ${valuePtr}${host.fieldAliasAttachment(valuePtr)}`); diff --git a/packages/runtime/src/scr_array.c b/packages/runtime/src/scr_array.c index 50b461614..d4cdf0810 100644 --- a/packages/runtime/src/scr_array.c +++ b/packages/runtime/src/scr_array.c @@ -1417,7 +1417,7 @@ static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops_kind(const static inline __attribute__((always_inline)) ScrArr *scr_arr_make_ops(const ScrArrOps *ops, size_t initial_cap, bool small) { - if (__builtin_expect((ops->flags & SCR_ARR_OPS_COMPACT) != 0, 0)) + if (__builtin_expect(scr_arr_ops_compact(ops), 0)) return scr_arr_make_ops_kind(ops, initial_cap, small, SCR_ELEM_CREF); return scr_arr_make_ops_kind(ops, initial_cap, small, SCR_ELEM_REF); } diff --git a/packages/runtime/src/scr_array.h b/packages/runtime/src/scr_array.h index 2fea1ef2c..67ff7d528 100644 --- a/packages/runtime/src/scr_array.h +++ b/packages/runtime/src/scr_array.h @@ -68,7 +68,9 @@ typedef struct ScrArrOps { /* Registry id (scr_arr_ops_table), 0 until scr_arr_ops_register assigns * it on the first array of the type. Descriptors are writable for it. */ uint32_t id; - /* SCR_ARR_OPS_* */ + /* SCR_ARR_OPS_*. On 64-bit targets the field takes the struct's former + * tail padding, so descriptors emitted without it read 0 here; on 32-bit + * targets it lies past their end and is never read (scr_arr_ops_compact). */ uint32_t flags; } ScrArrOps; @@ -76,6 +78,17 @@ typedef struct ScrArrOps { * arrays of the type are SCR_ELEM_CREF (llvm/shapes.ts arrOps). */ #define SCR_ARR_OPS_COMPACT 1u +/* Whether `ops` describes compact class elements. Compact instances exist + * only on 64-bit targets. */ +static inline bool scr_arr_ops_compact(const ScrArrOps *ops) { +#if UINTPTR_MAX > 0xffffffffu + return (ops->flags & SCR_ARR_OPS_COMPACT) != 0; +#else + (void)ops; + return false; +#endif +} + typedef struct ScrArr { size_t rc; /* SIZE_MAX = immortal (unused for arrays; kept per convention) */ /* Length and dense capacity are at most SCR_ARR_MAX_LENGTH (2^32 - 1); From 8f08cbbec594caa07af7164bb57882209f81fbcd Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 13:09:01 -0500 Subject: [PATCH 34/45] Build Sets, Maps and weak collections from checked-dynamic iterables `new Set(x)`, `new Map(x)`, `new WeakSet(x)`, `new WeakMap(x)` and `Object.fromEntries(x)` now accept any checked-dynamic iterable, as in Node: a native iterator (`map.keys()`, `set.values()`), a compiled generator, an object with a Symbol.iterator method, or a Set. Before, a Set seed that was not an array or a string threw "is not iterable", and a Map, weak collection or Object.fromEntries seed that was a generator or a collection other than a Map refused with SC2020. The runtime drains native iterators, packs arrays, strings and collections, and steps every other iterable through its iterator (scr_dyn_seed_values). A program that builds these from an untyped seed registers the compiled generators' next and return methods with the runtime, as destructuring rest already did, so a generator seed can be stepped. The seed's values are all taken before the first one is added, so when an entry of a Map seed is not an object the TypeError comes after the iterable is exhausted; Node closes the iterator at that entry. The limitations page says so. --- .../limitations/builtin-apis/map-and-set.mdx | 2 ++ .../src/frontend/lowering/dispatch-sites.ts | 14 +++++++- .../6926-dynamic-collection-seeds.mjs.json | 6 ++++ .../6927-dynamic-collection-seeds.ts.json | 6 ++++ packages/runtime/src/scr_json.c | 32 +++++++++++-------- .../corpus/6926-dynamic-collection-seeds.mjs | 28 ++++++++++++++++ tests/corpus/6927-dynamic-collection-seeds.ts | 9 ++++++ .../6926-dynamic-collection-seeds.mjs.json | 1 + .../6927-dynamic-collection-seeds.ts.json | 1 + 9 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6926-dynamic-collection-seeds.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6927-dynamic-collection-seeds.ts.json create mode 100644 tests/corpus/6926-dynamic-collection-seeds.mjs create mode 100644 tests/corpus/6927-dynamic-collection-seeds.ts create mode 100644 tests/harness/corpus-costs/6926-dynamic-collection-seeds.mjs.json create mode 100644 tests/harness/corpus-costs/6927-dynamic-collection-seeds.ts.json diff --git a/docs/content/limitations/builtin-apis/map-and-set.mdx b/docs/content/limitations/builtin-apis/map-and-set.mdx index bf77001ee..ee7435b2d 100644 --- a/docs/content/limitations/builtin-apis/map-and-set.mdx +++ b/docs/content/limitations/builtin-apis/map-and-set.mdx @@ -7,4 +7,6 @@ They support `.next()`, `for...of`, array spreads, and mapper-less `Array.from`. They also support the iterator helper methods, such as `.map()` and `.take()`. Detached collection methods are unsupported. + Constructing a Map, Set, WeakMap or WeakSet, or calling `Object.fromEntries`, with a checked-dynamic iterable (a native iterator, a generator, or an object with a `Symbol.iterator` method) takes all of its values before adding the first one. + When an entry of a Map seed is not an object, the TypeError comes after the iterable is exhausted; Node closes the iterator at that entry. The Set composition methods (`union`, `intersection`, `difference`, `symmetricDifference`, `isSubsetOf`, `isSupersetOf`, `isDisjointFrom`) accept a Set of the same element type or a Map keyed by it; other set-like arguments are unsupported. diff --git a/packages/compiler/src/frontend/lowering/dispatch-sites.ts b/packages/compiler/src/frontend/lowering/dispatch-sites.ts index 2618dacf9..c8a8d6ba6 100644 --- a/packages/compiler/src/frontend/lowering/dispatch-sites.ts +++ b/packages/compiler/src/frontend/lowering/dispatch-sites.ts @@ -11,6 +11,18 @@ import { everyStmtList } from "../../ir/traverse.js"; import { toPrimitiveHint } from "./class-dynamic-dispatch.js"; import { GENERATOR_STEP_METHODS, HELPER_METHODS } from "./generator-dynamic-dispatch.js"; +/** Runtime entry points that step a checked-dynamic iterable's iterator: + * destructuring rest, and the collection constructors' and + * Object.fromEntries' seeds. */ +const RUNTIME_STEP_LIB_FNS: ReadonlySet = new Set([ + "dyn.destructureRest", + "dyn.nativeSetNew", + "dyn.mapSeedEntries", + "dyn.fromEntries", + "weakMap.new", + "weakSet.new", +]); + /** What one function's body holds for the class dispatch pass and its * caught-value, generator and class construction sub-passes, collected in * one walk. Lists keep the order the walk meets their entries. */ @@ -186,7 +198,7 @@ function scanSites(statements: IrStmt[]): FunctionSites { expr.key.kind === "strLit" && HELPER_METHODS.has(expr.key.value)) || expr.kind === "dynIterN" || - (expr.kind === "libCall" && expr.fn === "dyn.destructureRest") + (expr.kind === "libCall" && RUNTIME_STEP_LIB_FNS.has(expr.fn)) ) sites.runtimeSteps = true; switch (expr.kind) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6926-dynamic-collection-seeds.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6926-dynamic-collection-seeds.mjs.json new file mode 100644 index 000000000..32edfc402 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6926-dynamic-collection-seeds.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6926-dynamic-collection-seeds.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6927-dynamic-collection-seeds.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6927-dynamic-collection-seeds.ts.json new file mode 100644 index 000000000..89c591dd7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6927-dynamic-collection-seeds.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6927-dynamic-collection-seeds.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 1c85a928a..e4b66990d 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1577,6 +1577,20 @@ ScrDyn *scr_dyn_iter_pack(const ScrDyn *src, const ScrStr *msg) { static ScrDyn *scr_native_iterator_drain(const ScrDyn *src); +/* The values a collection constructor's iterable seed gives, in order: +1 + * array, or NULL with the exception pending. A native iterator (a Map's + * keys(), a Set's values()) drains, which runs no program code; arrays, + * strings, typed arrays and collections pack; other iterables (a + * generator, an object with a Symbol.iterator method) step their + * iterator to the end, so their values are all taken before the + * constructor adds the first one. */ +static ScrDyn *scr_dyn_seed_values(const ScrDyn *src) { + if (src->kind == SCR_DYN_HANDLE && + (src->v.handle.tag == SCR_DYNH_ITERATOR || scr_dyn_handle_ops_of(src)->iter_step)) + return scr_native_iterator_drain(src); + return scr_dyn_destructure_rest(src, NULL); +} + /* The for-of-over-dyn pack accessors: the emitted index loop drives them * over a scr_dyn_iter_pack result (ARR by construction — the defensive * arms cover nothing reachable from that lowering). Never throw. */ @@ -1592,18 +1606,10 @@ ScrDyn *scr_dyn_map_seed_entries(const ScrDyn *src) { if (scr_exc_pending()) return NULL; } /* A native iterator (sp.entries(), a Map's entries()) or a handle that - * steps through live entries (URLSearchParams): producing its entries - * runs no program code, so draining them first is what the consumer - * observes. */ - if (src->kind == SCR_DYN_HANDLE && - (src->v.handle.tag == SCR_DYNH_ITERATOR || scr_dyn_handle_ops_of(src)->iter_step)) - return scr_native_iterator_drain(src); - if (src->kind == SCR_DYN_HANDLE || src->kind == SCR_DYN_TYPED_REF) { - static const char message[] = "new Map(entries) over native non-array iterables has no lowering"; - scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); - return NULL; - } - return scr_dyn_iter_pack(src, NULL); + * steps through live entries (URLSearchParams) drains; a Set, a + * generator or another iterable gives its values in order + * (scr_dyn_seed_values). */ + return scr_dyn_seed_values(src); } ScrDyn *scr_dyn_map_seed_entry(const ScrDyn *entry) { @@ -14836,7 +14842,7 @@ ScrDyn *scr_dyn_native_set(ScrMap *value) { ScrDyn *scr_dyn_native_set_new(const ScrDyn *seed) { ScrDyn *items = NULL; if (seed->kind != SCR_DYN_NULL && seed->kind != SCR_DYN_UNDEF) { - items = scr_dyn_iter_pack(seed, NULL); + items = scr_dyn_seed_values(seed); if (!items) return NULL; } ScrMap *set = scr_map_new(SCR_MAP_KEY_DYN, SCR_MAP_VAL_F64, &scr_map_dyn_set_ops); diff --git a/tests/corpus/6926-dynamic-collection-seeds.mjs b/tests/corpus/6926-dynamic-collection-seeds.mjs new file mode 100644 index 000000000..a48fab894 --- /dev/null +++ b/tests/corpus/6926-dynamic-collection-seeds.mjs @@ -0,0 +1,28 @@ +// Set, Map, WeakSet and Object.fromEntries over checked-dynamic iterables: +// native iterators, generators, objects with a Symbol.iterator method and +// collections, as seeds that reach the runtime untyped. +function* pairs() { yield ["g", 1]; yield ["h", 2]; } +function* values() { yield 1; yield 2; yield 2; } +const iterable = { *[Symbol.iterator]() { yield ["i", 3]; } }; +const valueIterable = { *[Symbol.iterator]() { yield "a"; yield "b"; } }; +function attempt(label, make) { + try { console.log(label, make()); } catch (e) { console.log(label, "threw", e.name, e.message); } +} +function viaSet(x) { return new Set(x).size; } +function viaMap(x) { return [...new Map(x).keys()].join(); } +function viaWeakSet(x) { return new WeakSet(x).has(key); } +const key = {}; +const m = new Map([["a", 1], ["b", 2]]); +attempt("set keys()", () => viaSet(m.keys())); +attempt("set values()", () => viaSet(new Set([1, 2]).values())); +attempt("set generator", () => viaSet(values())); +attempt("set iterable", () => viaSet(valueIterable)); +attempt("set string", () => viaSet("abca")); +attempt("set number", () => viaSet(5)); +attempt("map generator", () => viaMap(pairs())); +attempt("map iterable", () => viaMap(iterable)); +attempt("map set", () => viaMap(new Set([["s", 1]]))); +attempt("map entries()", () => viaMap(m.entries())); +attempt("map bad entry", () => viaMap([1])); +attempt("weakset generator", () => viaWeakSet((function* () { yield key; })())); +attempt("fromEntries generator", () => JSON.stringify(Object.fromEntries(pairs()))); diff --git a/tests/corpus/6927-dynamic-collection-seeds.ts b/tests/corpus/6927-dynamic-collection-seeds.ts new file mode 100644 index 000000000..c57433d57 --- /dev/null +++ b/tests/corpus/6927-dynamic-collection-seeds.ts @@ -0,0 +1,9 @@ +// Set and Map seeds held as any: native iterators and generators. +function* values(): Generator { yield 1; yield 2; yield 2; } +function* pairs(): Generator<[string, number]> { yield ["a", 1]; yield ["b", 2]; } +const m = new Map([["x", 1], ["y", 2]]); +const anyKeys: any = m.keys(); +const anyGen: any = values(); +const anyPairs: any = pairs(); +console.log(new Set(anyKeys).size, new Set(anyGen).size, new Map(anyPairs).size); +console.log(new Set(values()).size, new Map(pairs()).get("b"), new Set(m.values()).size); diff --git a/tests/harness/corpus-costs/6926-dynamic-collection-seeds.mjs.json b/tests/harness/corpus-costs/6926-dynamic-collection-seeds.mjs.json new file mode 100644 index 000000000..b4a56f5c5 --- /dev/null +++ b/tests/harness/corpus-costs/6926-dynamic-collection-seeds.mjs.json @@ -0,0 +1 @@ +{ "plain": 3813, "san": 3374 } diff --git a/tests/harness/corpus-costs/6927-dynamic-collection-seeds.ts.json b/tests/harness/corpus-costs/6927-dynamic-collection-seeds.ts.json new file mode 100644 index 000000000..93da087d2 --- /dev/null +++ b/tests/harness/corpus-costs/6927-dynamic-collection-seeds.ts.json @@ -0,0 +1 @@ +{ "plain": 2436, "san": 2273 } From e39ddf3d00e0b1305f4ceff4534547adace32f5c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 13:18:04 -0500 Subject: [PATCH 35/45] Refresh the native compiler's optimization profile --- packages/compiler/native/cli.profdata.gz | Bin 1452782 -> 1634955 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 55523e76548ae821bbce8762876d84a3b3ccd182..e2f344a4d7f73f6e5b70e119a45c1e9db5fdf6d3 100644 GIT binary patch literal 1634955 zcmV);K!(2`iwFP!000021MD4loD)TNcXOTIj*fIt+V%oS@6tS~AcifocY$1TBst&& zDHe)~pjc2qu`8gWf`Vc}u>gvQilC@`B8s9YidX>oejz(|mq{k&3LKF4&&zCfr@ndf z-kUdX&N%ZtZqqTh3UL-l0)dU2-VI8>ziDSsdY6?>vC`Eoe1|iDJEYV)iyvwE(TL*s z*W)Y^d79ps(FE5uTS{q?EA^q^Bz@fXK|alXKEEM_rTJmvpBWu zYiFC()OtRrL7;~Boq8_Sk45Ww(}&L{i8~uSc=kiP_595?>1Xl1N$n{=UTZy{_-w{m zJTr6GSv(F_RHz*2ukVMS#Vu`C{a+3A?9I6~&*J|A*%H6as(KcW&kxkMVco!Ux?#1m z_`Ugo^zcyuJhofl`IfXm`tPp-cz@5p^Uthm>|PS6kk~8myteiHM8C7mAi7)6t?Chz zexa;^r-&}o+xh;N)XMtjur;J!-L9E-`*c>Y=kk(hcekbNKWeyROks zkL&om?XHH@KH}U$8gYK0q~&Iu<9cQg3Am7+^sqc2*J;ft5LlQ)EGuIjUN_k$uMfF9T-X z%oAAgcRfdjErKGFiJDWl9{u(|Y!RFyFbd0X94*s~$jWFDcUKBvfN4cCv2a9#rGNj@ z5(-B|$Wov0a=2Y~m+JAjr`dT^Vf;;z04qH4&e-WQ4sR^vL=bL~&drKT5-G%8zy18d z)EdnQB1mX0R(sXsv4g3=Q(!k`lVwkBr`*&?kZGb6aXB4isvxHm^_ubAi z;-Y9i^@_>Q#c9k&q!Irf`st>A^XuU#OAtj-Vp)#mC7D-3XgALi8?V9)P8!kPcU*sd z;bm6(H!_?I$=Ig>EeoiIsyV@Mr|N3Atv|zL-CMQu1;#B>qC8JYFjNeg-1tfLZJQcF zYtEWLQPvctv9wwf}op+%Tu>-=w9& z5sz9p)xuq2x^8%!UE;ddB8Cngec0I+)^$PHx^e;wc!6Vq%*lrijXlw+{#(gaO4v_H zaX!b_y*5!}YC9l)+B#IRDUvAd4sU

#6I&>venj0Nts2RG-7`%FelOZSP`g&X}ef zgK%hhb%=jnUN?1PY76VhG76(Xdw@^PwyQeeIYpE-gV!FFlg+Ph-jOt{gq>Ekf(yU( zehB}(nN{y?R=Q2KV3W(!=eV8?kbdk^#{GI@6zzUdjQQM$q#Kgu!>lMGlNhyq{J>h3 zAOn~fmH_~cqYXvYX$EK?-Oz%Vd3a;U!Z0q*n>94mZy)2v(E z`Q4L8l(1oZVsR`NXnT>juQKL&qnKC7`oy+d<~`MW8C82+79nMZl5{-z=)%}|uY=gDHGYl)! ztUxP*LNf}-poY>fvg!n3bUbXtWkjbBKibp0G2X~8Fbb{6j3V+1%Skj^#7-`NU&aji zWyHHTZ|~i18RX`2SZ>ZM3a{}1CF{HLZGapPY3YNPg9tZetqF5 zX=_(#kY5r;_!3w-V9x8E<8T^1J=xx#o^0ZmAKDDL^1HOEM6f6T0p0y9Z+V>}ni9J< z-Xy<%MFWJdAWI-C(Tr>uI?u6Z&Yb!6lZ+u5kbr8XhtInyv1t9TH}rV2Ug&Um{6eC` zFDn9t0SdxC;u5jmOGd4mUvJUopbdPhBt zsA3Dw6D1tzeRKunz*c3RLEcNX+`3j|113~om%CZ91ENq<}@kZ=PoU%0xQ^Dpapcd_J; zTOXi?_PK@UBk%ob71Y<_`oJ8T8#5xLgliV2WWkwrK=+Ou-5Ckug1_5g)%#i`KZsj4 z3;!P63|fuJ=bM`0pWlG=Lk$d_9Eh?Ilr*1`epj`W-(P9e!+x5*;Kic>HlvKNf_1{Cr_diVUDJA{kcf2`5xM#)XzqWuJs+gyZ#|5U@ zJq*j5nkupeBPoA2&$?~m$xW4@x)!e=FiCVK)}7q&d+)-{=`j0t{+%sdWkg9+Sx)2c z{vu26wmO}PW|}D~qbo6}^N0iTB>X16OtXwgvl7opoJfo44*TcUKHcXci7BERaTDWO zw_;zUOTWe7yZ|pI96rZ2F2SpbW965g2>uEz-0i>aNsfB zo?O+XgE6Yd<#2^=_NK%*DS8uRtG=1d=2ZJaweB2{!G2_$V*0)hv8B-+ z+5e=#|M!Nr$M5*#b>{**s~DO|GZLrM>a0oKZWQ*7%|HpJX`^6_J})b%T*~+Hyskg7 zcHd(kyk$aa93GY$O_dQvU0?*-lxwv<`W#btUJ7J*PgjYb-%>$!xQbX|F5c%^z*XprSq4^Y1;85bTaamPwO>2r@V+$#eQB9HN1cTRAc-h zyY$0yZ(wBZL>iMZCGfoOpy225J*|Q$<#@I~nIQJExqr@qUIt@BNY&wT`0Sj_ZtlG` zbK{SXr9-iIwMA5)k)@r9F2bc|cV4i(b##HlKGG|Vad?2;15{%$aAo^)xW)H17P~&2 z0)>pm?#QNArDJ$rx2kISa2ks65Pv;84xFxp*Y*US<77sV6`p5#I>co=1;eCa5gwxT zyFau!*$rO+EAl+8D1so%5-*21Y!Cl9Fo$9ZRn-H8w^- z#aUkYO9In~1&^CQHu)qnZL73S3zEv2qQs!IorKMMCZV@W|J!5YjU$4>DiSM-94pA2 z!lTsvzO`|+7F)z@V&S|`m+0HDVztQ_K+`mXRuvN!s~@oJ$wLcb?X88xus6GRAGHO~ zYjL*W=MWWHYYQh-5sC#ztJxSiNLJ9+Es&JFMjg6XnL3J_@qs4_6rf0 zqz4PG`!yNvWOeFQx;lSsEhpD?Ikyw;mgMm1TjF$WUl`*F&cWp*e4*vzEGc&pV_v$d z)9{V(0LYxs5ifoKgy&gSRwRvA4e-kL|N6gUETY<5pU(bYd{t~|&FYV>n6bUC36u?G zq^StQdeCArCz}WB6}Nf=_))9s>n!1KniSl(jAcK$#mW~RU|#XUg|#bH#DbO*G{5R$ z`ijU$)HvOgG?7<0Ndc&Fb-69pvhE=+OS zG~bawr#4A~{;(Ypj6x=Yqdh*KQ|5y-7xfW=_G#O3MWfh>x^;|1zB8o#x zT236SvDx|2!3YY0$kGDCvjXc6cBh~tULRvvE-GRLG3Yks?a!;%4I>ozJgN@t9!+Nq zMWRKClZ@<~`>w4~`40-!I8tI(Bp)Okc|ZL6XOBp|r$~~?>58C8M#z3sRSXVo+CxOf zmMX8E-d!WK_lm2mQphnnoW@#|^(rFgM)yY}2f;=9srF$M1&IwD7wzfss0Ab39-lu3 z+{o!Coj2@wGWpI5c227&k$|!Qs)8?MNf%jv+b)rDBcj;fFSNK;7aJYcxWM_<`J(@% zi;VuxwXw=p&UBIBV->5N=PJL%yg$GEy+#?&WAxb4unTOwZ3(_`N$}f?O)k7p`BA*< zzb!$x6-$1*!1&9t1fM>y@)(2$=UMJ4Z~k9a^X=dzx=xlAJsi70_&`P1-^!YP50>$G z5*4If=bGM*m9T$%mQoIjHQ#d$wi320BS!vLBTD{BQTV0}!MOV2>a!4oHz638Uk0Xq zupUz}&mpdX>4!Zrt{1S~Q%g9$88QA3>k+FHZBmr+rI2t3XgRhL);HF6mNoy#z_bsA zCS_C}bQWuep%Ysa{uQena-r^zoNp-Wbt@Wu;hvXtz8t(j`uSjj)Gn#{bD_wQ7b{G? zK+F^PIr{yW^iPtQ@!cy`lrCR|N;dvHe!E^|Yv#tBLW(^}-LC(9^w`JGs{b zoIv%0j`_e4CEf&_p#bBStdysU`;*s3FutgDM4gTAv}k-Ej0jsS=8DHE%I?ub%^v|s zFj=0n8^G)HxCu7O)a$PIR!7<|S*8~A=}GHtVCytnWcJ6QWUM3~luE%SB4J$7)b z#aYliF&0OBoZvs|J>28Y_Ncl3vPZb{Jv!*;aDt&~F7V#{__IgH4m?0Yy4#ExG~zv# zUR1?5h~MkJu(Qdk$RT(XL1ko75IK{RuKwl*Wy_{{RUpkLBRKv#Y$e{S{AIgQ3_NL8 z>_n=e+Z8F~aCHhMD;u$$xap_lDuWN_ejMpWn|&Ier-|Ec~g_Ts6}wlDV8r2aXo?D)0gC5a7#k8~(#ZjlX=P)`Jr|q`zxTm5;2cl4F%6G!HJ*g*2N- zVu_0hxhVk&NI(J-P=VmJ4+D7CZcF6+Ao%}BN+}OOv1GP|mnYW43IR2VVEH88|I143 ztSFFliIsb)Kw1UQF988)p6G%EB%s2AMqZfp;x6zzTCTEiVXc=RTX`R0Vy+=^k>rK6^pZ{u9^a3>e`6SujVO>=w# zjHvUBL>)g}h5!5JDoIvZpI2~afzQcHlbKU-_CtB~(`RI&-%HZppIxGKTTzs=X!%t% zzVdm3UK0J2fJ@FuQ&#Il!nl=?YZ8!v1SFt5pvdC(Kce~4foH~yhvtnp!QrjdFaZ`bElcAw8V$P`BsGOKZ#}zQ9&GN9DYXS$+Rt1GtOD*QV3K{2%hW(boGg zVBKhBozN}pw4T?f6}&#&jqv&I*8BUb1;0NUso(e2g7fWz;d7mkbWH?rvwnPDEj%B| zv2d?A`xUJ(jEp!FnMaV$f5(*54&is7R13~;ht=Tm=ZSt2aBd-5ct@0eo+5*VW^_CH zPQ;z@b|j6Sva5@vtHqhF9EDCRMG@j-O`q`H_T!){nh!_+PmhvLi!+^yS*LO7WK5bQ zz9)_k_h?OS#d}9^tl(FmL_uJ9PGL~*h?>d4I8>MTfuOo{pKxs^KHeZL3arR;BF}Ox zD+*{4`Ie@0IX2Mm&%}c94YO@^Ae|HoBI?ndZWpk7SXO5hmXkO}Q_zs2OfnfZV~RLV z44nYRec!7duI?-^DWWV2iXiZc5YjtOT8e2$TllIUC$3pmz0(Y5WSx#SIl%;mq-zX= z>U8~L)|vkz7H*mGUh)IbcVur-Sw^m%5e2*EHVR&(hdXTFJd}b?xkgcBu)$Q>rpqdy zqOl~&etZ8L-15r0SUMDGmZxc&mN+?-3Qw*hBhF2dob(j=!Ib;4u~`k#U^rf5L`LLV ze>8g5?`!H5#%Aq|VJ!I3w2^l%zI@N$ldr&AKpZZg8|vzUYzMgx--sO51B}6L)#&Ma z{Yb-p?oM;6!m!adSS`i*4jIV*Fx`#}{~j8zdxM4FjZ>-cV*4PO?DTT8MMvx{5OFXl zoVBPL98g$})inUaS=$XXpmp7$vFY?Uj~g42Mjp9y<-ymlgSzy_8sSYQy4&UTsV?6L zAIR(I;MgnQ8MnDEvowWE?4Beb0Y!#a>j<@Zj>^kQgu;r+7F1r4QA#?w*y#RJX>Vy^ zW;q$-o1Eiz@QHCvKmy8qJx?j+`f{oC)A@#0WmJ#!gj{w>!TDM@M_(k)dvM-$MEY^^ zB}!ioq+ePf{Zbg|jC`xn9qpcT7v3ordS8+0va^iA(LmQViI=nAo?m6#Vt3V83HA>J zM*g_m27E;Ql|XPeSjaL>;JVAnD4OG)Yt? zzq+IQ*Hs!cKxz_98-Sr1Rx<=i(?V_x?2M(m>g2{BY*{PE;q(+EIdt~zy&7dhiVm}pmdgr^-E_DNzoTnUk4G)&<@R{o z)4Vg@I5T_rHv^JUYA3BC-mr=sa6>Tee?$1^C@w2_1G{rxhpcq>!CU@LhV!%726W*r zqQhrr1rEJ+79L*tEb2|DndH@DAMModkERH(M5ch(oeS&?5LihxS>E88&AvfP|GIp8 zmCFzw6R*ZsKg#!|h0Jr5FP?@QkYL4@0abcn`5417yv#AOz$h{;33SNjwiLjB*>Ho{ zh`jm3k8|capjkAhsEDGyRzr{hCo+Pm@VedWbWeM8@HcILzHDX{=&!Wr3LBR z|3=O&&W7fugvV$}6w#J^f3i>h>3Y1YlRx?k%QK=PE3zzwOcMT?z^EsshA*NmsqTJm zZO)zuk!Bb{V0ndBM4I8~5NV?Qt$_lTHo^7Q_xmZ{!XNoGVF(xe;BFaij zy6W0W`F*VUmv_E+R@$EYAgy51m2~}3akEI;6bw^f7)_=XPC%v2mxtg8up{~J)!$YA zy)7KPC1GYa&&qZWm;`j+2%qY|jy}iX{cw5ey0s5bWM!nnCMZ8#&FvMy;14W9dVa1FKCRn*-O@&Ed$Y@!qSYE|R$x6edzl#>)mH&ls{bQ*P( zs~j^+qRF*irS1Q>5Wq<&@4!2{Y$Qe*s%j8bk&l=o9&{GP<<_eq$3FR5K1CC+{876~=;QH}<;1{j5^@!I#@hFm>h0$?!i!vKLY0;Hsg!t2P+>?>_ z|7YPGYaB%@Ll}xH*D`9Xwc7KXHU9Tn#scT}0lebTK*8Vj3j8swPN1P5T8Gch{AJOX zMTjss*gVTCHfvDey;+t=(_E_^efpHooG+T&9LbMZ;BL1So_%|Y3YpuvoXpz&o>W;t zHF_2Fb%I>r@_GN<;?QU;Dcj+>-I9ZIE@ZTNsQ{!2Mt3 z)+&;x#^3wXzSG!dv%Dh9ionT|C^8JMpv|7KIY1-%m}ZOQr?ZFc{NojPLT3Q3(JaH+ zvw#Uaz@>vR9)}Nj7d*Q5hhuB%6rK}&==Z=)q&MYu4=U?a)Ke@HDdy4hUXtO`9p?H; z|CIwG!%IA;3P2Ehj@V(7@>W%boT4={XibuWF$(>yaKLM=j)H@pg}irb8M_Y32-iWg zcO!k3OTu>*a^|Wj{qFh*PYRMOGYYFPf*|ue9TH@*m*ryL0efJnE4h5fnvI7GizrSE zh38NtQIK_DvNF#IC4J649o0Ob^cw zi}LS9l2x5|rgx3#dJY(lHaUiqG)+QX&naxyy~$Nu7q{{)vetc~diZk#U@Gtw*dpI6Mx~#&WlW54vAwn=Fi16vQNL5e*;tT(~nmpK{-Y@2Mcm^uWJ;eDghueRm z#;0c6WkZovU8WUTP+ot2{xGxa)MOZeyn2OOT}O~tymtEMZT*p}1q*jdh=tNMV)p*kJc1A8{`-Tg(D+--Gwp*ph27L3s% zMv>;vH?O&=ccep3tjI8eYKWYu8|WdYA!Ad+;?Q0iP3Hc1c;SFa*nq{1BG8h+GOR!g z48x;bYSi{XcYRtHHx6UTox43ZcbQhGrB@HP4l1IiNxICk1}`6aY;OPYf7hXEP_apV z(av)wA*>$`TPh~s`6Z-1)H?7<2_@&Wa^g`qVB^fUq$fuz`Z!#y?YhwD>q4(@Ed;C;uKslWe((moE^BM0l%wQYkL>7{yi++5QIa^bC9?G ze8c{E>20EvH(d1qmoEo+9oGW`UtsU6zom-f&;lou9iJKb@=Yfj;0rWec0*Tnj@CF@ zQ)$#VJ2`46y2$(8NA|5d4c%JuipnS+1dmh1dEf2LqwBww3=g6FXZ`q$EH9SiAz!-l z{hx+vO%T!!+HQ~)g%cIk5F}O)yUW`e!6@MVFS3zOBRh{jyzti_Bbwh8UgdOC$+l}g&R1>}=k-@P^Y z75siZ%h3`iN{TGdyv#_bv3zOOU>sV+3^LcVt?sDw$keMd9II)%%IdP7ykN)`#mlfo zZN?3xXVdO)#^&LJ|FMk7%CaDH49^KP9e*=slRbC*{m}AnB3$9fOAO7jk|eSmuY~l} zc59F}WA}CEkV9U&u13dGkpny#oFp59#ITaaq5+=LVjOsixRK16y=mvWZ@{3qd$EhJ z#M_6eKF3th+nt-|a01WSTl9u${s3LQKiYofv16+Xo#{Tda@kFW7k4S-y=d=$OomUR z7!`vd-W?-PBIA7jViyB%B(s(_t$N>*h@6gBbs(}jBa2+fb)vl+;E4Pdvim`AooW=^ zpxqcsN$2+lvRTjbzW5UhWlsI_Q`u}XyD{ej+Lyn(Z0LxhWP%+Z)N!3(=;~5RT81qFXfEQcoj!`G~B9ch@>$k_IMrOH^E{U37P*W?#8CD8$CmUoj-G{M#bthS!yvlC-D#8k=@T|m2v`kAP8+!Zi&z6nnFs6t* z$$L_=AAO>B#JMDM5^d@n;0#?x=Tbv#_uNHZw_tGfj}Ap1XW5`70f>@JGX^@&t)nij z_mX3Ne&xE6-#5cAN*{$J91_&NmR z(gKRmHD}kG%AHVhY#$9sXt&FZvNfm5;CyB?&?1h{D z_~mODh;>&=s1nPtqTQwXqr8uBx_w!yD;s$CR?94S`?gAHaHD>Ph2iB4-&x#nJRE6@ z(|l=J(x+P%^Oxa5W5r_l`*d(k;q$$gIcDhm;PhZyFvjT!r)OG*YfE>sV|>Sd)C2f2 zgiS%o76v?i1^Mnf3%@@+wh{QMggad@|F?&ijsjw>=YTjF7VQ5gFrG`W-cvHdKmWB( z`0sv0Fk1gttn_Eq!slC3fc1pRu@Q2lJ_gnNbrDpj04lU<9rT$kZ{5ZmX8WF{u z_aSB+lB0|diqQ=fSf5zwt9LnRWCJczP47rzFCz$=7F)@~NuU(5hFthvy;V1MDm<1I zUc@pTP9N~tMb1z}QDszK;2Nb2skGqrHmUGro#UF)ZSR%z`y*v^-y<#`^f^q&TJF&K zd(?H3Gm`P_X9Tu0ZO ze&N#(Z%o3ukD=oS7dzNdLKORx4N*VJTJEEW_2kzNAG_hlq0s!27fS8L{o@tI&{zcs zw8#j?N5`IMzja&26^J5RQm7xLGf=36c`sTNuM3US!@*ilPI_`n_1m6-Zs^5NSp@EL z@oTq@+;?q_%6}B9_8spG#zZj%KGM;qIhZs>yiC5_@g>lBHCgo+`|f=s zyNw-qfJFBUnjpC3I_A6N#xd_7U$?eNBs&hRYa*+Otf6T9*?qeouetS$x@(rhee@7X z9L1sKZX;iK@}U-<7H~Y$lETrcY(LA|eQr+{@a8*xqg7`<@SnSGmHo%9x$cumHeA$oFhK7(>lgY zH1t3T7oJK{#tS;0w6a`X9-lx4)%z)o(FxYCON{laM1(i3;BJw5hm5a16@C3BiS6Xh zy$1i{zQ~J*sPQyV1w-L96FN41xJ*xNC}J!YK1FswrJj6_RZh(p0n%fj6ZyW9UYS?6bV zD~W<4Xd3&(J7cHMIJ`0HeNH8Xeo<$}H{_zVY3p{rjor|cOq~}QgP|GO__KM|Z4--K zef6ESqxHq8$PBlrxF5;K+H7oaXBwpSC1JxN@sen;rYZBLC|>={%-YMI9Z=0#%nneT znW0PxT?F5c@w+OR@3Tw!{ne%XUO3O+w<%%2qhX2QCC?ur&s`SIMBYQ|H5Pf^3;Dk* zCS4ViFPeWxMz_T1Lu`J8c0w1zxKYD$jko!_`Mf^$Lwow?>$I~pdw#9T8P2qWsS9n#^VTc2? z6$7xXI6>O#beh>7NW3|KcRF<+bAJ0Pc$sKX#^-4{IqhVpgN3Y(ClG*Q?W!Ip)>vlcw2OL2%ZY zomt%d0)=RPez2%&)Strh`}*{ZbQnSgGNaLkY>2dm9)_5m93F>`S9NN+CwbNT_ctJd z7f!@Z#p?zy3Wg%dtjO$hU32e~8UJFozFQLsNI=Df)}{QvqCoTWRBqJ^q<=CKq@I8T zT<}oVK8zJDltR@+xfPP1U+m>wtWZ`Vmdct>RP_83aB0fPmm2?}675Mq0uqpb62XC# z_|}Vf?P*m@xGp6j{IDwWeP)dL)kgA(H-uKS`p23NRmy%$KmrnwfCMBU0SSl~@cys0 zsjrTAn)m+w&@-o4*svlW4@IzhRTDT1&Zaev=2)H4fy8SmACLdE-|2;^(0@R06}cj~ zOIYrDXYK)?lb%rYUnaGp$C0OG75ZiM2)*gfI&jC(_OoI6hD~z;k2lAWXLoq}d4M

+;|Atx75w;5ZM|3@I{p-8$?l>FjNvhZJN-nuy?`8tRiwWBXhDsOG1dF;K9uS+zlzR$Z@9;)oMh3?j6;!p3tnx0#Q~0 zuV@_V3B54J0WWfWYC=tz_2;pnm%}M>Aau?LPAj_%JD>&CkW2tnnxAv0@AcJtmtwW9 zqsSEM6U9RczJD~%LoTa{(!G!4hE1sMddl9$`4M9VshZ4bn!sti5E3(}m(?@PE#h95 z8k`Ot`75YayIyFz^7g8swB@p#!*bO;H0aggD+9q{_Gctv@@+>Yx2Sd6)iPpJM1?tf z7{rh`6>W-Yb<9pHy_5(}hZfm^YE0Mv!`Kdw_J%vz$+EP4n!{zdr+G)@Yu*B{59AJZ zxF!QnPfxb@<&}*OEL_1>fm6M_Bk2{@ouS5De`NQ&SrJbenzX13tO7XI41db-jfW!R z&~jPozREjiZmS19go{N`EGn1fI7OgERgug>58;~4uKw}UXIiB~!s<*0V-(Qm%gEp< zfQC=wk@V$A8Vyc_-g8zhiXjC}qpt3iqogavxf-RFGMyS{Iwj6@av^i(sAl;q7uK4A zU2Q~`Wo1@ic%GLeF68RRSFLb*b1|z8M^VyauBJ;H5WyS}JqE){w9fLpu5e`c6U~<{ z<_hmFY>kWw>I4mQ{?fw#*kbz*_dObBMTEkr|FX9 zP}U}}tli-qn41d>hw1}?SZ+seIQ@|L&&{@HFL3>#Q;fdO(cmN*dD^tM@Kxujolr=; z+^T0CGMKdDg)W%qHH%3iXZsJ6|LbME0@jc5J$Fgzq=et0?C`26^+jhmi|Jp4#}Pft zs2>MKp>H@}AQOgx>}Od7#*)FyWQz6P0wh0pf({;kpNK5SvHH_Nmg|hOU8ymSS4D>+ zR^FMaHhN{dWmVxKlS74F{(#2NtY8W<;Qu@RWv%feS`q`H=wyvy9Sc`l75uzbqassB zaro52c5Cs-ObQl-)>$&k?3D2NmsP&Qtj<_r(crQD!R6udf%QQ1tJNrceQ@RAp2Plo z!J6H$og=IW%MDJGLFwAov7~P;+4lESk^diIsk?S~$!zcN@4^4!`|v%8(R|8|HoH(# z%0I)u_QKdW%fi{>iq2c9`eZd549v}QdwkxJy%#*|7t&%44ViR~W*kLyrCN{Q_f^J* zHuxEr%P_QGcrt*?=kOKub~~Lw_c`3It3W|c`)?Xv|NBgGAf_M{NnaObX~2C)l=F8) z1^ccAYK*bgh$ToGEk}*9{CJ{cBVK_nvWg^1oT0M{jk^NzS<$eVqGmi~45_9~ZQ1hrV9yze?YSNYZ#i% zzxLYVh=;>9nPC`7Rx}9+xWnN#?0V9N>V8%2g?eh_&@(D;sG2BCiot}0o|zVP&FV+3 zu3ht{l!=kgAB&90OQI@q3J3{J-xQm7e`@;MpFf|L6md!_j43N7$D2UV(J8qBy-zAi zbCQVxlyu94{#l!02!^J(D@|Blv=4TUQJs_h*N6FUGa2PSXFtZ{4+vJNNq_OO$tMa$ zr=Df3e#8pPkole#hB}Kw-6(rB(e`v~7_|#c51=kBKct|wGE@L`-^Mk|%-TaUZ ze0$ra+vPXAG6G98x@t-^KxtNMiOV*# z_gfFv_#3;C19(XmO<83`UP15ZFkTPzpUo;|{5&$OvQ<=A?d$)pKdJC4sR3b)*1XK? zh6wySR0|$m`@^v{bt)Aajji#TNd{XR&~&IwH;B6Swb|?UKMUDB9pOp=9q1Zs(xwUo z_4wqZ&)GN9n_@<%f0T4I=wHhJV>MIURZ7tx{T{a=HHhk*)iig_nh1e5OqZQuG=b$< zLD6}zCUu8=VrrA5HYKcCY8mxVS$|(z`+Disn8DQa8s@~uu8ia;!HKlp1TG!)13o<` zaJ^M8hs$udvZdWK|LIi!tz_7cZe>)l!PLo&i8Zgi4Kk!K0bp_&MzH6qu52gh=`C>S zJ*TM-UvJgvL~s7u6|<%~lG=HlxPk3n7#SoqI%ZG=U{hroLFaWvRyJj&t$TFyKdDg9 zxT!O7QNYePO|{XkupDj4E@#Tf%uutG-`|L7-`2Ke)PLuB{3cc-5^xDa5px?wUH#0= z9TTSFFM?D!ft3_SVi}2HSrOfWJ!(Y;Yg!ps#26}%vkkrCFg`RS%W)zv^Ma)CvLc0q zhCE^AwFTRX@zj*eum1PR6RkpJ?BdFwq2~GQnr!Ht#PX~p@^(jVp7ZW6veNQSH7vRU z?S=52hBGL5haKJTUj1`H{lfnyP>Tkek3Vobc3WFuM1>Y;+HdV(Xc=wrz1G5ZH`a;D zPI+p~o-^deI-w%HU#XDU;yMK?(09dVJCX8z*7n2$D>TS!=D=j8Z^o+2hw z%LXUC^Yd!#_$Z1fvobBxydZKckB(0UMn!}rOs1aPUGv%w^O}Wk76?;iV0g%a>a@srv2S+BAGti%?RrnqU;T?7CC+dhK~0x6iG+ zopy%y$8HB(R%RDhKPR*!<7AY%)KwYRyjidoItx{=6lTAI2e_Svca+Nj zx>NN4!~e^4xPSr3YSe^%?u_f=6r&FHC|d<4Rv=5bkCKvHw)OZmMgkkx@!TkY7h3;a zXi!!TA!{l}W}{^VCCxvnoay{x9sdh$T;rYZd<7lfidN60C}}fF8m_CAG3^_OxVEA1 zq3>^~9Q++h#~YCO-8shFU8B7hZM}g1-&98QTHf;vH?9?>9kw{>?B66J0b!-!k*KKU=S_=cFmpdGEimyItf>Rk5c{|-=k4V zvrwZ*QNv_aWEg{ISRewN$HhPd6PPq!`^=|$-_x|m_dclP%VCv#Q(;t%p-quB1=L)B zPmE64`PAR_c07F4i0EcwFg&jttgNa4+i0E)#sm>Q9nH<8$RT1XbvHf7elL$VwaKE) z(VW1FJj2Lxh*>Dtvi1Os{bnll(>L9R?QT~Ss~je zQ^Yjt%HOhU)w{8M=!8Xl2L#1F*x5JN;a7|8&cN-EeW&EBPVb@b%o@dmj+55Gm`|)~ zRf&;(Or!SK`C{>b51K?Gbe?Ac%ZRF`Fvi&#T>HBg+>-I9ZE*MOHUy(^TU1U`K-oSX zJmb;U?W`xuV(Sx!%js}|EPbTvaIR_mrH9tP}zolA`41crR%9WkItIa`ud1IMIytB z5^XXprvaQ#k&d-o&!Dz5^~@)0K~Mj^p>1}!d~Rqt6XdhLF(Y#P#-3rG!ERl34tA@? z2QTf+U;Oo>m7)K|4OB3W2I#>6^gDwJeh;RNQaXOY{JdC-pGiIQ?v%wJ_Qe}gS)LXp z$?smm%c6vGw6`;Za||tE7B#x_f-dW;)eI%O;yg{@na#boW^VlPu|hh7yzDcww4^_m zl5RaVb6@=q)|2Tt(l34;?lgxlr_kWn)05k<-T$sFexGM<&bg7T=2F9LJx<)5hCgo2 zu&TK#ek1mi|f(ZZ8TjJlQFPrkYz6 zQVls~TiL3&$4d7`j0|lMWgNnzNZN&IXPPDRxK{@7dluuE+BkSUf$$z&F06JQu?4SZ z4_HScS`w%?B+%TDd5^PX-fqL+dC^V}%UD5E^$6e(x9S z9tw6sFuv6~8uO@iUFs&pSs#860p{~B75@7cO@sfxqc@b+gTJqGEciKmAAS$N`vr4< z1{@b$c@U%j!|yH?z5*a>!7@`HnRd}6>ERRQX3QIz8eay;&_ABZ& z*AkOIYG%9zNuzpnycd<%#q@KynH38_5p<6&*mf|42<~@Wd+S8WA6nFIB!VT9SPz6l zi@-IA#>yb?9kT`N`EMZg8^;8EWe69@-R9pE#Pwqa}cP}9l zZ5>26g7fftGPZe?gnU@4;@&mK^ zM0lFr?#`d11UJ7uR`smq5CbV%hYu*7oM`4N2Sf)y)At*9P@QyZNQpo0z*>; znih3i6XoXBS5B%7=WlxiXCi4F9H}P0L)! zE!b8hxaL?Fy+u^czNP<2v#=%?PE-_zW?7nHSdM4o^<5*0B~;hiCvIu{O1)5%iziz* zJ-}~Q6C|DCHB;179d%lZ7PmSx#%%+VSW4ARAJMJnPffz?3RxDuVm3#R4W{=}9Zqy> zDBfUsMLls3^+eV5%#3FW&-;bFMOy=^AhH6lavJ-!JY9R?$zf@BB+qA%LL5-&v<$tS zt$m7#t%H}qc2<+^)dM}V?YRJMZ*iaRuL&Nb9ixH?2Z}!B=37hN zzkvc4S+dD=Yhd7sv-=tZ_uUDr-kDZ`ovdp7iEznk7?BqZfOt7Vdr(xZf^hL&mUZBM zE6rkz%cw}Z#p>WIto3BctyaH2A4vbujSOnX4$Q93G;8hMXLZB}*7INQ4&drmzx>l9 z5HxI*MU?HW>$$t!63D5(B_pi2D*CF0;i>_@ga2=}D)76N{>`dq!9CVeZdpgJ=@cw_ z&(8?Y!d6-J?^MRi1%7VdOP#p(_GZbav3yM8SWck@j+J?l7eoBcGovtL8*x8%^tJy+ zryP%bpo|kt!_Xwan~J#d(3zbb=8dg{9w;*`0E|F$zx;!R|Cbc3*pw7V3@@%>HS!v3 zHhtJK*c1i@`rV@})7z-v?`j~chhj}9sblc>(6Ij>8H`H`|6w+}@28g5mmawp)DPXN zDK-!qC+UhwOSBQjPcMu*mIo zOSYX;RFxIfz`h@D7~Qc2ejlUwK{i7X0jr8KCkT4`|Gi$tJHS&J4#U^)m9J}RQKeT> zTgRn0TR9}gOW$c=>WrZ)0_I0jP+=pPHE7n3Eqzay>1?p+acmPA6cXsUIPll8wPsLrw18~2_k&DsL02unVe13zlO${ zG!kXiL5DZ;fX7#07sdDMq}Mq7&Sy3#cs^D_U);xR7y6hzMRm9Jxy;oH?>;1mGRx3{ zAS#N?(IJ}OlnsF{_h83pHFfxFY2cFDkR|O3)pv3^nzwt;#`_%XcIPesu=eT0bYsd# zgg24a#z;8HQJ&+zs~w|BxOR*t<5(fqe3Hv4U!siLlYmPbitA-5K^n;#>glKEy!_Ip zSb||OJdh0)sH(~_XfUjb3VXHKYA@j z|5uV&Pi_2unCHrSBdWBF&M>^9@VdqcXgfyL#@Q`4P^0cT*k0Zm*;(39{Q*WejuTW3 zb(W5HQy?sB19cnG=j)FjgvaK05n<=L|89(dE(1)rYbu}>U>d4ss1xs2KA*FXtb$vT zK6=_xoyWvCk>GbITs@*>6BGRoN2(jB>#sGRX~@RH_%xN#OaLLl~mBQmGb*o z^Dpmw@lgO@qJHYVd(m%&rvQEnYmk#zpz46u3{liJd~&eE(v-UCa0)!VBVY;3Tu%}S zxH!a*;N@a7b?x5E|2erRJ(RB+x&GrYC?CBO!`n7f>ZX%_&HAfmC>IS{Wm)!?tdysO zjJK;oLXLJAqG%C#jk@b?`Ta*vLfh1w$hIk+)>%{6SV0t(C*B!5-EWA*861yf2AgUj zi@q{S&wdzY=7q2PTU7Q0sloj9^|2k~U%@oaWDUV!RE0xVnP^k6sHnFoxjnhE{_7DB zXy~FSiyDx0TGzuK&=3)ff*7?P?@+dh(o@~`eN_d&-OjU& zNb{1Uhzc+BA=~ZqEs19!MxcJ5s&n1eUXO`*n+q@Uvdjt`M+-79C};tlPXzF?Bpgj{ zr`EJDxN%#J2mzR6USK4SWoVw3LvLKW`*_w_-1X(Am~PrZ-G0rVvmuAEWgca|8MeDaAt%F zz~ceB+hf>0?tCAxtDLB)fDu%VVXwF&wT6H9C8LB^rudDGA5)(_>|E>Wf~QJ}Wn__) zWR?{qfeA4--e)artFgw$-BiYVjZ)rhe_1qTwJ0Fb$bvk8YN{IIQovLzndm_hpHMH2 zJM&9c|A;CbubYfuu$;y!EGmkuz#b&~jCyL=?I(7>i0@8X;CO|RI8Ib#MG0Y4`PRmK zGi;RFFQ_*^0-fGTjc~eDW@(z`Wk%*jE_6eEv?WvTtQo$DFQ|p{->J4mjo3Y`X7C)N zG7Jq&w0oYXSWNePN&Vj8^w?!zKvKxTN7!X}jTHpe&!(8lebe4}=8X**=yv_!IM>%` z@5h?o;1aIupOEoAFDv*YW|P%HDzj(i`&&We{ZLK=I?tG*E^9OzTs`}DP=OcM62df9{PEJN^cj8o=b!gWZWToqD=&yv-eqaw-;cGPJ8Pe-G5(oK$(&K?>obMXgCi5R zz;FgDX#&H_?Ca0ZA7*x)nhfuo+)<0D5Kz>(U#Q#H?(@`rD@FxaQGg~hK+_Dv#3{g# zq*qu!pa)*83b2$E%y2egJ!y|o*XHiuHS0iRJF9G(JPiy*FirmETKh-&r9jAFPFkkT ziB=i=vBJ(7szaAgc0O|ycGS8kR6wf&tBZo70prOBayD@vRxUinP*G#T6*ZQ$9ehjt z<=_jQLZ$0SaS%K}HN5^!M!t&iG^$83xipdqv(NjA?sZqo1>5$z5dqv=32 zXiheSuy%*#wqT3`d|n+}k7QfVY_RIrFCqpdQD~VHcu@kfF5!ZbRBaoK2_k$tT2PW6 zh5x16s^7SK$=p4#veSd@ZBkwHu`bE=hNq!t+NzJO9E|_L(4{>ku5?kSrPG;ae5kprPhN9^VW739d;zCy>V@)HqZBuW$quZp%B02G^EHHJQW>ifK zQL8E;7^R>}F{)LyZ4Vyt+_%kmNoP&3BuF}z8)UU9460~2QYNLnx@zL*p%BdTlb_HJ)_+ue~b4pLN8 zF(g&iRFy+VIs=<`16%slbE&Itfy&c#yz-Wao8s*m&Yl2#VTRN zD>0Upgh|HvoG7Pq@ix-Nw)Cs)e=Pkt7ArIWv??nytqKxAtQejayj;D?KxQE>Xd52~kEilVuewcOOi zmNtLNy0s5P4A&;9lA?$-uLD}d2??1o7L4D7YijdK?_XA92i~skzon07ct#NuB3Yn$ zSypJC6-9*)3FiOi^MQPAw(zvt#x{FTzhBl}2ibK~9J}`T>@rXdR^(XGl=Wpl9-Vs{ z9In=sxUhgcNBoW=+S#@qOKp7n?{&k-sMfu7sw4r)5Cm0G=;Uo39`K7}P^`W@Ju)VU z$j@O#+Sx7}>u&tddMKjigkwg2#f(=p9x!r1OMG+iH*J5uY-SZ$o60d_0+Ysb<4(3~ z?6-EK?{GL}PGRg$zdLE* zX1aks;2Aa*c+UDUj>u8-z@F0`zZ}!?kPR0VqUImJ-%M7D^WUKT^_1}e*O=Q`u7&pdP<2fZHABiNDV!_Ie7JkJiz|Mp=89Si>r@bWs6<>`kX%BG0d;}3 zv!WhCD=D9YcTmHXds&XJcs)t)nm*j)^!Ny zBi|@aK1G(W`~)Q6VuH3*(OfvIbf+ZSY!pS11m%a2_tAqDsGDQ7>$k`#X&y43hQ~L?byma!(TXp_l00skr!!+=NN@m zxR9%xKR{Fzw2Miix9#99_WJGCL(eE|j6Z=H*!xIiA8COxbcSI}ffK|tXU+^;xO#XpB+tLn zf-zdgK-)7fKY6m?ZtM|vMG^#-DC{Oo>km?Zo4%np#S92sFPxl?cRQ$8@Al$ z_y)PPN%kDoJ8YWEE}4MiXkKDil|h}q+ehuZVYWYnJ>X9pjV~)SN`T940RNE??=Y9M zU_?Q#=60ebr$s4wnC;A-Klr!J2BF-i*q|{$pk+?wM4&K#eAOV|@0tXejtjxD5)4U< zu)Ub|>HP!n5fFJnR(Ot6Xqr)YA>=x+E!zV)cNVUMQMRx1UsSJbgJs_wFG;K@vOF(x zv?PR_;yM0OfPFlTb!;7H+q$9O@NKU(Ll!q=cN9zoo&vid^O7v9KooU(;qq^{+`nsU zDlUd%9|Yt6j~8&?^(-TX&@+s2F8sdUc-w}{``vhghKtQ!EX^~#eW>c{?KXgs<#&>` zJ6wJI{t)@PFW=*EWsg)n*}ymXfz7Y)`ue77a68q8Eax^1CSrU}#Q40dS?hS)E7$ES z7?ct5u%4oGsv^s}3{(LQCT+MQd_*KIRHYF3bM}&#}i&t@?)Fe=d(&lFR?<+7{~MKIQwntMXt({gxj|9 z7u(IvB-mkL507%R|MFAdarFl-;Bn{!U0$E+(t&MZqet%S=d?kxMbG0`L)ddQ%zH$P z|Kr{#qI`F**gYAgKKOtHdA3{TkD51T8sv{TVPq^;knE;I10E;vdV6{cTzbEJm+te& z^m~;UcFoGeViI(FtcqX==$*k;;-;5;8`pnc|7X8T4V8_2hFxl<*Z!usT@1pUR>qqckQPn}Z6%rI78l2c_=-o|s}6j1dX zGnr`Zswln?-^WNl7g~KURJzH!#K)n$73B*(e-tK`^8eE@zIUPZ&k^F%hKknyQwY8N zX5qsKAA#vp2wj>~@c%WDb@ntuUo;hrPsK=o6JvZ{+If>y#^0ST+b0{&tVgmfJ z=o@TDZNFu?_O*kQ8b;gU><(|=>3JUD^*Y?HF%DmjfB&yAd{Ice^eq`dI8?!yYirw~ z%BPR~3l)s_iEs*rq4>|_o1$tk>a+(z-P`A#s9Xm#aZ0+o676|e?Y0!P{YIPfyB4#( zRiHvzEO?K{AKPEF=c+zEr~7L+zJ2$AQ)##>uu#b>B}R!X+Lc;Go5MHT?(DYU=&w&e zJvi)fZq|QmjDLrrkI$Qx@A5fv!3c-ubhxsgtkGkYUk`@v=01CX05^>b;A5{_W4}BY z?_5&49=_RDw_3w_HIGJ)FC+nzQ8h#4d4--(gL|WHu?V|&#ypm{+t$BYfAOyQF`Qba zC63hvlc9A98w4UViWHj}qm-K&r!<^dM$$9R)IXw}x!dTNx!q#hl4-MvMKvzR)3jya zVK{phFoDOvkv7KT@ByzKOwaTDYp!qh<%&a9Ayq$MU2uHwWA)0UDQG@L({ZWo>Vk<+ zNmNv4DTcH6^!kRn4Peg(KKpb|wdbiGH5d4R$BQ~kZS0mB6Rj_`J=`oWd(1nL536c2 zC+Zw;YNm?rj>&^?ljvUCeEI(RD>p#1ryS1gDY5}CtlnyVc8<@#{J71L!0Q{aqZIyRl=j~7FKG! zC7BBo#re?TU>sV+W46BCSDA;l!6J$~85YIX05YSJ2m+V|yl0}v0Y_0M%9o7k0$)d!y-rI>n>CiV z_in$x;SboOh#^^?Bzck~If|gUFonsF>Ed()riwKd=V!A%0!yP(FEXH6z$-G(vSF?^ zeox2wEqvK>gJoXo56?w$*)FgmB{Dq2ay%h~wY{evA95JhZ{a4(qd&EJFYh4qVIS2M z4n-3z!HXnMkWNJ=E>?FqyDRBXOEGP>3|YHw*2wYAqVsT?%N?*iAZ1l#XkOuDO6ZvO zvgL(suckw0;;k;_Yjkd~45Aj5Oaf~QT3e5Moy3)HF8!;6nP`@Ff{RH%R43Db#Am=sdAS0c|TgYRI9J}fK0Bp}&mL~qs`<z?s$sqc2v&;iv7Emx!$XYldMhWO$JXgiN6*o+2qWOfXRAzhY8m{x(a*8n#yrX9zV3NNGWU~yXw1D>aJ5_VW}8r(hV??VxMbq13qE_KpCpHriF zngc+QWtMn%!O+gb`y4T&3wweVnnHIAXlk@DcUZnTJ?Dxq_S8eZ3!$Y2z)A`Y0u;5{ zWHS5Hfst)Xc9hQ=y7PxPB4dK4*s!mjQKY&_Jne^|T%`XU*f}YqAV5Oi8pe%kB?XG^oA{N>v_-t&>j&+}@LfW&6hpE= z7A1`(r_X!;jZJrFqN37&hKVz|`f1&vY}L1tKy!d>b$F_3RHiBbO5 zBu+V5lLX1tKE%kY-m73a7FsXqim5#H(*HzNK%6@=V3p4jlt{=OQvT^3pnf1t`F4RWr$s`N{^pOp zMWLs_x0c55b(*(FiV$O~lq%C$nNxUDCRDN{Sd3GBhHqDG(+PWOI?~nh>K0jIZv1za z_B$5c_|m*6(QP@3WJQ|hc$y%&FeeAMr$&~xl#(MyEsrp^zq*crDM>4|> zNbr2%)&h|4&n{Hlple*2-r7G*pG z${NewVjzGj@ApPd&rIcPKOFMkEiE#i7oNNk9zTzTM>q(M?5HRzFEM~2C7yXkuxW>8 zeqbGVkx+}53S2IM7tCc`(q_{imVUJkPMWngx(gDZiGU=4q$)hhybi(^eabQ~FXiiT zPuB<+%IQVBJTAYJ=IJfj+v{vRzAO#y&^_kRwCqRoY0I!-H~jL`qE<$<1jz}`Y$?xQ z-~&C~-ic0^n%~FMX>DHC@B!UQ%4?ycqB|1El!Q{z7VG;pxv$elMR(+*@tVM~45i88 zq3O?@#T^)_*6Ry5E==zjolFr4mX}yYQUFP#WJ-H2wsB9jUc0H4?Y}#s_kxf(MUzE^ zqxdk@-ANW)FVd}Ftvc7S*%rK~GoA|&{VXp~BF_pe%4a-WHG1RIt)4$}>5LYP(UPHA zrr1qo_d<`9>r%SA^78^_6h+}}yGc2{rF^dI*uSXWgR8+K3iaEZ87Cg@g-E``7ko8q z|AFg%xXs)!s$fbKWtx%+k<f+{&y|H7P|EKm)_8mgQCBL;Iz5Qr49p z{_*-VQY`9fKnMie4n!PeiHliX%~WYR*o<{|$IVOIZG$+acZAShBuO}3`Q2SU;3-xh znql4gcas|Rtv&RQj+U_*>x{QV2&= zVta2%X6dF3ocMJEQ1mzSJv15tny*>Te2w#*&njoWdIjf`pzKqlH;Eo|H>YJvq`XCrEd7U>V}R+vR#%Wor8hm^{Ii|fFda` z$alK(i|xyEo~ypiWUF0*m|xdt@Nmu0)Ch1I5&r)3bMx1q-O#Y4;a#o0$gew}yaRjf zuQHm#s3I+joQ7We$0`df6|#4?a{gQX{%IU!x$8!Y^}$Gl#AzJE35vLRz|0>$Uih#B zwtNY)w&#}fhH*&+Me@74W@5g>sR(qpE}B;L?MFUt99=*eQ1BH5j?x5@V+e^_Td&9D zf9dwtMo6{2(h}Q!qw?adudhxL3@f9Q2>lL!Vb;T%nsvnsfWsONQ54OJlpxR|MUZ4z z*s}B&ip%>LEAa1aExh5(7b)*Him>%cwDK5LG!qBu#k;>C28@;*d?h*~f8_T%aO7TEntI}ZQ z_6=L2Um0qo%CaOc0zzeS#xBUH|M$N(cz@^CHHXI63{BCx`dV*)`NtRce-phXiD!9< zRvCfOc=U4equH_cs-HD$*pQBSQ?SUCS9y-01xh1G4n?N%UQYD04rt!ovYm+<(}o}< znqx!?&_4d-}=^1IiK$B3diy#TcoihfX35;sLG-wymMy4m}y%U zlqeM@Aqh!Hf>Hcc-21V9SJ^Jk%;)+0cmYTE^tbl-?Em_t-H$!NI9g-`N#j|931bI7 zVN+u2OerZc*!oDVcb{3tUKLJcMbdl}WJXqGhG2P7>foX&)LHA-7NZk-h;`4Cyd{Ey6745_-Yk&b17BS=ODBFU&~L6Z@y*6q2M!SD-}88j@Jup~*~M44a|S}rx4nZ2O(8|jUID^WbOnM2bP`g5F8whfu* z;mCZVlFvVpJgT~E!Qw~F`uW5*vyYsO%7t*0$a6fcDwIe>KFJ0^kwKrYR40Y{}?pC70&Ce4x+@0hOKdviuTq(__L%;R9wc|I9~BJEk%pKAWV z@Kq33O^S%CSb<^)j+X(?)3x4pj1G2F+{PR#r>bX;oR+_>UMsM4pO^J+3}8eZWH>wBL*(_rHrb?{=GB4-tH;Q%QYpdy?lS+TChd#tB_x%J~klOyOMyH%f4 zU;`fQfzKtmUAKWi;Bu6lXoYosILpcp?J%ld9yA%K9?>^6TkIRUw=3UYq;odN=gk8? zf1&5;)AMg)nx>!|<_XXBO0f&K zJeLtL4~Mi#GZT)h9(*U^1GsgeK`juBXbCA?Ep(ujI**EA81GJogTh+@2GWQCPJJo~wS|HMaOphQ}vSdkDoMr4FAr%_!Dokp#;zV`6L zPw)K>c6)5(A*Mx6qBWk83FRbP@I%0a7V13ZA(LZG5b`pcUb3D&T({fKba`1{0rc+EkXloi0K1TCm+t6euu`E6D05;5VsF*;%>t!|68 zpi1BIN1lr=>{10DP`pN~437%C;`RAZdTIE&)&2V8pC9gzx6I}kh7>54paZ_7sW6%A zANLnaWp2A8HDVR7TRZ*wLW|pTn&L&EKA<=!x>WyICo73O2Siy@By#Xe14camKwC!x z{X6KW9HxWJp(_jh9ZgN9vi*)euRM-on>BN8$J@3(YG4#j6MUPF`>yycXg#d7lvQH= zmbKxzMx+1U86DxttSD#H!VBshuU zZm($>d&`RxQXheP^CIO#UM!>3rGdekLjyl#RB%6_NP3@vA1U;NGV)jRF5;J@T_a5W z7;1S`g8GLWzdA{dCkf>^e^N|4t#gHI3r0O1l`J7SQqX8YTO6ot?;VIDzZXH)Z6G|kcMOZ_pOdiw>Ld)s}W8N1s}L1C!pF{xC6Je z><_HIxuZV#dV6%PMWul#^Q5MzY#7%vcZE5|L;Pdwa^`T0aXaz4+N4NI48seYq?P}c zdzZCtlVdH8Js4G>Ku9dd@**RsQkZ|EhMUcpCHT4Z!ynq-)n{u%JULPnb5`+s6v;m@ z5BMaHI&{@XM_O%4O+y`bQuRaAvhIw}tvy<=s3$%aRXd#ygu#;pS)nNo)lN6E^$Z{4 zJ=QMQOtBvR1_~&G+`u>&*~y)cp8$P(|>QQrw(ib_F6mj zJwBo8_gUe64&E9Jp=5(b!9F@$HjbAY`od}%Kg=;98_$w3B*l|F$r3a#FnpMf-6JiF z>l#uASH+js|LV1PKeqw&ReEpuvWnm>S9Rr&(>1lKHvZ7uDfitB=!*=!gNFkN=W9wi zk+KClS_iCST0Z*6xJ<}j?KedfxfNTT34$tfBqhrtPfQutc?SE%@N`t?Gh^eQmf#e9 zo+#MzaQWWHdwo7=J^taFzwEoA1ztjsOFLcp1Lbi*@#}XmgCxHn_&g|Lzjj8QkQAMO zgVx8YcAYtCO2a61k)+_v_e;w7qWEy#ypvFY#1UPoZ36c6IAooB4h?T=boF<*p~4Glm+-a7b1}9s8A4hVz~E+sv^qJXxzw_(>hm@}fB+Sk3D| zodb3Ls&cr5H2I@e%V*yI9O|2d} z746cDsQn+U|IGj5%hzs;as-8VqvRA7P^?C10;Qqk%sfMJ^-tDwbE_O~vlyNZXCfRz z6weg-SoM0`g+-?MLksi3)xGP#v2R~b8@vf9^b{|;k8F{#PpnufQK7;sj<@~U`uXic z?|F1Ji)Y95abrbiKX;E@SAaYyB0#0wz|g6Kf!57C=_bit0MKAzf3}RR89!TJQKz0h zH>ElLnkB?JI?HN2NpK1+seg88_33-{`k5gme>O&A^H|>t3Z7uy@Z-vBYPyNCj8u2Y zFLe#rssJB4NSQIW;H33bv%CL2`7&NFoFNHPBzRGvDVAqBbO-gRKhG`s zN$%uNoj$nxAHGDWGfO{6d+85y%|<)@AM3%_=Ntz=z@eHJu`k62Rhr1MfMY0Gm8Bws zs+z4%bX<1UQ9?e~jd382qBPbpK%{V?{$tI1{@Xs5o-r7M0ag)7AZZjW3lWXMNbCmt z*E(Wkx^w1%tMO76T=1A4`HGYWh5-MwJ8u3k5E~Mf3gakG)Kf$h7^bz8iW!O0R-Uuo z)s|}Oe-)1gNQNePf}|Oa6DXcU(ZFzhB(BC*VYAiz`KZTU5LM#IGYl<|oWuZ*K_#AV zv@cE<>fLRrPy7mNXg<7ZyY2QqKd<}aR;roq*Y zcP$CN@@vFhA##8q36Y^yNgI2v&9}Qhnqe)Y@GRzl(eZwtp5XdQF-My1_QMO;pWfCu zd`e2mDwcBkfiKtPk^ErDM3-L~d+dd-JI(}=)UB-XRh(w~{9e_0_qgcDm(nAso7`}O*n;U#8uB#n1etJqHO7Csnn zjVe0@8pRPBC6Fv7qO|x%{l4q7^w8_C&(d*AJ;S!@tbg29%i!jSyfsQfR27D*wvYZjGx!s5MHDe1MNv+*(9_rD zQO}(_H*nUvSMj=?B$L)+%%AAi&o608n)S%{V$1U zn?=1TVw|r0Vn)BG<{AucEpYijZs)=S85^IlrpCzBTH|h8OwT;Uu+Ys}s)P32GJh*;UKddI@{e%q=BO`yv_SiGsw_ojx+ z`BiPalTNAD&RQem_mZ1~t5QQ#2+I-iJ?c^5Ere})6UigCswPyor2&#hRY~hbz>L9g z1(HV@XH*KAXm6es?On4PhT9ojJ!5YErjC0`#rd^urWt!~?)zYSIOFvqNFF$%*wS-| zU-G+@p1`k+&GzQzNde(dV80U6|2VwICueXv22a^vvCH?neP&Y8Aqh#i z?4k6^xT!5eXgla5zkw2vNC^}WWgtlaRRY2XNxI5*z_b1lcMiPd!kD>I9BK^J#!&CQ zwe2z2J8O4UgDO*x;T=FJG!G;dFcQJ?yY_A!vf#f}ne8v}`CWa1wgVS|&1`C8Q}?*W z)U1a$#v}!fW;vQ-2$rFRFx~41?kX-g>uTJZX=`&x1DYCe~&l5_Z+;N7DDPRvZV3_B3j8R06fJpsQJ{rj>u_vO&x3t@}}JNf3HIO zjNy@b7>J)GDiq050uN1NP{Ww4TA^t#L@y|-7Jgns6_QBX^2fFIBfDeug%nznWR~Ly zRaQ}T)BSOxvlJ6;OFj78l}&GemJSj8mjzoo0D&b$6#z-0*}R^vjDUp_90N-keI3y@ zf46E+3F{0jm`UcF17F-7+}l_Uu}bHgx4q$gde4-0v0DF#GRM*s&`3@ZQQOeT?Tl&@ zZQ}<`P;1X@jz21LNs@MgT$jJdRe4uAA9(yjLB1b7Ge%(5ldrLzesW>moPXdZ9TaH^ zlPWDL6s_Jq{4{NST z8w4~m1D^M53G;rLwTQ}u%05sDCSGNjL@Upf?v8G@5r_U5+Ub#~o;X;VBQ=?jDNzjb z#BtAZ3#RC7TkYv9ZhibPG^1%9L5rFroUZ(AACUY&*RAZ68;EejFRk{n>z)NaWIzYz z)i7yFgr#W;asX~aez#%XN5PCq(ekaB=O)bWM)f2iUKG&X_VR+!XR1FQ%^xAhGJ-$| z1jRC37`>TcP(^p!%&BDW``1E^!FiEROObWvx+eYRI9GS#@$DH0#TpUwWlr6hzW_5s|c@(Il^ufMx;Ht+Dm4fM3pZq%2%o-Zu8I{oClPdsqKJ;fWC# zESz=@@%vn!oIV~EOzP$>@TmC#KR)?>UxDKH`cTw_C**tDmdmr7v|k2kfO(s!=hVvT2-U-t*`C651Y;((LNf>Mll*MiK<4@GK;coxtWpE@S29$PCCEX z@=q@G5VSMgZGA4oiB4aE$M4DoFa%4HWqlEmJ-p4nlS@6{XBJctQZSm_-j#&9Ki04I z9SJJ$N6hnK2H!a`Dh4ki`M)zl*~m4BZN*Re8E@9jW&g%Z;JZlve!bjD`jVR7Bfjki z(Hm-?{{&LZXgzJI8=cL5yg2=SRdL!+4=Pg{+#elPbfO`Ahu4Cob zkn&Df4^1yzQS42&{YU1c|C<{P>Cg->uq**Mk`qy+V?=zG)->F9O`AcMH|Eq2mlFjW zG9phfibgXG2y?f2eT=MSDHEXB8q645?Ya-}eh>(eASjk#1eT+CkwJInB1>fM z7FMCysyAKq&1)i_2cvmP;5mY3S&A3=umA&o-7NGN*568wjqZ8$ny((i_km>zLZCQ? zV_1TwX|#&Q`uW9T`jBIzw|@Lz4R3UJs~ky4s=|vrDTTRPZ5uNx@Z0{Wabt~9M_Y!^ ze~2#yf>J1f6&Z~xHjs7sfa0J3zrn|T`ui?3od4dIcrnpL+e^-Qb)3=Nkt(uCDU1Ll zLJM<8n*BmCUinc+FSBkph2+DloMdaVWzGHKu_)qv-KJS^4$bF>fc*S`*v=0o`F}rH zzaStIhKtWR(j1b;-tR(N)9NS2S_o+IJ1H{Tr@7n#e?+7p^MDgXP33rt>EUy0w!NAT ziTfKGm+w?4@As7jkM^saa`D%Rx7oHfeN_GT-x$RAq{2%gM@l@SF*x!4I|=T{JLUWx zg{nwuD&zOY%9^L%an(rRXAHXnvi#zm1U?!GhcLR@3DLrDHnN_SsuGPG|R+?{6qc zRWw3iRVB>p;m@u%PEFq@37b0%|~LI75w6pcb<^fj=k;cnZaM;~8Qy)`_a zsv88<3AnOTI8G8-fq1U)_bX<5O}9_L)m5cTcRq1rQ3Ok+RHFyo?H5OmW9InPr>(&BwPad==uZB`HyH7axc^ zNvVoJ19r~_VcE*v$4j(nl8}V*K#zp)rP;QW49);aYoG6eSLy9U(i0EFbQ8nJ` z=GdBU=&|wK+6a+F1K#OLo(uL)@5}-I7St#611{szkOrENd>72`%`nfy+xCF1pw*5Q z?pD!t97REvNLm0i!9>(?tc#?k2<&k5c06o*>EOKnXFiA?pc#-N1z3?Lfr64@GZ4XR zY0;0{yh}Q_%Xlt&@KjRPG{9**M=K<%kGjCH`AcnIojTZMN5`o0NReg4&`k!Vgk_iHN~_G!mv20^$b%Il8}fK_&M7RokzS`uNm~E zdMq3#mju@#RfVJ|4Nx3Qzd7PJ@2`{QRzrO$R&?+iQ-aEmHHePcwA|KeVaCZTpNxJW zDuhVWJRxfwj~j zcz@;SkE)@f_{oE#k0EXeT1@L~{j^!B-xx&10F0vWj6kb^4wH@H)PC04zS&i$=_|*g z-&6-I-!y^aD1jjkSyMh>f)tF7Rf}z9tg}@mR%Gqy2QMxNGrEmJd^YC+pTE$_Faw@{ zvh}CcXH|iO^wU`e@<=3ox;kbA%$F)gf7Ry8`Dpr^pm~%POfsZ17kC0{qxs!)d{XWZ zuQDF^h1LZo8VFg2O{rXr>8abv>v7&2n{g(fvE$TyLy;@G^ii}a-yIfW<#Wy-nQj9 z#`RwNKfE#_MGFEi@)W~xEJub}b;q29cHU;=P=ohZ5d{IS8`Q^CqI zH7ucN>@C<~yME~MJ2$kbkEbC5hNTKe5CW-bf(kkv|97tZ)g9^G6U2m~-?d6GlWSCd ztdTBLFyF)HoshFUR%Ib8f`wpy2$JuFyf*|919nI1?}D7j?ZW0h^!qLbw7WTBtNtU~ zj>TzYn}K*0VTxu+k!J#0!U9W#(G0KrR*Y&#rI357|W#4eb!+@aehrfX!@LxVjG5_BXli?QXwAQYuIpbKFEHMT+b0ocM6wqAh9AZutFE2yOCv zd{gyV%&tie*>0VDz;-aYvmJ^fNmf!hnp4z>&USuj9X$=N_iNj%4TZxq=0}%uNFvAZ zgd($oq@nuw)|fHJH?{|UZRQ=l2G4Eq6em)GAdsTS(`=aO(zmx3|EE^PRq?HDevJp8 zcBSnf3NrEQBs#x%9@s#3(J z{j~o8e4}n=I6X$c2G@BjzJQVkc7({O4+O5Z6Ei&dE24YP}H&998uK4(mc%)s>TDZ>s&{6K*NG8 zk+_8d%JLr6Q+SosHpcI4F@9%@@jLh&N)58ip?UZ_qo+NQa?pAh%G2ghbxk>AVeg3_GuvHH{I8u9L#`(H3nnNnGXr#Y6?R0)+=rC`fGV|%+>^XvXT z)EqBO3KsE*6s<4>rLepT!W_lcG3v-)wx;(TTK9w8D!e05WUA}*(4_N*{65MMmmlOq z1ADYneX;e}?7gNBQm4#|=4eU@xW6PNiU96;hf)FW^ z2uMf;j-=2*d)QFkSJnR6&9B}4%lk2SdeB%w5dvaMk!Nw99KfYTW{v)h8x5CZq&swm;{qae;PVWXWH%UEmehL$_wm>uGKRu< zOWfG7vHk0xt*<=rObkv+fxy#}#&IM`sW>O4^(*M8s~_j@Wo-xQ`MKO|s43R{)6A~) z`PezAdCC5B%!v$5Ymz1^bFLeCa?#i0%Iq&!_i4 zZ{)kQ3zW3J&~F$XO;7{JU7#JEjkK#t(43@4oUhjQPA$jJZF~p*5{qFeR-|Z#;CNo3 z!#v1U+of|9*qAEq><`R%<+^L%hWIqdkQA@XP7&V^?6Wjry@6ZnGa92RG$8>%lakr{p(FT|s}XmdtbN`4b+qrAHo=qJx~?}vItNec1w2l- zBm*}}qkf3JD89!2y7=y#=WdHm)bj)*(3-?c63L)t_ox-Q>=e^=_In@nc3Qj`mVGQ@ z*`&y+Dnn@`CC~$AkNkNwlah{_K=n4*Nvrf}USTlZN{l=5h6L^0;8QCY$zNx`@ycUY zo-#-A$jA{CMG_P(1|psi=zi)tv6zBsaxG40rL$eyFzMfGzJX2*Bgg-cR4LEzv^V~ICo#?pitfR!IX_GSa7YRpV|LK=j-D|CDj%T!k89YW(M2-3qgZGb3uaybcTD_*RR+()lH@xZ=Zh<&zco_OEil#(U?3V29bv7PfmIg8T z=Q??^$6UT{r4n|3|2f-{Le+ixk1pBFhCLxP)!-3Az^JF>DN{-uA1Pr!U%b zb#&aV5TeGA97QQYm}7z7SbzCL?XBi;o(2q zyq^h=@$MMfwz~lh4S(-mK}wRfE2&((>&%<&qcZwrKlORtaDvB|qi8+=oIZ{RK<0rU ztE`O1j>Dxmp>JyhH{)XFq?jao8aZP3iw{PTNaT_v@5~=7<$Ea;$@a&0j`A{Iyy}}skUT4pgh=xY5w^9V!-$&L z8Wj7nwfDdCd~TGOHk2R`1TPR`z?piOv*QC>iqo}Nf!5BD%|#s_rH=eyg%IGb))QXmEuH=Re3>Gq)j(W?zn5=!;XdtqOcQ9 zu_wCRXlCu9J380CwmtPgM+2yYV*`HwIlybO2n3~3vk%svn0C|>=1hjd zw2CTYZ({r|r;KtO^gBF3=&{%B&}F{+V2yAAUNFJIQhb|^`>qJEQ4m2vLSs+dj=%Ek z@BHZ+-B-YFT!s``fhIYM+&aV0X0baGpxs-Df zEjeYkR~i55&Gl9`s&bh6=QcO`=8cKs{;p&g~`S}trCc1tj|14(A^AyZ`7mEURtn;0Oivxt9xpPF|5^(c9 z(awE&a!2)F>xG}>rL-y#X;L6XQjlf#-e*>Se=_JmuhOo#s6G!C=bzNM>v0*O`EZHB zRQu-1rv`bqM{rG7imMq0C?pFAj-=?CtxhtR}D; zN3$};MKrfsx!)W$4e#ik_K^#}f8xE4O`@=5w9}Q}v%sSST#y9rIs<27&e#R3vx5kj zHb{!rbf-OI*i_$^TdRj3yTMc$vuNboa^s-Wb*e2oO$N)inr7MuA36GYdb_Lfa!FmJ zO$*MUJ^*^;y8MBFAKnSTr~UuIba`@~Te|h1fD1`@Jv-enq7uBeWHsA!3qEz({$n$Cyw6#k+`bVdB&mVgk zYQ6}Oc|IRd3l!iKC7vfpl_37u zJf~MsfaaAi|Ga)$r!!`_puf!vO(mr3k}2}@cn>AB=}~*u3v;(^_rSYKjK@sP!{sJk9bb5qLY2h94gb?aO9gy>-hSF(|i@tU&Ss>tzuTIOVos6*R=d;{3g=?P!Rk z<%NbZVz7nwE!Wp>eb0hMcoBV3-1Uh81MY#Eeqv2_-f%_AJ0l%%@>(IO3G*Ch0&nzP ztnZ&M2=ZiZ-&HqzeYasv!+DP&hwu!?^BO0}6vyIXymqM`nwm_J^LX+1)Amn?|N2oY z4r29b)o@6gVVwN})(61n1i3E%U?3@D1L~|zo>Gp@9ag2<6EVtLU{!m~q4~1HqwPXd z6M~gWD6e+W@$6}XSZ^cSRn9U&>uDC}_vrY>+x})Tjz?J`-u_fnJ0Lt{2~88#AF5XL z_nVayjU*bZ2Kx)w-|{Lj%xM>S+^WPl&asMl|EJU6Z5{FLZ`}KB9p&5CXuEKL)7FFp z`(ATw?dz&VFaP7(6|=8mg|3zCcrwxTJ(M6#o?&JD{rL*I@8}>`?EA68-pk}Zr=t6L zzQ@t1e)RXf$$Pvclmj3=VMXW_+_Hj_=kJi`kEN7;6Dpk!@=qS5^No7LO|wL<2LgI$ zgWkbZHOOZgK%qI**+2qzLunhi_1ucb1L54yaGSyFBJ|Q>+?=r zv~WcCS3F;5R@GMP;YwecPJnPnspU^^zi6WdBTWbpgS@fRmShOQ4ISn+L2 z)B^^>U5jHYuSGfA+uIQtF)9cqJ$Osx@>ZoLX8aXv#m_9y@BT*e!Iwp;Aq3|O_P6i3s!EsDFv!DW;Z$HQ#Rg0ZCJk|W{n_3EkN=@TAD`NE z-IE!Ro!Mo8bdKS#wMN{sHePn#co&rYM0|-+1-PGjzjdRapJgZHp^rNqDEl_B-yq&*N+teBbE1 zL5&mBzXMqnyQN_HXn%0J4KLc=o9fphZfX(ENrkdG9?9qPPIQtgscIAuC504G+rwH0 zd_s!pCHu|uI{Yx@G~|pviD=@Xu!^Ygk|$2+pg(l{0qcyprE=N2xp0SM7!So-b&g3EOsWskb$_5&_F3JEVR%X49l|wO|v}D@T|zA>-TqS zH-a!;JxPlkG@O>mw9e10bhSdnE}UXf|~vEwJEp9RONHMz*J#DkW~!9pAD zM_-whz40jA5pP6vEKN!bPs$94@0$2^`%*&uWT6Lk z^GHN~jsYAaNPyQkS{w)_SLgqlY1x=0iIR|nBwS(uW2e82d2T{}w_%=}48Avd|9qXZ zX45u%?gJ~X)T*=&;!{i!ef;x;v!}}=xqG^RTg7_$H)Csh%YMz-oK8QzLgBf)a7&J& zcoG8&a%JEf;+Om`CBQMDE^8+J5L<6kOxx}Ch20;YQ{V~M#2V=Y6lI>5NkyaxMP2ky zN7uq%He}vZK{HWV${@eGqW^BaM0PYP-G=?5Drh`^bA{IPH%9c(?>vvoaC7L50xJEV zh%CfhBtHvzAB}I{8Ofu(Yy%`;*C3B-AJ#I+qtYc*o35Hc9@Q>P#|RP@efCqQuI~(J z4Ci~h{nvLhM|-!_3&)>95xg~0;s}mWXa&R`>t%;sIhDC2)f~l)b%NwB0M3A~MoN=e zRhB7Q3G-$0Jz;bR?6g1GX3@_}Zh&ZUcw~{2Lh=H`YBZw=1Gqn*d9PkSGaQyCy6NR; zU3aUeeo{h}44C3{QA*qLo_))&SChhMXpQoc4RcJ8oZ!rs^85up(9`Xm==Azj-~;MV z^|prwoV&W-E&pV`k|c1FkOY%gPsbxE3T@1xzvt_z1xfp0q)bMR&5Rtpm6b;77NgXw zF_LyeQlolWRkD=rV!u^0S{J2A|9yMQd%v_#SXrXJ9l?N~6h+;zTk-nTelCA8BT_$m zz4e}y-PNv%vr*TTQDTRFj}i($>axnYNIKdSIqi+4I2euOdspz}-CIe)2GQ{`W?4V5 zkDA%J#e$8{kx8&{xcHXIM*&%*8G%qJf%W$^&gD;-gtob+HY!d>WHr`yfzH-Yg6iP zf~FNlR7G9@tN^7CsIT`z?zcVQ-sgm6kXe2qLF3 zxZ9?bnDN(PyRvfbTRV?Lb#q5jD#LR$M`|jAy1844Oyx?8QI%iY_wStjsCQv=JcAc( z9;GOn%CjUdD~d4o+f(O)IlW%xlvtHE>RbE9QBxi|GCNw>PnM)4K~rRfVQSbLh2@mX=&UE! z?>>p~ccb@)V4Og-j`KS_?*86Bb;q4gjUNO%R=s&R=|&4&u_Skh-{ccksmLFba9Kk4IGHLk5yF$LKlN`CdHs% zIF$`t{Y-+-ovO(9sYqI0{+z+A*9+}DbtJf-ghBhu+pkNF&PdWtl>?S!dy~GPQTPkhlV;@{pdBKzZ<=uD0uvevb`Vc zclG0>(LYKlTe&!&fGMVv_U#iMt(jqi13D($pLf7-5(QXUVpNW$z*T3b-h1`eS=Qb9 z7tr_rPxFh@EqdJ@8;34J244tf6dM7rg~@&GC`ZM*dCWz2=RVd`GPS%Njtr zf3?a*AERU3OYiCPvN}00l>!@Lj9Jy|SmfsvB7f=9Kk|F%??jj1%om@nfCIUY zhTl63?y2uxTm0Tvx^L@Vy5fF&y&)_02=y6ybAHs7QlT2}bNYg{>Y)qZvZ$(?z@52K z|6Rv#X?i*E`H#Aee0RN^cdiR<-#k6NAIU@5Vvd~mWBQFg@2qbKqva*)X`U&u-=8m7 zj##k=hqfug3r~mUUtJoSzY;+lgOH8!0x~a4ko+S^-izdWA$bHeE!10Kmo1^z*n=?31_ge3LG`U924c60@2zEGNEy*zk64%F$;&oJ#@hoCPQajTgnl&&3+9$H@- zg6Hqk({V_7HUwM4@2^6>pM!i?)c`xA{kT}iA9o$JM^DrBMSO!fln;UPg4zkgZh9}$ z`K{>jcswPP7CNDmfzTe?=yymp&Kg>rZq-rB3_ZU-GxRykH`hDn)%l}E=IGB?>M0C~ z_bP_2f^(Pz`% z4PV)zb?KI^#p%n4!u#)f4e#n{Qynq9g|zvt%QRRop53uH`b_)yUCZwJcy=e?5|LpE znI%a=Qw5Z@Iouex4s4D=`-Zicv9~@VMhGpN;)HRvpaZORrxRY=@2t>d}1ZcvN*XX*=WQc`L8N*X5PR zIW?a*w};2?bAfy(sjw2m(~3Zn;ukMIzsWT+-vKLbgSe|e{Q#6!oaMN+Wv4OMJ_NT> zm-b;5=dv_aY^2?-z~%P4JpH|Dfg1#jv?pXg*?;rySJIXtT6RXkk(hEWTJ+R`)$hc- zk3Po<#lJCyo)VvLQw-LB5|U66@Gd6bQ%_-B=Y|O0 zh3gqo)zuJupMsQUDI*b(gd`*q4{t}-XA1JXgz3Q0F%|=EItht|E0aSI5g`73J&0K{ zMYy{$A$Z$poZ&j(Vjv|!zqt za)~6N0@ovy(Z=hH40leaCZ{3^7XfrIM?Mb{1+6ZSexk;?j>~-B(et!sCC`H+x%HCc zkc7(~F1I^wR7?BO1eZTqPwQ4NzJlfFBWbLB8vMR(g4y4+uxvDN$AwlqC*_`czr!2Wvo*sHJX-a zMG+{iQL_)$pO|*kg7Vh`F#@E4WfUyM`rXnp&d<^a@`A|9{tX;|Z+hajO>?kO6lsbR zNkQO5ie_j|pwTFbQ*_I-Pq0(n$nitrkS+HduOD7TkUfFS1D*%8se3X#X3i+haO3QIB9ppzHKAjI&=rryuy7vdg0mlKg()^9+@IIl%werzdw_5#%ze zra3xW3F~j{_@?dm4ar8(?1R9ELuCm~W(ATH6u?P;jJNKiwxu<>$gzPr!QbOnYl^9< z<7!8%4kNPRhtg$>;M7dQji%=N$@^|<&iO#)481cylae7n(|5^t6kuD&yip}8EbpY zG1gnU_^)!@-RiO3qn5%z$Meh)_MIZC5)gn&s~ivA($t^$=0a-CDhpikZ<<3>lPPk3 zxH+`BC}Kuki6}_EUIauL45)c9YQB!vSJMC?qk=2ci##f@H?q!j8075+c^f8gHnnlw zw8*^Uuf-7p8|NsR50v;BVi;$i+}r}cB)dUR7jUcjXzcJ^$fOxj_joF^o#U%Fk8J<< zI@qY4(UB`fhyp7Eo&XwgxYgELpYSHj|LLEeu35#Dgd|)nP|BlF4xjniqoYQ)#PdP9 zq#!umt_ivq+ktucJ>0Gwm+S`f|2J6ZyfQ5Xo}qgUs-qm=)=FEctZoyHzg9U)RCtc1 z7=>~Az(k+R4|*1O6u-;sLHX^q<8X%u?Rc@XrP;b?OPsAnT!ICEj$sjZjIu6p6L2;9-z&p?v6n&d;67{Sh*G{@*>G_0x1#{MRQ@yYR7RS ziqc2#6fkR`m*cu$PrWzOUJuWN=aQT=zc5$!x(7(P0QE?Y5{GqnzG#kI)eVk+#74vZ zYJ}|##S#q9@gh$!G(%HiQo4t$8f~IMjx%e7dJ8_T8{QjVfGTr&oIXJkfl6`;&6D8k z|AtNv_W7~(uE=S4O*cA*ZsB@aG9ql(e0{riDBx5{0=%H9KxCS28L=!NmV?_BYI`>@ z;3G?`9O_uX?Y?f&dbnK&;kTuyttVYXi8uNLF7n5V8a&jiFL&VzMX=b>yeJ1vzIOGcndt4 z?~Qme6O70KMbQ{RB6pvZc4?g^*mRdymF}0YwC$rD*_*E0)!;`w)}lF@xpk$dKNlqX@>ucX1{qp$9 z)fyVen{dx7OB=^rLFM31LD{j=ErH2XOB`86^yEs(lFZ5~si*{d;I_2ao~bpnniHu3 zm1w3R@@_{;WK0ZC9T9mxT7MsU@8k9Is~}xlf%NM3+e3e!s;47#(I)h-v|N|>c=fKY z)g5K{_21WEFy~2AH=D=tPUxe-f&)(9Qjza5M@zdg#x)r=&z(z{sJHPbQ()<>*F!xi_I|~C|*aCH&R~wwl0?SqiK;51c4-2lH({6Jx{jl6Eh53 zL!M*E{+Ew+E{H}q$|5TP84w~VYbf1#rGC+Zrr|aD9j$Jtb2q6XKD^3Fj@(V1ckDJ_5iUmXDQ>R^IDMomJ1F-Wn1mm~mWjnvSxE!Y{k&B0YQwROG?%kCYqY+hCbf>Z?tsO)QZS9xmQ z$g>tG_&to2eK_Xzc85cnIsEnaw&3YIQs5X?AZU_dIEG}=1^2l=)WD3ZV!DIsRIh)V z7Ff@nfaX<^5M)Z?z^P_~=ZyJhQ;Fx!P4K{oxkq<8Uikj;*#!ltEj)Gc`9J}qN7I+!29x8#Loc-M0 z3q4Lrb`8|DeBeKK?%cpxD+k$NZEs#-v^Hlu9{BX>Uq7jy6<%9OoCKHODG;ba%~Xs7 z+tQ-vIIi$~-sJ2|>@E`tij!29mNZ&HcUe7ZiH60bl~~WqUoUDU@KbL~)I7v;G_qITGeyr+NIM_Iv>(?GNCdu(yhp{@KPtxl zC&8HZ55_7_IJUHXYjvlrYak-AVo*FbCJmS*DgHrvV47}HPQkGrA2hm>tTyK&8JVHU z#gR}LWgy2k8uy_F2MP+UkTg~(>vtC#B)a{n7?!NE0XN?^EZMct@zl_>cRf|BQFNAC zk`+dzMFEh`e7ASv@e#BC7knQh{$-7thS$5)arA+X?WJBtJB0b%r*lB;f{M__ucPvSN3?sUNGFMb(4YIaS#dSaO{eXMQwyMf| z8zNMY+T%w3g7Jufi0?OleC4*jK(W>zn2C7cB6n_b(qB3C^wX6tYS%SgQt<307Dnx^ zD@>Opcx{O($9j=FeS9au_^Q(-=1k#Xb7-1q=yidOm+JzZzj$@nDjN+quvKpR(0Q`P z*dFvbj*da;xLErK%frz@6D#Q4eCHBzDhI~_?a#$dS3G-}gqMZ;5}m*Du21;=JLbz{ z{FYrJ{XypoM<4aN$mynKn0dThd=yzP5;`ggmnR4q-GXNw1Gl_-WB&rUPsi$M=tVpu ziZV^fgh*2khg5%I@OTIJZK&7JP)=0Qap(KgpS%Od)&ef#vTJ1o; zRHzXTg`I8n${x`35YH9r&!OdB16^13jGmvVrzv{PZ|Eqej~;?4RsVjfj>n+YDJ=hp z{(Gym(E8!1o)+{1i&t{BMBUpnPN~L$}FO{l$Hd)k6JiXk29ZH&OC~Js>GR3FX#Lkf!QSxh!XQ#XG9#lJ;buLR%6eqGGFYqiE zzdh?V$AAV~M=Y99;&rZ0q~;5XB#68UWSIjk|5*Lp#u2^@Xn>HauRZUR#pwoQrr6K#dl&jRp09D~qA&7?%w@}$b$o6<7(I=*9cX_O zHUF`;57u7|GtRj0;ByE!#wj4ZRDyI9WfTlwC~~Tb4u0IAMd&^*b30E)Pk+C*ctm%a zi_?~Rl+|Z+qgTfUYt-+5ZWcX-TsN@# zTOWqG*@=B#+4}~Lf1>vZ`E%%eq5Xt;I1cfSOY@7&Pj0;9jP}2>*L|WPy^Q_FL7m3Y zf6r(fc^{{oC;X3tb{FZndF4g2?kX^H{NX z1kOtvbA0i~AuOrN+Hyz`S6JJi871bk+BuS#oGXIagUPMrOk>0D}m3?=STyiEkj;0g~2nb3?#O^231Vj-9MNkn%0i_Bk0t%?uJBZ)! z$lJTiCY$6MQr`Tt*}V6*%+Aiv&d$!r46UfBM;g@s!hXzBQ=rz~k&;=n@n041fKG%X zICsfnS>BnQrqr-z~h9y=r-cNaL z`Pw$yo{Hx6M^OO75TZ&63XgjIdCMF*4X^3Ll%?YbRyour>J>$b;}l5|DNzAj#4C!i z((rmeN^uRe< zk<+^kgNm9aksTRb3eTgeJPCkGsuZbi4s@UQN7E0|>X;%lw-7Xp)n#+^?@J7qsa(8U z<9#W2iNmVay9HvnMidM)DyL8i1Ar({o4QYEwR`Ej6zC!|)-iBVA-RkYQ>m1`!(()R z%ANB0EM`1(kCGjM&y#{P*A>X@BY9j(XW&u5rN0TlQL-iys>~>PCW@yjjA_>F%@tPk z$bEKV+00|J>0k;s@}CZ#Pvehs~NyFEd&r@p6*uOEu1Viw=A8tyPMN^E^ofo{WYao!_ zE(3T1y+Ce_kz0@7vp1vMJpDseH(hOpbSMR*mO%3(8if9DiLw1iEG6|vEN{Ju#Z1du z-H{jrA7z!dT;_gVDe5f)uAS|4VX@)!lx1Ih|5@5$XnCINFG{<)YA7C&{AXvBEiQxse~3R@Z<|h;4d5urgN{*gFkEj zP~Eld*qrT^8-(wT;g%fk@)+kJmoJbbx!Zg5Jly!vfQ`%bl@j$3F2>v@f01(g(oXN~ z8WuHHq@ZyuO%sa3F%nvJU)^VO_wM=vsgLGLYiK^a>aS9A+8sN=RE=w&L+~0!2qdej z1S)r}!fbC>#n|@3=c~%dz<%8+7-itst1x1T8!BV2AGMp^1-k)a__Ks{R=BzQB&Zg9V%e3f~nQ-1rPK?Up zXj)Z8MHT_ah`#2}q!7YV%PjrV7T4+OQQ;a>hF6L6y~mRO+ja&_23(I&pxXT=WnV>d z|Cx#Dc-3y6a+To)f?zd`mE@25-sUK*&7E6BZSFTIBTshwRXm;^zWFXxBdtn;MscFV za=fK{^9|{LUr2%#$-1jYc#G+-MmW~|U5a&j>-N?p65qQll5u8BK0oLWvLsKyrF8du zJ(r${9LY;0MG(9OP!;xmbJ03&HvN#|-1EtT??D`~WeI|2Nk%4L|N71?g+&NOC(y>$q7ui?DUGNsqSJ(W_&MPN ziZj=x1~Q#ADT;!s$dX9#^FQl%DAQgg4Ni^faaZ|E%F5HP9UPn+AX@ z-q?j-<*+8gm3|fC*EdVIC-ozEMe_xXFj+57x+lZ`q%B;ERuw17h27Y)Vu`?FwT}2) zKCrey_{c=O7Y`&rE2=7LjEV*ycvSyU4qI7*b?v~PcRt&+b~y41wst@ud7dR0g5kiW zGv6ww8qj%@EE!pDaLW$v|AKbdtW)fFJ=cPWc1=xS1WphMMi3b$ELz>N#8`NBSku1S zJtX&HbzBu9K{GtXQyfQ=WLO0`t%B)N8?J(i)}zON>(QV*K7I)=P@=#vG{eyp$%KUf z`a_>n2e5spZ0)pt)A94~Mn4)Q2$mKEi4-MC4ct2`(cjgVS{_+#U)Ix)b=%=Db;9hd zUke>qIh0pZy5fb=qnyvv(eac{>9qd*4gG`Mq*y~<)%wSx^)DYj3DI>Z60_rZnxII) zk&;Bsy5)r(>syXafddHL^mjq3=#KoKj^xq*?a2RjOu6Xu(i8ZqS>L%}Y4!1JEHf5F zRv0hh_E}F9d%^4ONv}WHETtpb?(^n_&`1^&}dF1c~t{9?H+V*VX>-{p7z(% zHZhm6TGqGxcYk;AO(<54#fw#dpj1(k7>;1ooDR>87|}^ zjQ#%k84IHt9xjTkbv#awjhAA=O2r!pAC zZ{*To+QS~X{of$@3wnA-1j)T5kQ(E8b<7sa66ekWhyTlkcSw2=?^im$acYBDidYq% zBuVe1xme6{6XP78)H0&q;zFHL>hF~bl}uMBJk&J4 z_l6wRH{&rDq?-EPuwGgyqkHyEeK)Ju_lUkg*VW|=Xk7r;uXegVq?ayAvqE(Gfcy)t zD}joU-~Z;uP&q8SOXT<9|09w03XQ-1ur9d3_*R4TcI=OnFT?UGB$m#6NQ{9W*v^r- zbtcYs>__^GLS6m;4l(2zbbX!-wMxkIa!7xmj&3}reM{>XjsL>@==!1Mk3!!2*&NEx zV6b**nb^%7eVpdS`F~0INuA5gM~sVG20jhA`r)ZUz8xKK=W8)1CM1OJP&tIb&`5p> zvZ39C${k1^4cyiq$)f?VTNg2p8l|&Hp26r3AhbgAH^<1|gvp;=`Nx4-J0|*2zk%s7 z_&>V;s~cl~jPj3ONFEh?Qjqqc%ld7YJbWKr*WW|(+hXiLo<#CbVBSwKHME{_FF88u zYq-EK4)=pbbWa(uwQ z#umJD=-6s&-ilz=;MdjrEpsS_USp4YR7SnEwYR zM*qLBDO9sDFfl%y;NI(@HyGXu=&I-YnL;%`C_q!9?v~JeykJM#hw_KdVtk*B=_i_2 zwuF}3qlkR-vtrUBERQN8|9dV*9>Obe;-#q1uk`hdiW5Hu7;rs8VWS~y$Zo2Y^_`j9 z6ILFF(!x`w2s>bba)K;ZpmUBNs6D0Z{va^G^u`C>ADfi~7o4$(P@j95w!L^?4}>*& z+ZlFSJ7^6x#1v_<4~FHT8Iq?J21o)!T?)&Sym$D%&i_1=A3UdWdh|2uCP*{j?{bxo z&AIoVSE$T~J>)9vB-rUl}X|BP-K92hC85!?+g7a z*uYezK3Pwz>DR%|>%J$U-s^Au4$pJ?E+SFCn&Zcqj>2;C)5|a*h4%og^^Z;Oe4e!m zS{&^uz*?a@7#b}JqO8%ppgL9H5BR*}oN9XR+e@j{D-$4ZypNo_?3CU+5c?rp*#%ahU(fk8H2_1_P4cG@XYF^wlklvJzm3WBoJcXe$Pxl6vIKe|t<~$n^dU>+S;|@W zrL1gTu>-tY-L+!)UX~%mpbNfk9)C7a0)r%X4j6juz=5QTUzKZQ_(U_{GD5yuMo)R< zc`b}K%8V(es1Pr?whzfPXC_1yGfRfqG z695^&*M3|8_&a-jJ-puR>`H&vob4S{{?`~&wZav~LHg+rZi(^zYiXs^j@zyhRyL=M z+6gJJ9Cp4Uh-xKBwS=PI)(wO{7?zE6#h-%hzoeL=8ErOSU~ z!K0T6PnF|*FRhq-82#*7TlDwuuW)5a+7A`8A&{@fTE8qY39imKWC5c!~O5hqBj`Whkf5{^H%NsGSz{TXM+axnkDqc7kyF#MxV8Pk)c zjOfdcDHlbTqlEJl#cOgA%Nu2gyk!D#zTS<|09Z`@tdCFL+S~CP*2;rs37#T3QlJP* zU6;tAeFQ7TXIv`8xoK!Z0WycKzKi2EOX9_zj0!uzAm zm!(|1xa(^od?m*BVyRLXDLoz}rMXMFl*^Yn1?3JI=F(LfeyRppiWpY;>kuCQ4wh!V?$ zRbq{@PU>;C{pS;-hK1*4fn)@dqzRQq!@{RxxMC`{O4XV>x_sOBN8xRw7=fV}o+Ctt zAUPt;HmdcLL7XYwa8+p5R#gw4?zaM(3Kj}W?hE)NB`?%HNvi}+@}fu)EIs|~=Nq@> zyGvMOjhsRlf()SrVb#SClbK;1aPRWZ2ac|ZAMz~P>GJmvNCA*{B?%2!z~2~}qPWSh z+GjlTWP{i1BTA%8j;b#OmCzNJVxFJs44;(M&Lg?U`CWcAz66Yrfu`Z3k!hW`edFXu z%HN3RVp$}|T=MkN!RyHzpn#w5Ij!oE!z1&r(l0lKa^qVuq|GDRFt(IfO2U7<8WmHe;Qww3=<*~w#*D7W{xqfgrxDDx=5D5vv zOP-RZ5EP@45-p1nFL_GZCs7YxYb1nPvJuGhWqP|Gxn2_q502{d~HYMJrsnxG4hKMVPig$pM~V_ zjgjwz`RA?gcYN#n zxnIHj(p9gGI+sxQp*?#3fyJjsq`dIj$a*^Oxuy2A^@Q`n12F&1m?viZy(oPl%(w0H z!^z#}`y7Y)kwdoD+0u=B(Wd8RP}O?`Jd^^t<_$TA9B0h+5|8VX!D~I){^IWkQ=^BS zBREl(8G$8LSw;h1#S*{^Cj8yjZ{8X{Hz6G>w=o1Muna+P1kI2l&!ci%pF_dQ9>oM% zx!aoc#X}?Sxe*^^g$9zu0*WP684a@Xs6GR`AiHS1=j0W(+Muf0eg~LQ? zB(G_Ts7i{&t{k(*Rycgq_&8NI_{IdRJ=)&>`5jZB#M(7nVkLN%pb1(OL{&s3)~^qw zL`-9EfO4$We%OEJ=`U|W0NYKNjfq*Lu^aB|#ucsHtec|tkjm}LvQm!I` z0LZSMZV*}GyepMrNd>W0U&)g!bJl(UDs<2a8~9p~ws<5Ak>En&dd z6}Yp3Z{UMZr~mQgqQr@pxg&7UYL@W-lGcx!v!xfYoGQrSK?O`ZYZbBF6y&>Fm~yHh zgb^$LLAf#>*Z<16<9Y{65$UY303Piia;)`}UWd*pb6evVWEcoaboOv}%5nt)z~{^W z0q0m+a_0DfzvDPh`y7`$;PUhj_<)p!uGooj@;tL?f^}m@--d>d!xirKv*F2C2;(nV7{&3A8YnN=y_xl&fpUGBru>Q@Op*1gR2nXhpCTQKR>3dZvp*4$;DUQk2wWB5)mPc_RjG$%8vB5_jYzfDi=`)Fz+PNz~ahK$!C&hO&= z9)8ymQ%=Vc;>co}V%;?BhMMN{b?`XScgqav>^HUx@Hhj&AE<1-{oPl_w9Pl#IHva` z)e@Sbuw8!-u^Y$_{&g&d)LacIr?epz{Bmrs% zvOFyowNAJ0UO2zbA4j07;CT2*6jp`tAHPuZ<*&Y|XsJ<3SSad=y?;~L zPGyVfA?u7+9(~k29((dZ(L|onia-hiEmCyY$;Tx9RH6>X=hj2kx6bTz=kA27-=T2q z=i7P7GAWXb1bBjA?!Bw+RQB)?d)5Dl+f^;$`#4`(38sgwqduN6@RSr6MhKCU2tr^1 zMdL7XHYqek|1T|QV=meIIE*}O{eAC~6UJu4OJEW7iaww?b6sj6)5%LRr|_&yNE$W& zvwnv%?N!ns<=Nw;`iHIe_Yset`MLpq017h%g^(y-;w6HRsfNwE9Qkh2k#ezg1Jkau z_&#RS9BaE@*XB(93U9h5vI0dh3{CK~$Z%n%YtA=<>3bD%Rm`>aalNYoXO~%_ zS-Dani}_aZxmCAMdO4~mMnYv3RwV^aWEHgE30QhtV7+PTcVkv>tQSrUg}ERY1AOD0 zGD-6)BMOSjE99-((+}4EI02fOG~H>Am}(P4=iur-(fbUa!|!9UEsJT1bqihphY1^@ z!OiVq*l~GW0VgR6hgJ(W=bdxF^9`I~A#NO&Soc5Dn4J4@tMJL0;V&#qvJB(wk$0R8 zd_k(|2?Cj3wI|4ufzO{by=SvXYd4-NJYl`xzHU+HK@kYRt@@n2kaqR9XbLR4PbAt>IZdWiy;FE(-y8iI8y(v=JGO1JJ5I+oJMOTe zj&0lS*mf$m?M!`t|CxDaZtAJ3i*r#=oqhIx*IJ*YBMUBKQpl7gq{DVwaC=OqnvDA| znxNORQd6lI)o7+(>bZSy9$Cr{ieV~FqtZFkR3hTjA10wPO$?}#oK1RX|su5$>Ip-aBzww*z$KF4LvGYA%_!T&23 z11^$WLJCu2A@;RpzHcU3_#~z6&_n!gN3*)FU2my;t4k9pj3JScg%-dFAY99m6Wg!H zP+-v|>3Es4^m&Rl;>z{XqmmITkicfjxU`Sed6Zwun-m5viIx!v$q!7xc*T-}^?^&} z=`75&2?D~F8(QWgv=WUXw;=W6@e~1g;9z(cqNt2z)lKQZD-EZOk&J8ef@aFpSRFrJ zx!yDJv(<2_a<`?>81yq=SL(I>L@FaqUDB~A>fFSuOkNO|Vt#x{*x?O$v+N;anSaMr3%6EG1Q9M zV$^we0P&StqXRizv)Jq&IyXgI**L%l`~32`MVJG@CnHBa!eL{xa3?dRm{G|^YctVS z*O<&+qt}zo*|+>1(T1y91)r=USYb3eI6bB(vUD)y?_!sQ;g+4q<}mE`=5v>n$Pzl)N7^U>Q?>`1P-oxW)+!}~g zi;p%Xv8AJn{7YLer6s78WH5@b3kkj-%nG&*#b57+cg;bxsWATp1`|i*5ESW4t5pUI z6TC6Kt+xfwP~j7knhN%2r#Q-ce+hh(h)r-@^U6fhS<9|elYbTx+TVFw+8@GeS#Ot! z`4j~(%HKkb%K^gTK4)p!IR9%LGnM?}iP;yHzI`y22|hvNBVmdwf2$Z&5zRw1Dk49e z-8;TzyFG~dtNbUy>QTkxm7L zXdxRFrO@oy48@|muEEA}zH-Bcdsv5I{(qpb_pYoOrI*@vWNnkvWCcy|guD4$1ffH! zo6i^G;Q?deB6XfQH(R2|_CybSmmX03Tai=_u zAJA%^<4TW80ysGk)k4E#c2SXO|MB4c&c-CEQYqphAngn_jzCMG76vWOPerWMzy0WP z7L-?`Y1If#%xr<9kw>otz%=6PY26Fqs0qz#3Gk}3@+;q9+}aVc&*G9N{FqL3B=Qk1 zb4;WSb{aEs+vvPF^5&{?XB9T^i&N@r%+40d*LSPBBGj9vl$b^7`O}moULfajikUt= zW2r5^@3&F|u9*MSQOXKEDm=&L+;-iS=-tCWUa>X$ID7WO90vU*x!*+*ISWiw7X!Y* zdj(iF%sg$2K?5Nb#fq3SV+h}KV&-`uyS3?t0^ff{ej2H_=4&JS2@_G+_CBQ##p~_7 zp$?z)LO&S|-~u;;I=Rb#`Cc83Ll^nZb1vn>hxg=A-G30tbexf1vDDzVWqzG}c}RT* z$X+e`e!Sorwr}JL2gn5oX$ScC6Y`-tT`{$Ub;nHsso;cm-h4Bk2fCh2qOVAWjH7P| zQ{#-U-1^rVhaw2VkpI+<9i$QMS9OL?pss=41jX*%|EYK~-xO>Pu%Rw0Li^JX_TSh-qxWZSFX$a@{fOrnU+d(W z9I8M_&xn{4IR%`6Gy;im z^gpgI{j(&dY>;d2#M4|odypdW$S(dH9rnIqNP4%^%C56YOd`6ez6L+I_LIkwHnHwf z{u41SiKj9Y=pP8D6rjX)?H0drX`k&&Q{~s`uibm_5N*F=a~BHvR#_)DudUe12RCN& zy0!M%$4x?Np{jC+9h(ftwe0c251}~b1lw+I?&B8}OWM&=-1T?i^@*(sV^+N|O>)B6 zn&)-P+uiyqWsx`x_IE(o8xezVTv)zWdLdmbI@aN|(c5%oKJ{vfk?H#g>nsQ8x43p5 zi(8u7#3o8(?+|UxM8CNu8(@v5=Rl7Kqp!;pP-BuZ56}S$X!^{5X|cWvi<4KLQ|@U5 z?P}gl*Lsh8fKz=F7*vCgjF(JE(T#5?|6~zwC*m$BA%2k3lZycKRM9C{-!Tj8pt5LV z8Gs!GGL|7x{9?y)KcQF*tJv*yTkG#JzUw3~bXA9zTB1}n-M`MTb+^3(nKi!32YIeB zI0yMKjNG?&nh$SFHwEZ%Gmh*vv3QiIIYZ?M_@2jqyTBHSuI83nh?+NTQ{vnScK%$H zJbUC-KUD6-Lg~9e3lGeLCI!;MVc@ z&%5{*`)lS1?-TiWPcclMpr7BtyY8Ek;Xwr+BQL>!bgi31jW^y~c0*-y2!nKIDG%zD-1m^hz&V|uvI z=I;Jndko1>k5iCkUb_np`*pHu-_a)C<+y+yO-)wUSe_6C7vYN`v=CUMZ1TU^rH3RO zq6g{paN+qlO+`mN&orWE!&n`=<~VF*Aw`Mb47+$N4&9PPQnJx(_lnV z&oPqK5~`OO0UO@5xaER~1b?6?&fu@)Zx#2ETex!BaO0($-j&I(2)iOZD!0#OrXDA60T8#rGWzPqiTUgd7C1^;vq z;y$Be1G}?ON7fI%ihVPB5FekHK1chDQ$s@2eD_l5q~hW{eK`=oMQF&Br%gvhr4-eW zsVtX9XJqq`vY=QrSbBw?D}7yOFGyv0aDextHyP=Q45Nj`getUHk@chrf=9@LYt2h> zdonQJ&XKV=y&1bisovo-_OeWcXF~oL$R>LCcQ@Lc1qQKp}kuI|$_#beYX(lUGL4h7a=< z=kc^4^tBq(+~~3O^2Tq&iAsyE2oE7kk51=Q3Y&ELmy;0o!A^PMWkJwcO`~!C|7Hgx zx@;$6Ha{Rvh9{~(t`oRjT`ZcSZ{RD%wSLEhmx`wq%QKgIKCK|@X(?}GqO1CAI~cu4 ziW&1xurfvRZnEIeBD%NT{#+rK-%k%gHjB?P&$4{ZxdY+nVsc?}swywfl3}30Y)@CD z2^R2BnrFw^YUeinL@LV|D}x?2F_T2=96gfQe|Zq|7{K|xPQZfZ3I6cw#e9N{U~S9h zkSDp7IwsK>Xu~ICxHP6lc-O|Xugo|LIu_AE;4lVE@s3%GHi01V z!m&#%qoVUedpziS((ek2TSs|8yU@kBZZzJr|Ji@%N0l$i$ z#5hln4Vvj!u#I$uTK#pDN5EEj^g$jJ60uxG4m|ElMd9s=+5V>uv_d0;(D&OnZ9ZEA zjryyfJ+q(2_5#~OgMquE`jF6HbX!sSN}XHsHJAc}r$@?>Fp7Auk!LuSFbGJj$1{Ov z(MI+1&+osAo&Zwm${k`SWb1#?VT75WU)hdnF^egU*6;1R#-1}pxwUBuljmOb_0HNv zpI~s`2mZ2vM49tAIiVcnPmnnCKZQmcr4>Vbz8ppliFLa?qX+a|ZxiBBy8&k{`N_i^ zuyI@>T(gGbJ>`*SFn!wET)hb;{U&w-bL_I;CHw|!5q(@?pEFQWF+nhVi}E%$v!{sQ;uYhEg8j@XWw@%Ds-(xt5x8*-zM~2FrV~WY znI`=^0{QoE2tKkkGt7DOc>qWx?d&m*^bbbuyp+KdyrY1paae6EjZOo-^Bx% zFn-rD9R|t`ksTBB#Ol|-aaNJ!Z$?>%P7ujO)+yT(K}CQkl%AfUv7&=K%N$cDn1@R% zAOF{t0qHHf+#?DJ>G7M^PGU}A=_FSHB8+UYMr11Nx(iH z=gRyExM(NxU$nL;rDkOzoAf*O^q``dC-;X(n&-;CSvNVuuUk0=#w`OO6m5R`#8OP*f(B0Yqt!2gc&{M?KTX> z?%7-kxnF`$f}sp7VOP30>-Gn>m`CP9{sm9L_yQm@g#adaq;Tn^9KK!pSDD=h6=ige z+c^rI&1!Id=mV92JBTL%|P2A4$E zUPrDQAuEj-FtQN*bP=kn>~Th_-n`17h_J-GxDP@~72YOTp4>xdrEIYgxEAc9y$So1 z_18@8t1)}3kw8c6?qL^m!T--qXQOGH(OKZ1&9~}D=Q!pP?)_o+?-^zU->Z*)Bce*+ zVCfoJSS#g8Dw6xJ-F__f1A@CuIssx~cFXmHU#>pwb)VDOFgsAvE+(vp=KMLz_{*zD zlfRBgj#O{+jkr!e#>4t9a~Q$*n*ZG1(-g7;PLPB;~o75-M!92LA0uV1kg2E3`* zSRE5t07fDkMc^UCSsQ7iKwZbrlGC{{-fshCX!?$E7e97Gv~gH$bxMz@{|Q9@q$`1i zS}Q9@eg61QRXyHLdH;-t<*&RvL(!SpLhiyp46bgTII~D2*kHZKZ2ro%XW{0|!>&=f(PX z->8bVu{U-}2q+OVS$mP;3)|6)^O62nB(acGCAfSJlfH#<5dUquu`6@PgXkM zD(=X}E~u#StPi2rov(781#gN!z2uK=uv0_?LY9k-G3wP~%^$BeTR-|ed|IJD=rPIG zGmc^~GRWe4S3L&%yEG(x4!^pC$b0M=rZyke552+Mq#p~&J$>XazEg~J>vY#p6ktY} z5&$6%*Fi(|mY$5Lt!1|)^ed;NYu;GK$|4D)I&KSj+c=a{J->-#ssBzefSf|PRdAX? zYXLGqJ!wMad~))I5NQ71&@%%)z4o{9_-%05wnkyRvk3UxQR_YJTb(W^xS1juZVYCb zbyZVlPPZR4Jw856zMCa;#@I{QWpIJ$= zYAQv#IbO;Ftrmu^E3db=;{P`3IE>QccE%swx$7u-{;ko_4>(DrJboe|w2Kk1y$4AS z_cjsOJGe%FJ5_N=)7s;6_vO|+5D0e`-n&+1bFtvOesOrWOVvzNl}OjD#!TR^8=XaaVGNtr?5K5u;Ln3-Ng}EO1jYC1 z2F#q26}5kt)`VnT6mx{YjYDbG$fa33M=&^tovpCy{@pY+cgNWCQ+49oL5jnrS4I$) z+?cJv93CQc{0_N-Qyi#!s8=*(Ezv%VQ#~S-juaT4FBgl1;yWr=K!_@MGcNa~+iYld zmI1}Fv~97reBKs%x%1mwRH4MEcmOIqvSOR-8-?@N{N6@Gg*%W><#zWG7MHgkyRfnO zI)LIkd+R@$BH_pegUi29u5iJhG}jMR;Tfn4#WZ*E)HO88$ylLC;XvZJH4X6KC6ia5 z@%x_U!#|zC8RU7gkmK|vx{NfqamjHO(!ga~*$sz_b&o&YISE0O5%kk_2$7eT#K*A= zugLmweLlp5Hwaogliw)&Zq2qjk95^UhL^k9bfo#ut9=_TDs``YQZ@;NzKdtI)c$Wu z&V>J*`5AcXK5DpOr0eYQc)z5w%!Eo3liFcdH))Wm^)iUW(~cEy=k1vKIaL75ecpAl z9-`yyL-k=ZM)(rI$;7-pW*z>LLto^L=zesy!uV8^-3lsV@_f+39)R!rbKd1#Z?+Ax zUjh|V`OUqP2^WfKn=~S#LJ6Aj=&#M)s00Yz66hXEH6mn%7Bqo{Yp@N1o z?B;#u0aVVj@2pDFs!+(z^`8`0$F4;E06S z!S%YVW^Mccz?%SS+pD@8g-jwR2IcXke+|tv$!|uwg5_-DO#ktaX(p^_Wb3j(G}$d& z7D%Lb0!P2u4AJ5L^CbG>ytbVQ62$?1>Rsd#p0A$sFa8+*kna#%H=pSU^7!2i+VuVd zgN%Op83?WoiK%nq_v0+}PUiO(-n0IAqYNU_=pEFknm{DJlVB+U!d5C~TNtWsi$Cx& zfbQ%@E0A#%v5^*`u(y^G$AXHh#^9d$uVT*HQe1^j#egWW#zFW=%rc$TjrpgNs0EP({ClyhOTZA zl2KTJARi@AmEFg)g+9I*cVueXQ@Ucnss%p|5&j#KP;I`*Jm>H?Olfr_=^Mh)c>(FjOj_rk zl|h?Cw*Dsg)d-0nKnD*q3*sO)78{A~k>e)|aGLRN=*ox!-@qEm-a@oGQm5pDT11%1 zwGow*uI2V5rB~xeI*RTMcNPm+|Fry7JHMJ1dRy{@u3uM0Tdkr7(?qkPWXHgoL!l)D4lK%*wD`Kj2ZRqvsL@S*fD}EW*vLAI!7{aj#QJa* zceu(;YFkHin@W}ZB-O?}-7%<}7p*Jo#xjX2&<6FD$bVR6>$9Os zEs@4Quzn@25e|SM3stqk?OX!*%q_Xt6ltvnO z>GGe>9#!X=>wwpjoN8k$(xpI#w3Ujrj?J&TL1T!?hkzle`!t%l%8`b^S)E{4`ZN(d zK~@Ktd&nTC)!yz}CG)DcSczrLIWJT|3#MwYen|=Pc&Pv;SCaErc$)l?4=2+vK?2r~ zKP^23)rq5eIt6Kjsx-@8}uE@=0gMs&jDsOB>|^{dGp`{6mJp_@0n32Vn1aAX~9 zDGS(xM-co*Ee$izWJm5|_ouA-V<_Baf*32X{9Md_QjAD^7HaQ&XAVN-;ykfFkVF4g zR=1~HI~yusZGz{w-sT-7BSJ2M^?=8Jpm;u7O>wO{L`scSfkFs@UYUDf*Qpr6rV}VYMYqP%sc)LfQD29Is zoa79wp>Z~Ix9U0u=wW2{E)Qn)zCkF7l(VZ~B7ci&d_I3t{{*)jTkaY=R9qgX4AfDW zJQr^4_~~y9K}>K#hdV5=N15GemZ{;PH?3DZ$~2}aKK3%I#dm>c#%s@CJrVd5%Y&4|<2_+q>SO=zt|Yj8Ke z=hCS-3(?2G(Qs|WRR&>>^7++C&kBO51KQYa&jbuOQKY@V-&{~{4}8rCOG3N-pC5M_ z3nQE6PE2GDAJQ(ZW5 zk37`aA>kx3Z=)f40v-nIFs3@OwQgf@$xbH8l_~qS4sNPRp1jd*zKuqR#KUX-q#~an zMep}_@m+*}l!UD)KJYbWAw-5gUgik}kCw5nM{snCEzbBKWuqHj?9Pfm@h)f6q{m8M z^KRp@)JTd>^&1wzQbMXom8GB>_IH;-(VN5i3u<%nc|y z1LZV-Df)zM^qSkyeanVf2~DxN;cs~WQphujc z(cPcZd#=aH8C)4wG1VzDePc{IJ(@(E)^l{E{ut}~EO!N*zy9FG1X6U&(txZRP_ZRu z2`gMKQ*il*&6Kzlg@9}!8+h|o$z{k5`*O)^hVat{6`LqHTPX-@*!Fmao1@ z{E@LF0c3Oud)8XHgRBj6F0U&a!J^8_K9fsFBQY->f6pUs!6oma$Zhba>3OiT{{t%- ziRkdiRcO{S`sE7V%fctJkz$WZ&9UZlfA{uXSk*B7VT~rNMvZZX#z$#{jB8UR_ zY<7IZyN(gKThDxEH;6ulk+I@tlHsNy`(5xFW6Kpc2rE>NBPc;vQWiQPoqj%psNMRK%#V zVv<@#f5aU*C}ryBsd^$qx095NlXNcUz`s}Dh!C+d6Z|(*qHvilM+q&@Fh@}w_#WH# z*h9RN7CS9Ic7fp}U z2?i?f5=bl1Vgg+C1#NA;e#lrt!rq`g@w}zfY+WvrNO))!j1q!U4@Gl;sM8{hTJyLT zVL_8MnkJzzb78DHTQxLZNi!K;>?CVteR@HsFnI}wAH8>w3!$*(KQBTY|E0ZZ*p+_e z6qT6Op)OOeGT5&)SZ>Gic?Llmouo*JCV)@F6BaG5ZoR)q5&)INkj1|$Xeq3V7Eq4A z7kbk*b$D;g9cu6c_b1k})~{iMDJ3}s1|su&RRxF+V=88=L~m?%ma!*vfDX!A&R5S* zu>*DfP{K=rMO0ui=_Z=Dg6hL@kc*$}1-~9?_>wPihxLuDmkC&U#Wz0=>*;VVaI&?E z*Yy>vGG@(@GW}MzGdTNr?xz0z#!j)XAwQ5Uc{mkVc=izVy+Y=q`kr!;* zyLugBe$#PU$zR|pcnQY7cQf@ZE z?k)bY?^CDTIQ!PcP2$TuHj|`{_b-Y)F|V+uG1QZOFbU_o@nHO`(mSqRK(IX<^2v2- zRNj~JqNMj<<}GxEFKaYjpd>KyVqx5ec+Wg9!1?%{_R=F&yoQM0ZK6rp|Lf7=N;&RV zPId_q6nj}|G^tdha?7yHz`?NBBXtvMrjQGFlKU@8$whuy#u~?Zh50B6rn9!2<4PPO zXMwVSHNS@gw3m|8R8UY1dY!%-U&7qE=U@D2On-%?xaBDFh|4kX(j#lNdOp%W*Pmbi z2KoQzNNbvzt?$rMkk^rELf42v2QO76m;17J?11qC3*P$ zhzt;g*OX?g3m9u`t?Bnb!%h-gDhdWg+DTM4ncM!XGss_(oXPqG(3_Qf-9BzBX3Yb5 zr@DoIe!cw}AX-NXqi+xkn+=_^l$A=*2}^{I^7B|J_IPv?Jgt>JmRd!cPJFDXSopkY z8!o7B!W>|L8ik13U5T){aDktlzxK{)`Qmr>Z3!R&acjPl>%xJG-Py@NB~)1fclZCK z!@d#&w>lM>oO8Y`zXJ9AiXUhkb&9nkSsCl)5*bl(0pCtgxf^*_Y&Jyi#Mx+T)zHFs z)_IzC6&VK!ERuYOwCOh=Q?c&rlg{6uB%*@C)qUxjuH;CLwBUz$QlU;U?_Shjv0aj= zTnP_PreXEObEX+gx_CUH@4lWH%yW^Sm2;KQUc@?G%|QcfOfZeXEjt4z_TIoVlr?=M zLJ5eu?QoD-w+U`O@kTC+u}_Qn8HPi*eQUzi^@C*N#kT2_W(Un&0;tMZ0be;ZTdCmW z`MXm6hzW$`dJ$IJBln6swGEn1S?_u4o9}!iQtgsPi_RTQq8#g#$=@olI1#2MEf3%{ z&K)!S8Sq(#pR!5BNz z;4ymR_1-0T=|r?)6cCI0>=Oqr^!c=|zf9BsG_k=jg=m(%o$(@m-GrL>X9tQ8iHTFj z;EcU~*bpJKPOU!*K74Z9-CdSOtM7deRh3bl`NtYJqsc0%uW+^2QA4ssOOazmzOf&& z91Csf11f>p6dFFz3YsqS6#NWik%ss5D^=%kuya`;?y?Cu%;~zVAllXprdF*+FD;i+ zFPDQ<+v9?5pMEPifwgu+kaZaZmxu3(Yk99{#&Otx%Jy5Gx~y;(e7GJ+mrU#g-CB;R z!nl$ARw+R!2M&>srQ&HnUVHsB3f7kowD*k(BUG@&F}y$?&{hb;K-gyx>_B--aeHfR zn{9q_T0woXi5UZ?CW-eW$gkldt=jY}_VR~18CEDYohraQfBHP=3+cpt14(hxe+0R> z(%xx8H)g-r+{fc189L!c7=hIE$yCv+of@DSq+A^iDX{5)5C!L(jmw~p(=mvk~Vboe|H@ss3 zFFBo22ub~yrjPhsj{^|5ItsyQ6%-mus&5Ed6ILICNlYOj5cD04eK#pyLa1`sXMv|G z{7vzAxJcaPq4EZ&Wb7BUeg>|TLvCFz0>?QSCQaR@Ie_K6kS%6@sP%?t4}q;6F=HIu z$r5*Aj+-W3!(@cj-^0rwj)1Zh71-fr&`M}hFQQZf!wm8ndtrjmhi|CGkt`h z=y8-!P_r(YAM>Nc?exzreSkr`ZKVtRx?h#Z1zglk|4hYDzwW1%`*CGS1B??muk(#}%G8iBE zMJvP9mC26i3{EqVO5Xktbc%_T&oHsK|M3QsA+`>_4!iDSoT>lv zgdvXAtr8O!=5kMV(L@34DHMJp1B%AE7@wX@!{>QUun2=w#Q!Ca+anpdn}ieo6&;;Q z)L@k7=z#QzjpztWPHAN&Jo#cn>UQe=r;8dJCmg%K6U%^1G_0oPkbfNFu_@1gfBnv& zq2JmSaW>Mfw$*HW^32u?8f5_ocmH6A2oLHpL+$?^ME^aFg^Nkl;L&+h!lH}itVf=2 zFP|VAvnT;iixipNgH-=dZIrMDmDMNgxhK%P2fNRbRgq1!NdwkFs~Phc_VSYC8l0}e z!yRO;let6ztY>|?Hy9l5UtqTk)5dpJsj}XxlNQPqsCE%VC$CQ&JZ*a_#)=&B3v%i<{2aNvzMrBb^~J zlg$p4KRE`l3m66T7Co!RJoNDl9A-5L-<*cRTOMh{Is6gcb~%LN1h}*Z!9EC=W*J~4 zsh0cu!vAEc#%6Q9F8H`A*>Z9HqDSEn(oK*FJ^ZeTR%_vFUIeK?zk9daJU}Rpr>a&2 zvjrTudPFH`p7!R3Wd3DC!TbxXlu;T2P-yP8^B8*9yyZOtLD!Kl^jgpiD^FZr($$ip zv_@H1_Y}QD*Wy?6RhJEW z6~!!NC6c6@R$#8CIg0`0q(rXS3pVsUT#~+2`t24SqXSEkfXQ+rz@+j&yRonbX$~Bn zr#D(1k$mN8#At@%*UC7{c`f%@*kNrU9JzA#Xyo~ADYLRv_vC1iqx+^ndP@tJl_aV9 z=Pj`hWQhJWu=s51{(kwP-JWUD)leKf?=NAodRz`(rXIh+8Z9fRMLaYCFLDP{s%w9~ zaI6f*H9G)})_KDOUQsph%VDUQqL0nzAM>j?Dq)}a4wU{%4lXHpSve95E7WYQZYl*3 z6sAJSHra|kajn3WiNs?6mD*;OFQN)NY$E5n5{7L5Zs5NkCFuFHEJGUFGz$~bENTWS zEiqa3Zt!;^YQ}u|k8--|yYdirX4Do9Dn2DOO;kcJ3hz!ksXZ#yMHxMdSpp0U*BA$c z`<86%bkyO1`aK1Us$1lyQf?XApyDS6ZdpF3|Cx>6 zmkdtSlv2Ts0;o{Dr2pmgwJ7F!=8$)=`lQ^tjl{AN+t&^HCYk=N9|Ed{@Z0|R7Jf3D z<_h6hC^&=i!=HBGwyfHrhLn~jTJBp++J#e93%~!D<22$KP9L4d2q%m9tS>1LgI$*I z4SeuSoxh{2jR=%}L48j?eGu$$a4W!UrOqFEbw-*Sk~b_vd6{0Ga>ds}MO%qaLmmPH z^3cR&A_x*E zp}Iol!j*zfEZ|1V&l1He;1q#1)3IM+%{zRNb~#%85ko#Pwq3ZOIKo4-QFWj@<(@21 zPLQk4>Es)KDTR!nIPjuD6+TnH1iNrsTA85jDVt~=iZ!5XnmQ($@yj#xGcakE9k!Hk+A2^>GM=VODbr@Uo{GG1ffB|VE4QhBFQd5Zv~~G< zc?>Fh$12?%Hw?{-nGt3V_d{q^TZhDko9|UE@r<|npTO*2jXVH7ZWY27VzHo?1*Dgoht` zCID$>J!REfi_6T$%#~uKst3CHf1wWyW#AY zIkkSSMVIqa?&Iae4uah#r9R~5BQ=3 z>TG6A|B=NU(80J0EfBN~SVN<|G+t9M$!zNw6Nkt7^-d)7tAF40Bj6xG-c#4uk zCxA>Z>0@6zB?l1I39N%~)285;TN#53bF-ptGfv|T&#Za^vaC>pbJ3(~n34q{<>A6` z4NM`1RwvIzqbsV5Y51NKmIT?0 zE%jIAHpnQs(yO_X4#O_kmj^s$zIDIP-$-`HXJ;B{^yd>6T>9-r&VJ(W_>PoZ`TGT0 zn#CMKYaUX%_8`V%J}jW@ZZ)#SX4zy5sq%v|sUJx)3)C1$RbWa<=9=q`n)FW(gVnM< zWJz_zKVxPLZu~zePY5=Zj>5M38p}R?NArKQ=PB0~>c97i3e?CSD4zoT3b;F)gi7h) z2;>knP5$b6z!x{{^qz7yHmcR;YS9GSKhZG5AA*X!Z)-06sZJitROUZhwl4i%M_HmB zJF2xxO)608d5sH>?BKX{qdHM1S#3_B`$pOId;0hw>LCQ}!WUecnp#?2U5e%qPr=M1 zjXqfg7iJpW`%tG&W@)qptl;rdOBfTdismL$OWrGD{KxP~Hr*~>|AmaaMB(*0PeOu1 zDP2IBtLcK*wd_t(TDyRkEM7{**@IrwyWi8ph6?bqJ3g!dIsQfv^ZJJEJM-HkUeDQE zowY|4ScWeVjX0q+5AMXA$>;q4)deI*2q29M>m2Sf9Ub4MwPT(*gYMqCAvdeg@5uMn~ zHO4nyH1hqlM!kFFPc?-6CufrtEFQE=U6*O>%I@OfW}bzK?S9_8!6n!=FJ2gyM6$VA zx{7g4!}-E#3&>s~Ic5>%3Gr{CqtmRb6jTW|&;=}t82;=qJztu+z1}kB<2j$YKUmb` zj;?nzgX&8|(QUs~xj$PAd>k&rhGv|G3XhrIHh}ya;~G*DNfuiB5a3(WoinOC{ZEk*)LA!o(8@h^#i&W%mw%liPzUi)^LX3!d{Ou4bg*b?vp*|)2E`B_<5My4XHG)X|FK_d$pshTidEaJecxG>u~ zs)Cav&#mExmuHDW_nGulN zz@8@^-nm+oQuOZMyAqdeMa$Q*JR%fU@$u|hRg!e>0526duE@$EsxaqOxbLW?A+ z24_H*9LHZ}vDWze(hS|LOuivcncf%!6zUf`oCoTzON_{MFn z2l*bGckNUxQd%idjxGvEs`%lm7b8~3u05XDC4F~%jpSw}Pyb#&g0~otS?ZiEN;LyU zMBOTU2c_glva_P+Hj-W-e{GpSu6P4Q=O`epMvmrgwbkY3NYQwxWPn9Mw0Talm~~4> zSv{B{^KZ~8Q|>mf1YYr+qfg+VXirV-3LT~Rr<$wXHXYFQUbws`Fh!b|I#t+vIstX( zlV)rYx*d@oGMIE`|e(RPl!{Sj>_Dq6Syv~gW|tV&wrZj*|F+VOe=+iDeef; zksy?B$%EKqGuR;H`qol+aG$3DQB~p1{WX3Gn7C2xx6ECI9*h?z3do5-S_!rhhGhXGjaj)80d?P3#R<0gD9!Xb7bta^A1}4H``p z?HpMJQv#|8u2h3S=bOZ!5!k^K{Ayc=g1g$K^Dxo*nhK_b9T`%in$tT}2F7bJU~J$`j`GUK$p#VfD-N_B zu(%{EmvhTpXw=B_C@qv9I4uT+5JVWjk+1+Du7+Rqw3iAoJU z0Z)rCJ7!xYXJPzUW0|=!(IX?}lt5liH#gZFN^}!WehO*t_O6rZtW~xzNdB=O9jYai zQQyq824s!)vkBEpOovmqhW2sGLb{?Syz-GlE^x|>FruAiFn=ks_J!2bdu2M!xo8k4 zr??qM9D&Lims#klr;(v%kG`vxEQv?Xcd=Ej&>tmx--S|=S1r&ztz?5|=@ zq7yRB=hLfrb`&02q$GU~xzp<(MHSVrpHC`(R&%b!qBw{+LCJ3i$?Nc>=k~{@VDl7c zvJHQ3H`Zida=>i&JBu5T;>PSjCm-=<8`akjlgKOAj*?o5vIs(l*{tWbEwOOa3#daL zR|nI<3JRBVzfKS3eGLoSx?K2$cj=e{YZCTKXVIBh@uzk%Df%E>CQIEWT9n`J?iToE z0wZ9I0BuN99i1;PpCSSg9Lt;^Osv1QJ;4lOYt>k8OB(-GM(<*8nNB}{etfNO;nAWZ zL0DpKc8}~*%FE{mav%tr`lhZW_q;tur)R7XFqHcu+OrO?BMxC~6>d+i^u<;OuQqeBy7{_S*Z5$k2BzsU>|)I*-7WKkTwlQoNA5#ehiRq0xmxth3$-J%n^nzal)7I zBn(pF{^_pIgByoV_F*M$C%gK2jI$v zD=vA+kkm5|KOCqquy^1(e;q1`x`e$jT@jQjkV#A8jWti}elxnA;vF{!leG6={{hRt zj97d%8Q0XIye9bm*B&)L5?m62aDWYJ0FLL+9-#tKZB?GNCzkSRhu-50e}k3x06OKM z6Q^{70NJ;nG#gz6YhrVbfX7C`0M9BT)6`{Y%|3Qatb8o;nGb89 zojcUhxy;IIJP4jV5)_qAo4?wc4;-#5?(GS&yBPNZ5yk6RW8tW~zuxl7gbQOyi1DO7 z6AJJ|4;_P5uzUD!D%@zawP4*KH{Wj)Zf?KXTvUBI%-m&sg82Y`W{SrwQyL{x>0w9h z685X29KGYE>oE?!SgE3*Vt+i<`?;yP<*)ropvw#yPpY&g98hOeaPubb_-OZI`xubs zH-d=nha5C#a0atBRO@CpU;ak{dwQjJ=%`1J9Y*0Nv$Q&@`IaeLK>_=uiK{sTolV7~ zh_Ap@b*a-siD%)?r-7;{X=CEvxZ7OalH-5vc-CK?z;tT{lj>!Fg_RvrawTXsOK|S7 z@sM$3TO~ur`aO6Vm(UVVb$9#OyXJ%&qYqS8L2$7W*2ZM)4kB4Aej`+NK^j!Slx6)1 zb&26u9!6$Jv(@xrTlbZ3e ztH)w=d`B9IeQ0n;RbjK&qx5PV0ZWrvuIMKFW7d>~QP5ZN!BLOZAMmFzMB5>!F?YKz zX7Pgdl3h!bap>E_V1-47pxZ>PXiL{03q;(YBPawMPjpKiK)CiK>RGTGvgrQ>wLnV0 zR2R-egb{65z5 z%e!2(+V4~Qz1MvHYWkH~5HcH$uqrYP!?8T0D)bwJ4z^kn!RazN%08K#;1R263Daiz z%)aCBx^A~li@1NYBCpbt!il^f!rM{`0_{Ju&uaMNYwN~DW(-J~VMv@NIVNnsLr1Ls z+|IA}{MY9}@W#(ZMKcto$haz!ipKo<;76l&&N)yNa_+B2@v%WwLGa*m4^C7uyT0%ugYOH%C(*j2r3u+vo=L=)OnP*)RW zZVQ)#+CPrjH+(c1d*fics2nuMySjVwQoZqXSMujulXR? zaPI)5Sv4mToJ6RihVx-&)nIYejk&th_C;f`<6lexD{wDj1$spPfD0jWc!HKynHOc@ z{K~eV(>ccaF_EGrLJ8O(D_M8c z8dZ3@p%ryH+izQZ7=z}gZP=raeBGdZCQ^|t2n=rDwkeo zao#huFN+7#qIMz;yO&MP%9)xO-U+YYE6RZrD3&F7B5=yXDhxI6(TP^9>HAlzZKdL_Zek=i}IfkTYffQJZ2~%^*J5oZ@@UgLD zt5-bqS2FntUBJ|{~|bl=hC>#r}_sL=C_U;I{BUv_Mb3sQ6&# zZ&YkaP;ou1d39{trfr}r1{Q_66d}0$KDlq6U-jk}^i(ym(BmI2dJ5G+TFUR!rmg+o zcnsz*2i#_h>sX?^#Kd~og9DS6UR&f5eaLXic!HpDM%4(C7N7X}FZ=xQO>K3f9H3NI zZ6R8H-Vhtyvi_)Fzi%B;iU=+fm0~oGl_iZLG?zQKz_akk&}s$e8WpXT^{Mgl^Nq0+ zlg8ejk99;(g;96|HP`LG5Z|Cjjw(<1vio36*}B78x12{&(Pi~pt|{I3;Cc;(j!nO3 zwKT)txN1rJFJ~7yb%saX%OwfQ<@OEBar=g%6v-$wjjIx@a~n^i+}uY-`pRIyfzGWD}v@+-az2q3)}Y(Lu>5+tn1jPKlqLcrv3F>#U9uY%uBkQ3+Cr` z#7#Z6%&Ixh<+jHuS#Fz?!{? z#)<{53F;J|izPLg#~DE(C}wqS&)N`+@;ad@fZ6&B2apaO1h%1ejoG)p*)Bp02#O1y z5ex`gndZ0)E@%oSiXLB&Q~b5-OSI&PJ3`ag$AZK@`t$m|8)pIw)EuMzl2j#)qIp~< z@gm!H_%gh_e(5184Dj=4Htu(&f&T<7Yxm#74=n)GRX>7t8cAppM`;W#5$cBPr*+=* z=z=s5S@%|`hFi;sP`6sj2YMywJG8>$S}fzmX;01-&^lS1#Yu{0iGcYj#fBZTee^~! zZJUO|tL_+`e&4MA_e8W`BV>wI6i${oO@K9eSxA)aiP6>M>$1OzWZ2GXtf)#FE~q#I z8@4~@>1&vV*VG&HbC$@uV%bKS2nOkQLLi!DWxnIhEZ2W{=a9N;%N>*3&j5@Se<5E z-@{jiqfsRI1u6&r{vn-Eu#lkKqJrlwRsfU|up8M;%cq?{#svZg>c$*4Mg_wmy_`>V zj=M>_%DIkKFvdF)3`e04VfGJ<%h4)g4-MAA$-#-i8+g6}9)Wp(2ojW&%eh}5tt#_z zu_4xZgdy2tJiqY*SU-F_Re~B~ff2~S7?ne=(W|te<9x%frmkUHYCM>iXv+L3D zFTIM5Lu!oTO|0wgp#()(y}5!H`pvfZ@T0upr8&WY+!aNRDdOjoDrS5x_VI3_`J+UU z*H-%YKbqk7Ey*n1cUN9y*Rx&aTz=E8#(4#D%N;p0bYa|>U<7Va&iyRw{=Ze1YP~#87J9;W1=q@}TQxWuQy46^}@LM^_JGL^eQ%i!!z4P$U z0RYSVm5VI*!|ONEcve~f_ySTu-(YzV)~o&&qZ|!?_cy}5*Hy{ni&*J?Y2|A8dA$8k zFXO(jIYv4eO`l%SAV`@;s-YcvKSBDI>DG$T*EkX9fxZ~Wx4hSLYJ%~6U{2)!fBVV! z`S>#O%}>7=TEHuP;w!Mc^r{!@VhZ?t;<^;$c?ZxO>VLbe@}Y;5^aAR|i2pvsynJ|( z75|$M^jCiNDO~1A-Qn2)~yPywx%U`}Nk-=eq1eMu#IfoZ@kcrFfF3I01HBX`@>Zujsyemes{IK#m4Dw0<$H(p|7O>%ohLcL zEo$fP2u)FJASz8XyI9=m8?Xk4wmtgSX5a%>!p)_G4;V#=w5XAUrV6P0O+;I0YOxsS z10Gx@F$xZHa~{h72jy!+d3ZU&aW-L1RCUBqpfp4UbJ#xK=~LA$C~UL^zJ{7i1*H^6vLAO zDGNMBqwbws!5UwaVzZ3E`q^7iwH8H=yGd%KqOk+n+|J>uJR}HBKC~lK7E_swk z;0SErvUh4F=L1TPyxvLRTmwbFd!jnb#|`%8%c{=@U-5K>z8bH9R^@Lgk;#zFG7@`l z$lSBojbMB>+YHA?W^oBuDNWLt)?1cjj&d)w4~??kqCuh+s@6E4n{a7E$#qwfdm4#N zl$U?IX?wkJqT^A#E|L`jmvO3Ix9D+CRbfg~7rBx~V^19H{=$fih|aepsj;N0Dk{&0 zIp10kCcvYyeQ)mGR@gRT!3@bzoS@N?j1ysAy-0`Qo3XsBYqj`hPQ;>Vp3`tnl@(SA zYqJf>--wuJMX&Z(-W<8r8bOe(EV48nc1g!kWYHS7^&v)bwcEYN8H9 zD=Pf2t%68;yzM}3wK-VBzh7MQdq1$r4K`!~aGB=_Mqva=VD34XSv?Tz0WhWdb()sX zbhD4|p_&&(<@eoKcJ4n2E87Ia)-mS=E| zR|rl~wcGqV#FBTOzS1DR{@E;E?2F^I3KsPRl`pnMtenJURTfl1R9NasK1KWDj-APa z5{$wd6LkGRj_FT%Sph(5FSe!Uoi(~~5#w@Df+Dh-M#~Bh$K{xVNa1>tEI#b3gFCeO zSyAEzGmI)SGOKb_*zH)$uQD#%hiz)tIu4!j#L6);{YsJGU{TqWp{n-+6Pzi-p6oDZWiJ|cG89S@b%t=GV8yS36Y|l~e#ri)C zO)|^&J~|A~46Nz1AHBY2dBiJ)RfVEeil+sUg(>{XB;z!k!q390?H=>z54{?Ovwu>_ zixp*trC33uG!f?iP}ZHGj#=3C4_Q{Z>qZm`B|(x|oDfJhJmh?9998gw&9{ww`qoH; zL<3)s;m~t-Dbx}V*%V@jZJ?yBu1f=g!1{Q%L8he<5!vBV$EB5L%qwa-im^w*0R0# zjDE1$Z+2|&p~khW<6Os<*!L3cNz}8P=C7)>(}b#_5wTk4WAl6b_s;tLAb!2UnXi5W z3GW)_!C{6-7%=CTN{SUlO^w>Cs~S; zC>~b{8op3FHD+@45H|k%POJZE-#oI4Nu8*Ar?><~U^EUFWE|&f)cEB&*Uqj*v9`$= zIqI@<DT?|9gRH5q8OH-IfiCwg60V#EY`L)DurH%9a`u-*>8Mg zbvVz7B0*9dLE&Mh1RqW|E_)%iw(Ih%KH%G-OV(}DNY>Ri&rgv7TQr}`?HlaQ%TpD& z9;_`2^B%!YZu0*2#u?$rC>b=Wv0bL{%e{r+RICs?Fjd&U^Gv z{WC5te(99HSM=6B=s~2V9}yn)XA!G$UWd>n^N5bG>-0Pb90Kxt5$)NTWURLUV*Yid z>?dqFeI_-uTo`GQlKrdJ}i$eoA{;wrtIW>Jv*k#>>u zCR{3V%u=kW!*})A^y=Zem`5pe@jQG#>f>92>Gf};id>Ej+LbXz*owCBU|5{uD1o4O zoMD8pi-9>ke#q5Hs4AYo@E@NVx$B9@hF>f%GX$;T1i`@jRUhPltiT?x^>`2Z(-^LX z5O9X4aao{Al0sb#QLUV3FxLM|+m7S}YfzFS@K>Q{Qcq${od5M$^jT!)hY|!8=W&VV z`7rCg4w)#6?N!*A`o67KTS3|H8(JjuqC^pjtPzAt+`yl{WzkT+`V9#hhZ-@y_f?EH zkT-(I)mA=uc0FR}7#C-KuqHE6Hc#F4^jCe{D7{@9bXuauSk5a+mP-o2Jg&kvJb&dc z1HZ{a3!MSd=2KP0rEr9#1Z;XpO+Ea=(;M8Qd}&}w~ZF+5=S=&4vKgoVD2ACw`gt)7QWfYOs-D zrP3NMtCA>@DtF=j%{t$-q#hXcZxUccXVeN!VL&}EMyKbnIsdM>xy~Jt4G2_CU>R1V z1&R@24yI33x%*YDRqL&5m$U!_Z(w4SOOS%gEB8@71*$i2ue{GP;K|0BOaDm&>al0^ z891cZH;fH7;OBRO!+PRi@VVkI8$P8Wy74NOdi|o0dtMvKTmjb@iBcJY=IJn-4qyME zqWM-jG!37U*D!p~rhmr&9ofQP;7FAeSxV5tHtL_dwnr5GI`-MoL02sL9O$h!TMc#8 zgh054yS@HGQ8)AQjmudyx+eBp(WKADLQ?>XA&*7a<_8WL)wrDV4J&!Reg);NmUWo= z<=1~yzo~jS^;2Y*z>*(~#(vtoVU7b8*1tMdTA}C-tU&qt-o*==Mp7av1Wn5d$%~>I zyleR6P4karu6;BEu(-4}avEOmM(lsvmKDr-Gotc}5om@`G+Gh`sqD(D&DgWgEnS>C zIpW%7Ih-;L$h3%rGG7i0=>A3 zZP-d_^qh_N#ArFGalEDkT-*T>&pCd3{^m~T-8=lgKRMsyQDy%HSN!Z8u|S1)^t;j{qxt*T z;XiIVxaOlKMoJE^i=dd2?szUaKR4IyheJD{B;jIg+=*$|+g|w77FjESQ@o~WiX>@a zPIL#5MeoDr;(c!2avbT7#P1=Mc}Bx2S|Fc#Z^YzjC)Qg~Tgr!!Jli_PRrzj=gxY2~fQ@|C-Swt#LCH13 zNnI|Db1t9i@1`h2RbQdU-_z}rMX#bNuYWOec6IeZJM6}gYYk0fh1@FY@C=6Y05<=% z*XQ;>WnlVHG?)}lyQD(5M+x%yz16(y@~lMD7w4Z!waI1FexZ)IYsQ#@;m?4+cShNq zk_`kq3t}TEd4AwPl!uC+VMC;`LbNy=CR8r4#h^?`3wi$__T;&(53ZnM@W;|5g627q z)MQ*i`D0B=aEB(9@qZX5LaC*c-$&EZ9K=@Et}%DiKM^GeLcm!@V`Np9L|B5D(I!;l zJ1{phiUe^8yQQ)B&wY6j1FTRy%?k`ov5YFA0<1i?!iuQkb8PX|clB7+3TKg_PS7;W{_JfL`eAq#Ut(82*yGmRf|}t2r=z1g&+T^+)JyMo|IuAyz=oxTie4xY zthlOgv2lef6vv!q5mc}Q5nxI4#(C81@_KmkeT7~XHvZXDBUTyjN9^{O@7;QGESTB# zh77%olN>2fGRYI-={-~44*1B`E+x9c`%ix;bw*Lem3CjZT7JT?HrZEoySvB@KgF=G ziYW1_K+!zUV8?3pnl$}P##0GC8T%_neccNQ8iQrls=Zf~7Etq0RmZ=oUmBL^`AtnQ zp2Yh9%g_m6c2a2n!2jTRD%Ahf80#OR9&b=`Z2?dA~*XU_xT6|TX#_A5)wP?dj4Z?R;pU#SOD&!T8S6M-mNshg9 zXzJ>cXC4p7ywCiCC1ZV_Tf!sF8by_)HG&dlnbO+q89w9JwRMZk8h`sFJw#o(NcY=J zLRR+&wu>HpuEW3|hRN{=pVE{V;!KXE6EmiYGtx5R7sSDhQ0U=;;<1_@Sz(gn4UpOfyaajDXYu zHk+}k0zh?3Z2$j*P1*DCj2Gts#%#6Kh%u8$h9^`~EL}(4(dA?=F|+nKiC=i{z1ZGm`6RY>QGYVOb%HXXRsH4 z{{7sZnP6^57&6@oORyZPaw~(n7r@!Bw85Zn=AUZZIA6e2}P0 zTZ4IUrMm4B@7J64LKS{a-TuFYzQ?rGU(B_Kezz1>JnH3M4KdHaouDD4XaoU=0siH= zgX#b2`R)jPNmXkv%=oO;$>=T}Kfaw8Y`_E0>$;O`ts(swj8O2-sarASzphuX!(yEO za)HhXH8;+$)A98;{q9aMFSFMN7tH_kJM%ya6cs;hPYOxD)5`(rTe=1PffmO3k@{xy zh9$HeFo3IyfI_LX-<1}?{J_k@8SK!B-D_4kTZAj)N~%@m{5)CoyBLlYIF7{$R>Wa# zT)rK}j{J*ZbN{{X?sm1pwQ(g?Wi*4sN2qI(jCEw7?0>PHLmRbvtr_4M#uk@6ev*qK z$j{}b>m2KsB!dq+T0>J5!2fqdnqXKQEpI>m=#qoYA@QsvXUj4{N4a5B3e+AsZja)U zCF<<7)#=&uH>XU6c1S=GRzwkJ=jb2Qg1%o2H5Es6wPAw9N&vvceP}tUm6ls77XGvv zk2g3;_yX+I`g;mAU*P0-7qqqiR8H+h8Nb9U)`0YT#Ct1ZRJ$a{*iQJpXx^}u6;SK7 zBo|yQWCyf4{_cGp-oxG;t=IRevTKrC@#nZCno~4d6L5(NxY!)ZNw4Do%*p?y#VUs< zJM82KM;^hl!Zj@=t+^+tQ+zIt#Cd_EC7L71)wMlq*OgGX^l^ly0ER-79NvNy$FrSU z9&2@5FD1We2C9m5$KUPWpSSW+(48044NoRGj-q&i z=T$|0g?r|KYp(s)K2RU4&bqp#K%b6UR|fy6rmwlTbyZ(-qu_%hJ}iVe`wkL9W&zTm z3nA;JVETv7%>vyPHXxXC`rh-&Tfx+(@6)1AE5UuM1ManjkOHve4?wzt6S@#GQqQl{ z?Xy0+E0|JCgA3tH{lfW2t)V3QQtj8+mZ40#TVGVK>+|l_k#0#wD2aatLho}HV_{_& z5DN7aC|EQ|SebTPFntxUZ+iL?R8LiFZyJO*Zpgb8;0I_ozz5J?fCuLgWCgSj%=1f- zD(rQLoPI}z;%9$dH-;g$bTA&aOk+F){lBiIv5IbA_0W1jeGhC1=A~ZNkpACpMX(l` z6;nRIFR+e5Ibhv_`A3xt;|C0#qOiE*qTp-1@Ol)R-r+H-np;KrAJ8{I#{gXdbf{?= zStQsxzz)qHpqpTwf^|JfUx5E0@+f!`%CE`@-3P$;V>SlU8?Q9ZquPf8pd{OQe`ZK| zk9`$1!PsxJhNJ*yYQZi3-~Pc0Uey)&NxF*wNVoP5rdI*wfKGsteh7XCy!r0}N)SCI zl0)-gd=|f@D-HGX&gpSx_v`!Hza2u~19@EsSyV3QCz!Y1P>>cdZ{Ya{7UO;R1H`<6 z{VzK;bbo*W?Bigc1@8koQ_B{*Kg@zsxP7Y-^?-80ci&h;@fyHayzxFYDGJ~IK@?F9 z)&Giuo<9cDr>BP6e6@p&&A@MG?a%L@@$YM7r=osfj)mJ;f7e4r7tR^0pMoNgC^Cd5 zi6lo+V)wdFfBwx$UpkPs8bKrym~1PMo2i0uJH;I08~KyQpKXp7jEZG3g2E+|)CdMA znAClvUfq5+69bab$Wou$IUNILzA|IuW6dEQsbR<^hL?GcB6*4Ah`S#B>YYa-IKBeo zsq`rS#|xT$3r$H7Q5U zyH51@)O{lxtZ8Z=l2mlEf4wzEQLu(%(}{x}T91fmLaE6VEy@xla6Ac{P=384sN4GL zzF?KRYd;>653jPW<3DWuq=A00A&)S+r%@&Y@vu2b!Ns7z+2;OVw)>&k^dkSa`&-7A zS}ex-YLF`=OpO*mYwcbrpM}s20f6ll(-BjE(myEe#yM{lTrW-_sD% zxk92k$t#2))1oZMZ=4_bbUHPxh^4BA(0WzWEln2-P+JAuKdYsQqt^2C@6=fo*~?7U zXbzWXN)(7NZz-ZXY6)jKhMu%vbN_0jw-m=vJWdJ%PLK>v;;=Hu`9GcEPel>;=8jt@ z5B%%D0<^w}Vg#O|NF2vmh7rPozrCRAzdIpf+%$JQvi09P-y0TL`K7Uf#1O2e@dSI| z@Ktq7D!)3%xKmjzEgb(m^V+KBE0MNLEJ3myt`Q_9sc?uk8H;aYv|3s@YQKE=7gvnRP6o_SS&uEN z6*Xwn=IZTJ-)$L=wnjdq8c9nGA(0|0hTRR1a)v8L;P#GLwO`I0e1_4V7+)kTiiAKD zvceHEA8>7-BzhHJkNiBpI@y2W9mVZcW&eSejSmG}R)Kb|A0jR52w5#19D}EC>v;QU zaJTyVD26?HEbMXDp0NjvL%~**YYW|i;d~J<+az*YQBXW69UXIrv}bZo1IwV9s6k;! z#x>YopnBYS>UD*_3%FF6cmMyEyscd`F$JvCruo5io7FhACb$DO3*mTZWruz(8UZci zWaH2)3_-cF{a$z8xW0LcI=Op(VV>ffapj*~U%Gm+1K?iI1f@mf!y0-BYtz9}M4yc{ zESLKKgyX~Hj8;$9j&gqWouD*6>@2rTyw0K3r35pa&oWTu)X^nzX7*PKg zukl`v`h&Kgz9$Q)T3)=zsIQF1%A`i9iYy5(IY*Tz^mj`^7lR(6$CKY-Y0g*v>9%<_ zEhd;yWucxq1SXhZf(a&=P-@6bP&wv)Y=Q|Um|%hlCYVq;psZKg)HBDgQb4`SeB7Jp z$E+*OC0!)|;OlYP919anFrjo{(hrm0x|H#ywE9;RKlqKgUQDP2P*L%Xztr*l-b-ZM z%*zu@FyZ3EXXZX?f(eyo9o}gUg$WfPKb999u44O%)kLMs0+P)ks1i_BFPf=#iOs`K zQ!cnHp{neMw##%~R@QN^2K{fVB<*}(r(?I9Q)hw+34_h%x-!9(D@-tMU(S5>*Ws_)}fozJpX(RN?1 zcoXaXXs&+~E~ow5?APT9NtLu+wgi3umT6~SDPdR@$1f91s0;w;n~Be*(+`*sAD+!L z`OM22%=;OP!SsJN;Zg#VpD3U4M2%~#`>M&em{6JVd%C&Ln_$j&%urR=i#1NV5bHQ6 zdOVU$6t0vo%;YmKDmW3(CsguvRWHtVnh=DP%Zy(#`LrP1XbwSzK$|jtpM8mpL$-+u zhR~>zj4Rmp2UgN?N|b)9UnS{JuLSK^J!9P8;WQaaQ=)v|Jwg0KN}S)9mOmjbGQVs> z#ja};OfVt(I*aBv8L!@@y!141J4ckzE%r#{KJ2(#8{Cy01oQ{(^wcN2Jc`#v;EXF* z^s8RC=y6X~&!0bk`s4Hg>7XSY9HFIws8?3Yb&hAcIG(&?VoUwW-r{m4&E=X*GA_~U zb!qwDUZR}iqH#%)L`jommG9I~{blB1tD_F0$@VDE?WG)wYGr)Ceu*h6sRp)MdOJ>c z+mQC*MliV7CWQ@#JI|jV{FO`5w9At}N%ao)=I0jpyLrcb{cz@cGY7Y}Ddsx9q`_4B zCKigxQ6I{=4Vt_pXh+)GSsa%t{7 zWvD7D0}FE{)jL2exY6tOtG+$=-~P**F}pL0#Kn2BHJ}|dXyA9h?ah~-T(GbJbnphp zkkyki-g=ip4`Hy449>X*ie7L2BzNApY`-YEJ#POLm)kek>&|ui-4j*cp{Y-wIq`RD zI-*H=313_z93K|m-r?69z+OMtU~I(#mzwAIx>cWx!U>g>aZVCBdg06gHE-&B)C$A%rbtep37TgKP9SK~mT~2< zo+FQ?1L9lziQptDwT-J7>9}U}*RLrXn(6t;9m9J|Q)F-pA2y{x&DVNOF7Ph-;EfGG zx9VY8n_|*s6HGAS@&*?mx6t$239hI6B|3h<(4b3bz1u} zo6nmN@>sJ{(v{j##RW~+>dDei&Y*@iqb!m4>iGr#L0CgT-tKT<<`H-j`x_k zR7^0zq-&KN%=4-8g=*#ym~a`(BgN+0U+%`g?w=2w6AX;gwLF(fYLZ408qUdT*SfD9 z`k+C7E6O!@drD{;Z3S8_qaAB*9ChnQUuEh~=2?r{;Prb&S#^0SO5-U-k`#(n7;4_h zFV<~w0up)64OYVxzzA#c@nB%PNrz1T+uRsAziepa{2WW-k&%a&Xi}v}S>OqJZ0dc(c9cLKz>ZIa(pbs&7)RgV_H>)ywY8o%a16<1aMtDa z4Jz=v^YcVcj~vmRH$V-zuN>O{tN7Q+J79b$@`)JrbuiucRcL<4m!;cltQME!{mkKA z_q_=QY@XqOiMUA9lE{#f%zyjsh(9|w*plK%Fn?u>yX~6e%u9{Z`t1kP-_9D=_9DkF zl9dSxCk2MnsEz*X7yNa_4hPU^XOyxh8D;!F*7D1{+>(xBC1=5E@i= z6ntTXHHua=MHE<);ePjw-#v22*d&w-+q$~3we(fQd!Jb2D+l$xCBjIAy3BbU_fOco zcjE`ZOX=F;k??v|k1G09mscYsMP(&Hlr?Ve!pDX2qkL)Lc%lxJS`hhS^!7QPZ`b^| z^#kBbH#2mX)?6vQ=^nS8p^}uKQ)TD z2!?dBqrvB`&ffA!U4w;`r%rNtMM}gOiB>69Biig4KI7N5b?xvO-+pVXC^*Hj(%$y` z`}F`$l<*@io-a~kHBHnwf#Y%5ulSBl$%vw-I;y{tyYS1L`Y3cGX`CW>fucBp5-0)2 zwu$->twc6{nxpfcQv<%cAC1r~$?`165-cr{0w3lY`N=E6ZY)ScA@p=d?;}60zJl+d zKjBeJl%QPQeExy?is~At`dyPL(KRVY%^T(|RQHW+u%@YfND`Rx9}BE8&CYbkf$4t~ zD9?j^ILmnd4!EK+gd!7+pb{!hywaf8v~yI)WZ2_0J;B>#dKv$RA=U%#Xx~TQtmZoM zI*&iL;r{@Ys+MZV1@n?9NCD4YfqVbY5%;+p-kbEMsq`?xoR>-uP0DGWYE%(?Nv+`i zRo4EL7SMagT@KGD4>$O{MZ<80sbp*rQNksj5(PmZV2_JkIrn6 ztgCOHpCYq8`F@|vt7?Tlb+9`xPgPQW-u0P#lrJsJEU9i}%(Ph^cHDFKBei%fvZ{mD zR92NGMj>grvZy*9c1-AeD&yqm&Czm{SCw6p+=@TP#SolEX*46#EV=N=P`=BW>NZ;x z^e-NyM;xBk17CP#O@wG1guoCSgX1_$;sOt|oUI`W1y}KiqyO_W3!a+5qVX%2q;Qv_ zYVJI>zgxO4FWWsXPxKdhRo{ibDMryWRTM==V`1Eb1%qPTTju!K*S^M;M8j~oBSbUE zD5A)7ti;l(`$n}IXrEKWcXh08Jb3W);yNF9d_Vf|AD_XSYZ6jVG(X_P2YqAYV$ z8^2WNvvwmaAU;cJV|F@A`F)~dgqByVQD@8wtQC%-w=8RFUDp<^z{=$~mpW1O6pDUz zXknh;ovRM^s)}0{{pyUPEB4Oo>`Vv2_D1TF{7BuX_-|5Qpe;h5gLICmnn5xZD5eQsnw3DT?4}f}jbO$9W=5M{>)1!Lo;B8dve8W7y5su?L1n z-ajZ=)KrdS1X&G>J<=RK zzQub1&d`D)s}jXfB3y+HS;Y&Eub#hW*Y*jZilfF_Uv;ADo#GM&mKGURp$SQ{&;B&O z@w|Q3Xm@K)wa4~+s=ajO#0ubhxEwTh^rEA2^VM!`bXMe{2?Ql`NhB@dgusY6ug!eW z|Mr?g3y`;twurOkEz0;^Y2QbW%*&2FzFJ527VULLF~w+Ha25JgZ!fPm-`m3@`h2QS ze5==vl7ZSRF=|QBEqTN7dzV3f9K9yW0Wzi1k|2?RNvhrErx%FKIjNvdSBwlAYTvP0 zHaeafQ0?);d0+|Ew?K3as!o9W1Dc)gn)^9n6zUm*eRzGyR)zEnvNB~IgcO8H(~ zbGGY?yOW?Jc8d=ZkcR8&Z#wfde2mVMwhnE>7Ck`!Gk@#SoE}~8Exl76^@4!=h=SV; zC$u57g?-&3bX_aD-^Ty+!~e&o24&!vH|ysQ)=-hf-{*JKiYgAJ6DgLVx{(0aJq=%vz)OpR>lalD6qQo?oxvW&Qby z`N4EUR%rPLdIhR7xW126?~DmXVO-nI3P<5MDL-w6d}0WzMiV64D-o-R8N8G?WxM1nM?b>`%K&C9rY_nO;XEIG4&J=&by8y ztp>GC&5RJ5voOz{pXc(besP?Ol_`PeD2d}lvHsSEJ)c~=1t|M1n^$xSspQqTXKK6S zpS{VpBXe4z^$x+tJl`GXJ}1hR5?s9V2fJY2aYrN6*=swh%{G_8JQIcQo{+^ zkmlN=q;S1SmK_dh>gj?*9|D>?6EmW@tV#>CB5Q)EFbALR)$iR2i_`A0#X30>3u5#nMUYw5JGt@Q7}CYr4e+E5hwR}$^$`~)#4m31D5#@Qc0mD=j%6zcg| z@shVoWPZ(gy)@@FQR5LW-c)vcscQ3^ZwZwd%=tFwyFBMRTK)0^v;|F7~ z>Ldh)mPlIQRgFVgbuLWsj4dqV|1h+KQcEenk3O&;IeN|7j@{b|X>Uw%EXh(h$8Z!! zGGQmT;+|l6Daf0WK6ae%^^SacJNj^#<5`}^DF)|BhUddfnin{uDS19|?EU4Q)wlTT z8ZQK%kF*ZXA}uZUJI=1_(rM;hz_Ms^xTZ?CETTDAwqKMd^i!w!T<$!#KUkG_koM%1 zK1<$M|89~Up*^t0_&k24-vLLhoO$yeogT}nBFzXqr*IrCYD~0KMVm8}K0R_g^3Da` zhrf#kb>qD534R}i^ES(2$H(`K&bCbiLBGb@40OdD>GG;dp{xcK#XpS9&iZR}U+Z=H zH%*}w1x?E-jTg)tW-AuJJT;1OFF)+?Z&{W%@MhpsQ9@6xnIZSv01)w9Lrg|>Yur-!mA6^ z2JX1TT|LCYaXJ3sqNh;p>Gl-_Ol{!W@71gA8)NNXI2NwWo&4}-U`+I4iLUC7*0e@& zf~HBNsPJu$-M;>}ntTy?YX4Z|)KX$Qu$ExnZMM*{?*uh3QF)u?n4{r)cRs1~0*4Fl zhuGo!Vyel~Kt71L__Sc>B64LCdOJ6Iz%Nd0@+Fej6p| zJG7DVca8_1I^XY`F$S38^NZs;6-q3D6AVGow7`tZSv38j^xWzIQ<}1wA*ob1xNtXS zSrHTXgJVh(X8nFAkR$mJoq=C;=efKDqq2g=avILjU;Q_17L)#NQFN0fh%~&WpB&u! zft;Fzy2O`(1-vw5Q9nD{H+pC1A6<&}(PX22l;%}jB5;=DReaXb0e@l7%(dNDMd^xL zAMexp;Cy*yF#S{i|4n^x7T*<2*M1s0;j1?WM-#XgzceRQ_tkYr4#+8(?j1I5ThLTb6u<9{QQ?|Gkgx< zR29MFH!pKv(rZi5eS1l=uRomNZnpNyF6Zlk{q*M_KOOh)?oL;XD%vZ4aSXfvs--!* zbji+=gH&#@u52||%=5eD!QTAws_b|9rsPWbp04zd{l2OH1%^_WuiaTT1v!}FUmV%? zr#(G30R`gn;+B>m(zK@Hf~+V6tE?FR`J0b+{wEziM}SYdI#%$c6>mJhJEUqk=U(0y zakmt3meCkll_e40Ef37iG)%*5`r9G4t9$0L=OTNkF&fJ;0?TTIiZ{D%_J)$-F;e61 z-C2jd2|lC17SU0K;uMY%a8?v40p772B8xufSlP$%nDC*#ZCUyxBe0fa1Xq7guUxl3 za9XA07fK$rM}C1@_3c0ZT;_ZCI-PgwMd%dKQahuVrMj>+>P4dh*9_DrV=`o73;QSz zEukW?7{qD;FeZu!cu$o17^|222Gkw`T7{i#v5D*eKp>xI^%TtNzxL2A78dosg`^D| zG?^A?Tu{PI4b(p$08v2i*H6&h7oY34e^QP@W@d326?`=AZrk8tGe}0$V&R1p_vxK1DCTXGb4PSkFJ!0Iri$=x&b?~=k z9iAcsa@EI>wyHcyvA9Gi1Vhzs^V9jY_G-z1rW}YOiXT9F9{=a)uykt2lw}RV>n^Su zXCz)DRh1P)dg|w`x&_EOOwQWG-EFJ$o;uqGb!#8X!4l8Vs;Y5>%rI)SgQY%DKHA;4 zeGuP8gH~mHAAOi=ciO(XVPcb7&hU{@WEa6PE-7D`@D7&wx3 z5i|uWriP^%*Hv70J!b)aRNI&hG+;Ss!vmaU2!iKvQKHmpZ>}Bp{HE8^fs1&o$99Q& zuW5pDpkEZ`#8S@nq4iw#opToMS@)i;0dn#KMd%NiB)B9~jLc{fB@>1|B!jGx)9`v5Id4AK_U9HS0B>KyZ3moVF&axNxG1rV#=+-U z??*|E#x^NrY#Tc>p1-2wi@PKE^$P;e6AVt01WVC0Y`U?Z(s^iPADcS6R@;zt{aS=J z59eXoAQL%F?VK66ILW)eX^2)<2OQ)@5~q1d6iF`3ooHgs&@{Y`&d#ga(&XuPfayS= zy5S0Oh9+H#suuLRC1^Tu>)>%+w|$*f{joS1?^yr8SWwz_C6{ygCYW$JLNX#nt*1+E zeI?qIuB>$MQl($EGUAmj#L;Zk$m{%pV3oi}cPSkPPbXUn2T^ujvjX;4kY`d-S} zd+FTYANwVu>Yu>{MH5wpXK3T_QT1$*Q@CE6g>&}XxGnX!mgq}b1cDYAp2cZ~5GXdx zFLRCFw?>Gran63D?#oZ%fnomx;f6FNLxQP+KvfK>i3%aF*?GTnK;ySEfDLTn>s1Rc z!K`h_yUb8c8~lD2q8-2%{zu(nXt#be?|^U(7=Xa~JYKg5 zX{;NVNHvY?0cVh?GrZR!1HNB%i;8MGE-lud!=?l9xtTr5xZm$W@8!ifPvFQExPJiy znCGDPz(tRXq11#+8;YqV@64G#rD?l&TZU8VP^&;TaNX36Zm)Ws+oQS^(Jzjsx~(p0 z?Ko}TiR6-Lw90wsCr50zPTe1IgHQy9<~UJcSXndNAX-LA!@JzYSuKF&08PdiBXE;G%2|+Tj@kmCH z5cCvxcQ(#Gl{V2{6i?Cc_9>huRGN@^p4P^^Ii;60j6&>L-JQ>N%{kSw6>yapc0B{+Q7A+6PAc zn*>`ypN%nU8)#ZDXW`Xv-+pRF#G9K58Rr>|6>x&4;hUS25L7M+ITqJBdmkG3&3iXS z^r}&1oMKo;5CksF5B8p`j4z$N&iU4lKlZ+3QN+H8yd-hFCW#u$!+ja|OR&}32L|)Y zSA^!nQLwM`j~6n!|F)rNIQLqjN?9auPLf%fmo9M4b-rmy1tt%$uz;6!AY5Wl{};ET zpL2`$^8VLeDB>y&Z(hb#Nnj*ilm(fy_C5b;+XlxRF!$U~$EZ$Mg{DruL|RATtSBkq z_@C9=Ttj~j$iu(9abHvQ_khnE@Y;zrmfnm?Mpe;9sRNz(5~;<+2@%m%l_XXoSyEug zu%#FO#T~<(s~jF*?_H5COEsQXc!p4DmBZmX@{*(0af9>OGqsK#O9tASL*WX!TvDK2 z1s*YPs4C}sl^X*3xf{J=flHPM=iNCcI^49;@qgxqd|3f)HOIh&st;(VsvDgH7H7UN z_V(D~(yAgZi<&HRGR4DjX}6Vet!yjjwHD2g)BxN-BfnP0auVG>v{TL~=MQ)8U%0X; zmaxHwnJ>k{Em+5)Xi^tOAyBZL*akO*enb+qXtb;tv zBM6%3c%J8J0p|psf)DffSA#8FXG3uhW1QOggDKw~0!>|RG2k9JHW2#9@0N#6DNysZ zZh5{*s`pW0*U=wt`_u_Did0f)3L-K^^QNwuphZ&Lx0{{&YTw`H)h^&ttg(iDql1!Q zugL}8fvT$bdgSN%)ye)HNwYfP4Ys5d-OQtVKY;)?AQiR;)A-$CMd!wXW6NvSM@G=) z1xgSYj=@Qu;=(8Q;p7gsl4&@GOU@y}g;N3qZ zavsg^D9(&Kmc4LhMdZ7V35q8ao(M#|VPn07*Je?jHGRAPsquKExHAe)u`){$6ff{_ z+!=5LZ--L2Ce_)n%dXnjY(?*Q6iW*P$4~^$b9A`l=!wO_ZG7)I2ZHQs&imLE6Zx*4 zfubYXcvr|33%Yy7JVjLod)>Kizk8zEH_xwneX8tt=jV-F`_Q<*2h6cdzf34hY87i= zwDt~x((-E0)lj}(lr&m-{Yt4z2hhvhEX#yfX!@JuT|^Pi7uUlfyS zThGuc8tP{{A6Y}w@Fo;EPrUKzzNKG9)S{AoI2n_ z=lO3|%zEfp#Nm=yn&DNE#Cbk!xK=`)`6x=%i6qNJ=bvXzH^mBp8QfrWa1_}k zuv{>v&uHwYfOQp0I;P^ZTBuf3`=gEXJ+)_mgR&e$yu&F;WJFq)CFa6G+2;OVw)>&k z^rF@PnLJvGlHt+Ba+1C?`@ohQ;*rs{%t=SC4U#0 zEv6(&Ar(dxXZyg~$Q!<(s7-?r# zXc}F8Fvr=aaQc*qL&17|v358gOW}me@11g8p-=6br>K*Ms-ohOC49oKH=JlOZV*;r zx)NX3Vt$f2ewDgiN#=Z9R(N2}lL_X0n_$kn2_~59p|tHvy2$NFDrb2msg&(Yy3Fy$ zlxIvZq4EOy>f!sG1*02&x~ws9ax*Y60KqFshZ`Es$_y!}l&FPS)X(S|?B%A% zEruyvq1AG~^UjeYr5DG6%Th`lvR%-)(qxFnRnE`Nb^GDS-EE*WyqX7`JMzaqIK_&- z^p=)bfhI^or3h3YdI0;Q1`1!`BoCafdv6vP$eG2}6|1Nvoa0!PkO@MRz8Lgr)0gU3 z&%mH6_Ct5LloinN?H4-J-nyn;&Q73C-(1t6$uv%LipH`6r4TMTfR-104+6G!T{e8T z^X=Mc>A2q1277}kP>8S6YhIz}Ym`_bC83S}9_*NPqkhdudZUV6!T<@LK>UApN96B; z-Rd>^xPW6X__mT;QjGgOO+RnC_La&>;?knzqdhP0`7xnl=Do6ki5DiGm~iRBiwQ2T z&ZE|Zl$)jVJ{RYZfBfJv!pAp z(BpCYastjYa*pbA$rAbP$mgqnaM+d#bTdG?(;2FyQIvdVD6LaT2NmV;yv(`#iN79^ zn*a;b`e;*aiR4K}AT^rMr0)+7YM&?1N``NY9+u!uI$C-0)(2}Ttbj*^ zR~k^?@`6l|B*BP`I6Uv!e>*qWk^;u>Bc00|4e+=|d;?V6mZzNW9DV3h%Rj)3cyV}J zatR7|O>+BlvOW2e28;fjz>2)>=_%b07dR{qL=86~@;4=jO+>8_o8=j&>z#$o*RKOp zibtMOTBC7MRT!ER7&sq%1|Gagio8oMbfEQoIv#Ue-9> z9e?hAU|nW-FLcL7lE(Q!*dd;#h%mRtw5SvRtn<&~$5Xf7kM=$yDVCrpRv;;y;TaZn zWs8KTPeRT4sP(tpwD!AwdwM`C5!<(?dx#+IJ z8(%ukh4&I1IO&$}6z}S-=BZxMpYQECB~Q$C%RSw`ffPg+`rv;roV7etPQgIR%Rv+L9k}df zMiEdeOPI}!GJX%H>0A8=*cYykvz#%|5|*Ix%=j|&{pNafk=@lpQ!wr{*nAQ5QIeuw zcwa|u1yO%ijQvQqm|%hlCYWG?2_~3eLgj&C8EuR6l?5-<@;T6=Fpl#KBakFPP#i&r z1>)%bT#)A2zRl z8@4*zzw-0m@6$miOGGaW7(xmH?0HW8+iG$kpdAQa*fvTU4cbO&pw05Wv-Rfnxr=LD zqd$2+B}`V{B@^#}yvg9UX-95>jT@6Y#7DNy^Uo&wc7W}a*8iGJCR*D5&{nqWeC z!cFE7To$`oGyq!`to^$Y@jlSvWMAZdz3<$6G*fDipMPtQ2jaiN)OTF**CJmnx^(4NkF&QcwekM&Ti+_9kaiCdNAnZ zW~1?=1PNC;RuMT~>frmJ@yeykEBuHQ6@%IqC&E}QA3NXkq`&(20d#CghN3x^Cpm_q zXjb6hd0qBe5P9xHR`H3m`?T##eFF`uC>~XoAw-(z0%t%9>{(JPYA+5snarb(SNb76 zODIL;I9!xCO_gEKl6r9tn$2>=+49HhYi9jh6i_>25OhgY6@nrdnUJMr8+X3^gtXLw z(honJ7Ww(ZmCRzSQ-Z!j9X=m%u5s$Y%M}Ib`(O!~0s$;UZ7*$ujLyR5@Q!v(;QN&+nE8N#j-7f8kG+ml=u|G+N;C z!e?9jHlpuQD~uvdTG-0e%1@n+EmL!z+YX|hJrLeTWlElY^;2HHH}`^cbi<2>y8P`q zk^*LKUXv~t(rGPf+DfM2IY`S-g8kAt_n%kX_~UFi9YXIg7yPSws+w5n@edZgVs7_* zWlA7oJABG%iF(R;)YT166Pp$E4U+QFWkA9SuqxXw}Zq9=*TANVYw_*7hF-vnJ|;nh`C z-({3feW3hrGA>Sko9OD8I@VD64zz1`MyT8fr`zJxe>5!PIDz&gimwIjiMD>=>p;Lb z-PkvDoh*miyDKBH@^3U)nqfT7Rz!*d&@VWR6#zcPDvxqd`^!3?4H4~uQ&hX7!R=5x zqu~#jcSj|Y*D?`lGempg`NR-u3L;IE-k=#G-wg48wDHbF@O_OC{fd{*E-PPYL!_v6 zon$Frx`R53O%(n%g7|?(h%_4CkQrnD%ZtyCc4Uouo@ll!88J@L#xoi}))(>J#gdy) z;~H(>tLV#XlFPU*GA$PuE;gT@Sw{S*EMQ)mRI&WA2_~3ef(a&=V8Z1FKu-zu*{~IG zRtXs?-QatxN)<)tfg=^o~>gHTsOpXsq4i zBz4*0lZ!kQrfEcMq9zFLVVeAy5DC&Ck+xkqt+Vo8x3$Xn|K$eh<%CCo{>;-;pmGB7 z>>ftYB|DX>sazAxby6Am)yox+6V>n9){8qYNtfApSN3&M1A39I;Qk~EA3%&<0xCD& z^1*)kDfD~=^uIm9^R)&_0W?bxJ+Fz7_nwOK-R_IDK7jn08fU-Y@rgA?#SW82NC*sw z5noaGQ_=ctlP|tF{G|O79ha(#Pj(ZfE7iQ4^I?JsCIBc7taRMDYRJjP!|p~#$)jkJ z;02N(c}Ac(GAwpeo*oA48{|De-#L%{_t@=621JOj%n2k-&;-wsltAHd6~bG=^cO@g zY?dFKGw=R=Rl%s%`jgd0cgyiaFy@u2^!2OWz+F4p1zuHD#$9ba)AyM>Gdd%PuPsI* z9c$=9ls}Ix&i5}>sE_b*`oVdv<^S1x?l`B4=aXEAyGx-Ry;lKWFQ6z@$^l1_CK6uR zcNe(3oJo$Vw66tG5d{$i1S|Y#VnI z|4ioPy{)sev$MN1lRtf|8$6X1)Yih6V)cEUk7*tPyuIbHEohTKq5;<}os29s*!Eph<$vQuKzY z`){9kWNi??m$wx7J(HQdv(x>b!XX+d3>-r_^WBo#(c8_H4>si0Kk4^Nh$`-*mIiQU zawv`kn*JSUzR;?i%1n^H8eDJ>Y~EQBn^$Ccf@3IwCsn@9>L-sbJi;Yr#+lcO+bdQm zCz$@o?D^4}@kM*EPCo(9s5Hf@3_}3a>8Dq3^67DA_ebW~_T#Vr>Wg|2GCM!41VFF? zL20t4uugBjd+gDnGrp*?e7+Ut+9n1L&vot3uP=V^VANbi3h*K;5}FK{h`D}hj*i3G z4(h$EcSDVFs6eeCY`M`M%J?Z4dd=ucmsO&f|48@PEPJAw=ghClTe z$Htgf?B=p95){Pfb#GE=dC*0H51|t<`Lww}K96O@d@at?2&foD+&G^115&IDsdktK zgY!r$y?y5B7owlkt$_{ohJeP?R+#csl#lgFri%;4VTIB`O=O%D>-Y_$X|8FgbdBe4 zfC1O?_%_DhwISa=*CX!wlCG|LU2Ir?mDJ-4{q};b)#cH@@m^+#*KZrtZ`YNQpPL}h zafc~#G2dVAA^A{iHR|~e zoxn@Vb~e+r`s5a=I+R&KF}y|jzaw9$C9P>ZS(G z2&_zM6eUOix2aKV$7PXVwJcon^RQVkGE-3K&!E^TL?Cub7s)3La)GgZz}O)(>wNO# z+N$TrAB(}|#eWu4vh{~o3hLKejg2G2krXWmEXnZ#O><#;k(J*Lv__MJ$T=ii@13#j z^k1(-zKLjbCTNP}Sf1rbg4;P~kvQr$Z%QIkWf&E$Awq{Yeunk4YQGfCIt1<9Igzqd zWl>QnlHoWeU|p~JU1NIIZT}@e)9u)gLoo{QdCwbh<*-@R1zq1-SpX+}F; z*7DMjUj`WbbMfkJj5h-eFvhI`1{m|S0R}%AVDL-Df#Ea1V!;RpX7r~41{iQ{&$kyV zKVv>Oz<|qFPl)y0*cZOC%VmxI6>oo9;`~3BJ;~sY(zTkzsj4f5w!T(29_&*YpqD+L1* z|EAXf7t+pbs$*S0eA{EcSB(-ik7apIWO$JzSVrVgXPC`(=aC;`vuJFknwxDuoQxjr zOk;RX763`ew1`GK8;%LET#`o<>vZjw{XXe>}=g$AFrTAuiF+tDe| z8(-Bpn>Js^O^^x7p%-S>MV`1|dGgBmeMuWOv;MblW}7eXhYqw?Cxo?O0ZsA&|AhU) z9mOsW=qxFDpu6OK!t4CxmO@vW#}Fu2HPn3|z~23hrnn-ZWVE-mu6pJB8>&`=zJ(8l zOJ%>OUN8oD#yeGtVOd4iSe_y}^=kR;v*U)QSC5fZB7#f%e|az9(C@M^#!$1VmG!Q# zPR-&rM|GABXoY4eQspRx#W~A9o`P%rHr6im&7ZH_Ukk50_#=Q)yhxEG!)Y>k`0$WF zuCKWv38yktEoF05Ei>m_Z(X+cm-RPU8sq2lV7*6EHG<~_z>y@IoA>yN&OyqKJQ!cygmvzbp)0d*fl>V$U>sJv z@_oSL1T2s#g%K2y?5;%~v!r$IO)ov1$H2K_3r4)=OTOMxk(1$gj%0x*5>i7 z#S!8cumtDy`XnDH0ENCBk9!R8=6HY?6e^(CrrHbc>bxw2Knhajxd3j1i7@b*9;#%f z{{IN1z}3hA-rh6xk4(LIT9wfEH!g~tPtH|-^$4~D+8!kup=jOK z(8sNU-fp!xALMx4MZn`5Kb&m3euw2=%Wz|F#sC8hFu(u<3^2d|11=gQKV!bC@-e^w z0}L?0fXfkrEvCWNV6&;6wbAXiZ@;wScRd+`Cs~f?2~y;EI&9Z7G4N|4)@0YoI;G2P z{i+whJ?@buIRx!-tGuRhBE?gj2KTsYjeT!EwQ_j^G3B@K;WV!{iJA$eJiRb_8 zZr$2(-{zI9D4MLwn#k}Rf$qDnOvF{Yht=Dw_i1?%Y*-LCR3u5zbOq1HAry|&HEE$4b8#U z-BQ0VzIp+B@qy%6nqhfb;3-xV2?Euz?Ue%fNo*EFt=iFtmL3zaSx^+uiGn~=JjJjS z%b{5$==`zFg3Ds0b?+m;ew=wjwFqLf5R7$tRF#teMX`iJv!@#Me;`=4m`gn&NY*7C z4*&c1^jhKSbFe(4S&1W6h9@Z|`IFo3&RRa-3Ki%YapomiCl~GC+2Gy=_?*T_`NhBq z?r@5n#K?pqQ4|9jRImP3y~_O(V16uu@pV(Ie`Gv0+*aIFe=;OI#{z~VovuQcuj@FV z6#HC-xjAmH%ja?zwi5c!8q(vSIR#m>)X{Nz8Jk?OKGA#LT{B;XGjLw?8JJ@PnwDe^ zh$>i=u+!S?jnp)F{<3~TXi;EKR6(AXR!uOQMq7uRSo7<*w?$vDX{rh+nvxix^5}x? zHY|hZTWfFZNWS)YT_`~!^a@Q=&fI*rEaeY$6#!3Pt?~_f{`;z+d#d$(=SH5eFV?}G z5+-w7r_9dE>w16mreYP2QDsf0c|}5-s!rv|X}hiW^_f02=Y6~+0IEjus>F$$hDrjH zDYABk@AD$->Lr^W?7I(}oxo~5%abB03u3b!gC?C=Uac~^YPQ79Vs}{QG+e)D?!D*F z5k?;ev%WiP*RR5~mv8E2=7NoDKgZWY8lW|PNy{i++^U-M|)@cATP z^*BjRa27~D;BiU$t_i@YxC;tgK6Ga6h2U@=^;(}9ReRoD9<1?+qePzL8ImJJkr%>d zt@$4Z@QS3!Ie4w&mMY6Wtp&%xk%(hJWC@ue7*W<#@Zrd*gmdQgRydLV0gYxlyUxiB zm9C?826MLz;E!7eaC5x~4^9l=rNctsLotLt`ggQGTvs*^{l7JwWXu=Z#l_aNePWY) zI%0xM~R4EugW{pcEOfmGyFL``G`o)<`wJu-CJsA(JD zPe;|)f#tNX7b~68=F=I$WrfbB_|#XkX^OSd6Nio+OT?>w93ilx$n*Z|E0oBfgJ_I? z4Pz#DW}Idn@X;+}+qK5B3PX}KA!?#Tu?os6>dS#&xvk@!x$d?ux?^2G`pxJ|SwW&C z76^i(X+)LXe_5oUJoV$aF+IY=Jny!ityQe#e;M5*pt2OFi43F4DryqAH6?UbTb>Zz z24ObcXT9!q;q|>eVI{{!Ha(LxP)J5q85L|@`@w(rFQ78utPF=llOPs}1da=y4Q5yq znW5Z6>(5_#j(8bHl^IP|1&&cAGVz4Eq5XH?Bn(H=oPpepx*c|uu0MS+B7hGz4b>Ez z>Qmhw-SjebSpetgg1`Ns0EX-1-JL_3SzkbzI;Do@Pd5%#6YTn3wMP2QqX*Xoj30A0 z1?XJ8KjD?OHOM049bGVfpeOjL{(f3ws2YN3R_E6Yb&=;#`X?hpe*^N~2;ERIOQ)e( zp*Th#uh3QYF|7jluE~KM=By0ROWK)3>VbnZdV|!}`}Z^yMl%EWCcT|qaJl(Gpu=mt z6UqmvzQFvt{moEDf#1QK8Mo=_*3y}uX&b;$4Ihr#k=R|qK4tM@`ax?;a>c@$b+KZa z770-#MS`aYlILg<71PIy0>8*4+%SFE`hTv(_T*o9ZHf^Dh7ednq#2Q5(Hv%M)zwz) zp4J@exU<>+%lj4T#u2Vp1nb6t0UQYc4=6x&c;u<6pV;oNOkCk6>#NNvaY^SsX3Za1 zx8VI};CwPAl2wAE0^5l2#!TNL;E@W|zGJ@Wb#}Wg4PDv8@#w4_;FPoqD!s)t&)V(p z8(y6DRYUx8*8>#iSeNR{bF!kQ5xmT^jKHF+-lIcnN6ccLb>7?JPtu;6;Te?7ft1V; zfB`(iDjb?{wLxY~%P+7#AP*^CSr1yET13{3z3u|wR24=OD2Y}nMS08DbM~Jtw`M?{ z`Ur^JN(K7?p{JpS+)_T91-@9pE)XpOSCyA;+Y6MB6ooB`ln?=?s zyZ1D*u8m+fE72V_iQyQMBnb`B@OXn$o$+{!^_A+MNQ0Br21GkS>9Ws0&s&GwIj?z( zPSLHY8YA%pBM1b^a;P=+ot$__;xg+Usk!g87!30|7%?wN<5fx`R7L>Ol*wb*d-pz) z3@5G@dgmo}3eDs0^U1D=<*o)5Xm2#84WAw@jh$p^I=6=6@Uv$4s2dtW&ql zE$+kAkJ|bYDX4^~Ns>enPOq=PH|LA~`|>JP&469-7oybsh4uNc%DOS>?UVMup+L!s zB2Wlcl{8Tj37H|^=sEHF9rI_WKs6Ng+>m~O1GZ`fO=9Wg^c`M+yk!0Ph2sMrITP(P zk3<1YQ3%p+6-Q6=OnE+l-+wL?hi|H`u@+2xdsO~TC{KzanW076>GJxw2D*+@K#_l2 zVBq*7&`NmDyYL8?SP5AfRM7az`6HUkA!d($0=vpZ_|hGZ*-r<7mk# zd2);W7jV6w46C^;cpK%F!#(26oNU!*j$MJv;I$Fji6fk@b1efmPx#Nj7uK{NV~sFxSVy;g@xKH41YW_>8=G?u z00mN^&!r3~l#0B0Zl6k|*&vgz07@cWkjbAh5jv!Wmf z0wbUciZ*$HUxTnqmiMd=?R>b^d#^+}_7MML+?SkSJOlIY-<(<#TfePKcM6x1{n;53d!yZ>{6Xp7!ebjjR@-yBt)= zCI>oh9wBjjw#B-xd6oB{dZ%g3k;)6sPWf(Sbf;ohz6v}}UqKO?jk~#s$>u{V-M~XV z|0Z1V3`q_bfE4SWC{_RO{&fm$rSv zmPH7i-6s0`my3tJx8mGuSphdLbi7ILp!P^Td+1US&R?yNbbiFB^>DVDtCuHL?@)_Q zFGJq17iayRKqOPMQnpVbhX2i&_JL4isBUy#qtBH3d6V0!glgq?|1W?u^>WtImrY68 zy77BZWd5zA3!dYa(C4WL|3Q8}tbbq2gwufopcltF($%5&kGEV)9Is!*Fd;Km+fh^JzA!m~f+Q0Y4y&1_t zTy84EnYR)X;vVZ=bMtyXJon~so(R>TDZx3=%MSovughJS<8kMDqyoRf>n`>vpqncn zbOD-FobSta$sWlwe#$Cg&#c@2OMo0y<9MAA9B&EtSl`}scZ-JaMm;Ye0g{sdt;&iN zc3$8xSuG@Cln(EfFRU}Sbtd@(aHTvhjAcRL7^fF5_-UTxDT0@H5^!f9$^30j_kU9> zV`?>JR#KUy+mvRpxb;ix{9UW&&B}`E-d2`mMpYP!RYU>j-gX%_i^EpiAX^9X4bhJ| zDkPywj3TJ2q@Zcf#isp(wf?)F6*Cq!z+1B6a@i@V3PEWSCn>x($dfO}rjTSu)w zH^_bK)9z7@*^2~ClLSc#1kW;I$Lxpc`tE1gEPk^3y1oy-Pm8*ZB(nmL6@noF6}FAE z3TretW*z^`--kCWh;IB5DNz<^m8VFBMU6j}m}2#~wO7%awEs@min7DY61=kj6v)8S zM=Ainj{NA!GeP^h@Ar*wNnKtl<#Frj;(i~#b1G_sOAI3u5+m^f5w_`C{2{KvPgs)^ zPkjA%yP6o|4->+{d6E}RTE@J7wm3KcG9jjG z^k9B1{YMk*O!1F(%90(Uo2-qpk`YCUqIsGiIffI$+(K;BOST!4#Xr`jt?JS5_KtdL zg61?)Rb+u@DF%OP;w5Bv|D{qMGQx|Kf32g~cfVde8J@yy5Ftzr!;^s%QJwQ8ueYOj ze4*0A2RxF`?Kv|*c&+w#lPZrW;|e(zB**!Gaw)%0j)6_(oNuxrX|8Gr9$-l!1MG~| z+;aNyXAeOsFe_Xk4L(mQDTF3c9IvPv@%*%uj*oT!Hx(z659<=erRV&vE}0JM^lIG@ zlB4JS%%73ngUZLe8WEHaf^m9%ZV$+ID^mWg{<=|p ze!lbL);}ctT0t(UZ@ow!@LI+AzxidtjV;SLJu%LH%c!9Gs5+i{nM>7H7g)dYg3|I~ z@t%+kYm+)LB|>+!$9C3s*Y-Ty1>w_XXx-F<;$$5^w!RR#5p2 zIdo|t&2)A1wdoq+tFms&Os=4Qg6qqi3;Z5eKe*0?@BM^)mx1s{y!!5-810f%%5>56 zv5&iRO!goJ%ym%381HCIc>}Tt>%L%LRyFp`7Hn0arFm zMKFXCgMOmz$-gqUza0I>KhQXtVL63osIV(SJT~bx+oVrU6W7&-R|kSl^93D@6D5|F zSwfOECgN4Jk!|C{CR1cOmZSUz=l`p0yVW{z`eY{Rfk$2=7(&q~UgIS6z~ka>p|@yI zI=qR}ZP#yWQR~^k(U1NJBtZayr&NJLTYu1f7EIC^Ht;C#o&8^QR}Q2~0YM=-N(uA& z-x*u#OxuFxCqAp)1MX-=IAY~LX01p?zG4q>vYP1kIlwWDsx|Go@|~guZ=FADuYb-fkQC;oN22Zf=OE7NMK+BuPn(tcWy2;UYCCi$k%=6q&|vy;rq; za>isKXTYOs5nQDDJvIm$&oT-n&>A`R)>;YukG9G{J^!>T+u_!rW~pJDVEt^-`oq!g zep4JNQ!GuByvCw;zZ)XhhRvyt&ANBj#%WdBhUXM|?wMs6XSV;;0q_J)A9V9(OR5Sy z{-_S zdf)}p17gtqW6=GeZOYWlcKES(UR^dJx(_~rp&44ERg#sdD$Raz276vjE9E$AW*bv~ z;?qNxLdiKV{On#x1OSOpX_k;k3XsnVN!o$CwIW5(*4Q=bHhWcu&h%9X} zwX(VIU0(n8Gl5rME9xs4S8+v-(h3Ed^07pBCTz6x3^9{`(1QjLxf5L1@J)S1OoLn zRC8f+oD&vdyZHsrJ1d!(6DGxq&g}fI1umaIKmsUm`Sif>k|*2+$u4BvTd?_4Hl?ZB zU|u_{XH<$1WLZ#IM&KCKGpaqYbbV(wF}CmbrF2;`F{3pHfhdQ zG`ten-@TzJR3Agmtb;MYGu|l(3`2<`MaZmj|NL*>dm_r+%~+RL%IX;%_ua+5yJ705DZ09VV)g@mI0l0a&6p#MYPrXaHjdW*RaQN8H(pQjt~is zBUqXb^ThH%W-Qj~U{go@nt8HzRyb>wNGghVYA%qk_5xw@fPTP)k%2ea8Z4>i{(D$d zrllznFf2#Xj3lE;SHcwfCfi*piyAohKp(8Zf#rN2NdZm|C5nI|IKVT6l$-bXaC`d6 z^Y>*a1e=0nNN`7^jDTMEuX_I7j<(kmx4u|oS5^GtuYlpWa~H;v|F2#5;ME?4%sA;x z%>VHVlg_rbkJy*2`4TEz@N6c|nWrR)9LWkYN3vVLtKIao4Ud}_TxAn^n#lkI3@{*; z@a$^)`Na*t-ngk=G*cNVksL1oo|kCxoB_A$ca3Sk77x|iPwk-?1^E0vtViZsY~6d! zyT8sC^`aSO1ya-~Mo3X@&eB{~kzx0me)Vbpb&15qb+hM`oM z&$bzyuNO(LMgwSUnl7gB-Pt`?M;({ zjez~lkulWt`^FiCCfm0A#RV;g-`F5r0SorvsY*pYr@#S1k~mT(WCp!?)k)ut>onPn z$>+J|bH8g{EmlBUg{DN7;3y$XS?V<$r$qL(HS6_h%H6A>x->n4xl`*mtG{(VNiA@bS`SQ;zM?Mt9C#Ux3xGS&F0xktGCyCut!p zzy+au*S`sSVYk06eWv$~>vu=xW|3AHnG_ga5yPBD_s2RN9BBLBuh)+jK8LqLY~~0$ zA?sA6{QUkv10KIqZEs)gv!}&F-_N$CqJAmXB2J`-jEm1kg*wDX(}A!VdAt}2P^eb$ zDI@$U>sH&+Nx#oso`!dzPck&cFf2g`yvT@Qu225GBk*e%wyy@+Zr^uc{D5W=+~(?C zrH(IjD*lUp&LWSy2zY$sog~lv{CNv7_ObB^^^pZjEXR1U-oyPL>;21TnjC67yXD47 z535j~?TjqX1c?K@%(0Zj>=>1_Yxcu*a%p|mwutk89FFyVS=%7NG|cvdQ12G&=;q;a zH`ub`@;lt@t2s4EQ&@r{DVYUrT{Kl=4mab=1&1?n_lIuyG=Q6Li~Jm72-Q-`R*_-0 zc8yZ)BkD%qkJV&Br4*W`K-kPwEfJUSi(sJb`Fc>&1aCT>S79iUr3g}yG@by^B#G`m z?Qa%}cOh%*{fNJsSi4U)WTWn1Ybbp;X7>a_AB655V_N|Ad)yVF5oOHODF)pE<&+q- z7{L${jph&<4Sb1)zeA%CpaG$pp6`p1wgVkcFYWyp-WwWC^8~>PJk4_yOH-(EwR?3&%DV|y^sgFokDk_U#wd#A`Z{VWy>9IyR*vpxXi&4>(5dk1&Y&R znS(d=2*tSnOAEN~hBYjoIc->+k($k>0$Yc)>sFne9AB(vnpRYq=Twg3>B2g_G9$%m ze!h%;C*u9?cv^h_$9iuW=KqDJ(tU?-+d|u+$u+yISlKkf00{8Eem;VvodbLxS7Gis zKh~Yx#f7RD9Sz-dc5jE^@X>IG?dT(?c1~ypwei#lN<1kD&V1Jx(9z?O#`i7qHe`R! zyl(8N4Cn>4JEA#%q~ilR-WF%49>hF9aFLZf3sP?UCYjfE;;HKQFPk3YECDUjBF|_f zVAX#+X7Ish2@((-Tk#xYyLZ*y08FkK&L}}bn3Xg}kpKx872SiJ-8kN?#@U**Tf$ZU zp>g=CA!NL}JzXUw&nXCkB#FE%tDMlH{np!G8a>g9dWx-zsVMrq>P0%dnq5KZ;NxxF zWxH=;(SrvbhD)(X8|PAyb2J$5b#k)A$|3=PrpimJeeZMW1aW5<{=wD|(lsi>8u#dNQ&?hUD5g9oC!DJ3|KRXBnc z83BAqFI>Jp$W5t3|ManjWh=wIw$FRrGo!<#Xv!ETGMYrnq^hwBI{gg9;BbC;&{p%y zi4UHk>W1f3GW~FjbF9aIyrJ-%ZxJsl(00WgaQh)!Jy(w#_tALgPdrU9v_C8}Dex>A z7Dy22od=#As zGd9IDPFF!evCkhFA>cCBA1mgu*B17&J~JZeLNB_tE=-8J{4-&ehrLbL29$8a!?ri3 zFZpi9w3bo$o2EIZ2Wa^~@d5RmudUv|m*-Z`MYKS9eR!N%KWuw@=-2y{MRCVNA!J2l z8H$!TPKXr`C9#b2KzSc*iT@zWEZbdX<+0m}qMq^>36&Q$jUi-#Mo;;_F*?u#H{TVn zteImI9XEHqpzZQm6a!L%N8u6 zsOoW8@Y^`EqzUar2@FBN-)THttAmL*A( zG`87}L6d?FL;aENNsXy+%(q#VHau4NKorlmEKP|5NstUjP~l$UQ)Ak@7TVU|lG?t{ za=7-G9%;EoIKBFL|IT@?e7}0>Qh--1_;KKj1ylxEQ{x9~>1Q~{_2-?kU{E!y&KT9xR}r&TFiLzOld3;I58dAG#Y;33bL=YNX2 zxMM_`^++AEAp!hnD zm0Z3h$FdG|enn31RYvX;E|7a27x;bp75=>tqa7SE{!cGsxzaDOw6d61*@is!!!e>h z+|8XQgwIn9CkE!Ja}J$z^pjz;|NNTl)OKN#HO>P!U3JZHlTI%zr@BDl_*$ILFE&i9 zpmZtIl?mO-_}%DoE(eZ3ESUFjcFb6Nl<}r#iZi_nT|j+qiN2OF#zEO+>GhV#tM_YV zJee*~-o|VHPb}wga=DDp@&@)2<(p`_vY=Zz^Kp5PtD}}nGe2Ce{axC9Lc;-`p%)rZ ze){s|0++iSNHE6ZWd(4aT2jh+%b0HrFyyfTS37j7;PkInJNz-0t4=tp!n#dvSiWm^7AZMUN^>yOdp)PAw#CcKnfH&QZmio4 zFre)4Vw~@>SGe4XSFRfNC1{h#~ z0R|XwtpT*#uCj@(i|bbYIGW!&o+1d9=Lud^MD+HxR<&MYB#h=`Hoa)G*0)osyRfbu z6h)*s1`rgf@o03shNY~Q*|gfWfAo8gJI~Y&&n_s0ndtN=-9dg4@O1R~Jl^)ZZrt2; zd3HL?wj*Xa-4W|3a*gfS{jYVr^K`WK6f{a?8I`3pBFqn9ktH$?&*?4O(~nizG4c1P zSGa*Bb2Q8O{bP&h6>ba0WPtZ&@u97^)Nk&iOQXBV))dL_zn|n-D$Gsxd~9{L+Ma!X z|B&jxK{rX$BZbCbD5q9jsPqTEVo%{hhl zUFY3gzv}hpU92RAu}*O8I+mm;S|T|?koga4zPPH{yndMv>7V{^`{fz+ZTdrj4Yt{d zp_SiP5ZJJ9r_=CS(tgA)vtA!fAAB3Y8};YUejLEiT>hOdhX_4KzFwIM*GOe*LEa^)+<%_*40U8hGx2t zftz*DG2L~~ukVcu^y86w0dD$yLmEd4W3@c+}#KkU%Uw^&dA4m~`=8oiir z>)-vX(+hRK7Y@C=NpFUxe}n#9Zzj_d^#c`nVQwJbDTY1bnpVTirX9AHdEfr+yA#f> zt0T^>JWF#LNz;PL3+qlWeY-Afn+V-(ByF4WrhdTwEi( zjxgvLFOh`AYk&bjYYfsvROgJ;7wlGJ<5XJ>LyGb|~d@NM!7=jeIylAuO6I-H? z_EW2-Y2gZzsyNB;z;`cVqmb>kdH?RPvi){Asm(G)ozw(b;slM5dB6~>pS|wMAJoD}CQkbJ=7 zlJZ>>fHP0>HhOF5bHQ;J+vvmMR!b;8gwdHTreij3{zIRStN}xfB==Y5eSVoaW z74Vz_(z~X(OY4+Qa&#)K-0%LGdyO~_Dp%Q+JL*t%JF?(=@d5`^Nx9D2 z4)-^`+o5fg@M}Cx2s|wa6h{y|jaI#5LEzVjCb%rj_67fb)n0wBVKnssh_uE_nyhI8 z2mQX+8vEXSYUT2T#26ZaIm*y9hnR&D?R1KFPU4JO;k6CY5JX1w+qV>2QUx@sFZ4g1 zj%m?E`-hbW*WBlgo&%w@?m7 zyaVzi4^RjA+#V?x>@Q9@796FhdtxY#f2dmRZKw7*TBk~FX!S{oP!54}dKD>O@|+8n zky%{yaMPZB6Jd0guk@M?h4LFQ_&_i8hjcqirv~wT2Vp8kF5#FBKCd08fn+-7LQ)E* z(O?wM{&A+i451q#bTv#nt<`7hZ;(;{4>Y_X4e)ttXgN`EmQ%aN3wjv1l!J7pHKvAyx|arEpiGZP0J!n0f{54-2ZnQ zYx`Qs=;FI7W(1ZN(#!ZBewwXj-@I;4!@^_upzkzCGaTo4LC;eJ8K#LYd?S$HY3wd! zbvrTjakqOftbATc7Eyw}v-}Tzdpy1H2$vXZ_sDX=-Ce_;KXG)%-{(zOLn7OWMT#K+ zC-Sr?Zg}9~;Y7_1NsyJ{P<>V}%p;bvmL<#n@#=x!t?3+fkqHQjQwa%BGyx(mGKZL> za1bvI)Ij2-u==MoIp!O(q`2vPF&p^qO3w)<*ZvV<3BC!Ud zu~kRJEjp_nNe&f1`Fh*IxBxTs|Hs=x`@5p|c}v=+mR+l#_1iPgMF=?UH$&1CYKBBt z+>6t3NjJ8?{KRH;)u%Ch^@}tw(yA=8tb&GO%eBN?ji&ZPH^{@PP;rHvW_eLlSeB+_ zRgM*M`cWM>iSd7F0r%b1a_Zr!af``j_Mi7J`eFaKQ6i26?;OwqBNHqmDJ%ff&JIj{ zV{l~Q+HGvx&cvM9wrxyo8y(x6$;7s;P9~bz$;7rh_RTrpcW>QYUAt=k?dtu!tJkyO z_qbLKd4kV|km?bfUP0uB+u`^M>gnu1GO< z1K-(^2w(PM&N@O{BHj!xrT>?_FlXeCR66zz2s*gcXX?Y{v-1w!DT~wXW5ViU5&94j z1_TDW@|PQH3nK2+2TI92LC}ZeUsd(OX*zuLSjD@DcWRe^P$ZWEEeo9%m-z`ISQtYzEcD3WGpKnpFrBr=moil1UfyjT=nS`X zr#@-^c{S?`(T$e*>=Es{Ya-{u?^EFUO+58x3!qKuy9tl7}@;k&YnQjev&_G>Gr)jeSo;bIm?3uw@FQ*T1z6wE23+n+C}YUt_1veEvz(1;7>_^I1LI0E-- zjdl9fc-y^KYvkIVrR)kAC!U~B99_^FXtmzR)fXfW6N&b`!;w|2k>nSBdlmB6C3cqj ze_{E5vAIbQN|_!k4w4~j8*ScnC&vN(Q>{HrMTlB2>V+jMt$9nVJs_)$ko!0Jbiw2U zEE;NAH-HaF0c9?=a84U|0`wQrVmN!`IGxFrCS3y<(GZzML(f$zI2TA^t^j{ zY1iDIfEGI9(Q~E06sw!2>_7#ZG3v#-0rIv8T75{GSd zYT@6+6#HE-UD&xD#2;$32_BS&3NcEVSS5)8=KVBgBt|fGbFf=d^EsW3RMhZU6bwX^ z2Zw?}>$!oT?(bF7>J#MuuoepY`KQZkbcbfX=;a(bXJwz;wf5SCs&0DcpfX;yLNi0+ z#DfC*jyU^tgQ=4tIapxD*0kfR{j83M{-ks3!>M-PDo$*rh)UdF6(s4+d0`(L=cf>9 zcchbFIw&OO(}e1u9s86s^Du`&5zB^P+1U!uf>E*}U<>-axlNz;9h^mhVF*9P=rM^W zTza*&+I3ELdlWVujbHB>Q2kSo^yx#2Iv~E(ODIIfP>qH{+sUAJSA=^j?vK(5G@{M) z#vZ$YT1)NJb{HZ_OpYPC!U+|&0M38+VY&Z1EJ3cPMF%dZJc}O+YY&=g(|$fejxqn- zv)1M{)j-*4!?%@SaB}J^zVWR+594W9m@}Mrq(2vzNi7W0hhB+|JM2%2wsr^+|FxWu zI?_L3Ds_tHCO}{!^Bq`ztqI(w;gYw5A@G7VuotR$R5|$~(8jC0t6AwSN+!QeUIqja z3R4{My^rdBms;Tg#BZH|9$@7fM$QNzVfJMugK~Symp8=~*|&-HB}Y8&icRKnl0$cm zk3WGG)8w&gyRRsRp@Fb@SF*8jilu+ubLl{zsMM05D08|QD%lmnWgfzUTa*~!A1tSL zGZQME-8-yH%d@nv2}KUK{0||2Jd9km_dY~&%ZISd7XRavj z_~G99#Oe}6>qL%+;NHQ+lm)kNi!SC%FMzKnG$x5qej<~a9H`g)^GE+n4dEO>;rCM} ze{G4&>ik~|&V=(;oDj{!LrZDD0~Nm7SffI|x*ye(qm_E}0$(lSHwBkxnFS0jGZ4fv#`%p~o?^yu_I)94Xp7>1kLG|JCr|OR|J~w^WP! zBC^xRd3$tDw)LmXgx{S;2=4VYP?rro9+jK7Ais~+6ER^N&+dx8fUkV$RPZeY?lv*S zjxa~lYg&Y4%A_2D(ZujnWCeaX*1!Wuq*00wBc@ z;o>{zZ8hZxdTbIEC`=t!R65zjmPL>C*sL}FnSZhS{1>D|xBCfC7|fX{TJiM;KYj(> zj*x^Ki|7^szvob@i|4qk4xI-D! zC4F^}8t-bdD@~MkonIk)pp-w@rl}xtjIc6Frl$RE3X96xLv(k0W3~U6Bl{qnNAR}x zeXTxMNFxI+=$kD8`FMF*Vx9ZMkYQ2RMH4`Nfv;2>p)Psf14pLzPw`2QKD4%}mjd8% z{zCWn@FULx7EEsp7NiQjYr+le#_h|14+c^VJ;zK~i6$r$cI1;1E$$B{eDXN!#>ac} z^gbYAfGIqGKtET+U$ZRo|4KCue}9K8gUQ>dOvc8KY};adbz3n^spvo#Gt4ByG{cuI z^-fpCj*%8O6wXA8G4om}dRSX~f8u#2pJ1omSB^IJ(bKX>#(;~+>|5fOM$+{*G4VyF zl9jp|#Z1b@>hnV*_(P&@?u&Z(2@1jdSL(g~Vdi3{yvC&}aODg&GK;0GP9fRA$VcJ= z&Mw#JJtnl>MEZ&dG4aEpc&XGny%<}}oI|ebatg->`CC9zh?H@5T*b!zxKyX0*{9QU z73}<@RH6anob^bJahc@z9k-iF!#I6nTz@*>mQExL7q*T1G#eJn)Sjj`}xVxsWCf-ppcFAhGN z=ymQT4XEL_>Yy(bjkT!|beImit8R%O2q!s*Kvh{MS>#=!#O8&UoUsN1=o3sftySJ1 zxACj`TSXrGDT!P0ezCOVRlMzmLRV4#UCZA_$6)x|EECl@c9q>EL*((B8`|<;>%zc~ zU++8c@>c={A`$Y6h*msVCfU!I4Sn;(`?%oB#y(go{)4E*O~!n_#;%4kbQ`~-pFABmu;K* zAZu%%izUMK99gnmh&||0fl8G4DcHOrMbH@qEA`Gpz-|J(!6FQ2-RgRl_q$xLEj?I| zxkBe04jw9kp=hLW1c+&L+cF}MHb92M0Bh`vWL|%$_!wEHj4<6{6gE`d2?Inq{AzJ(wNd^g$9Ts4@zley|}!s0I5riUYq{ z=N3Z#A^o<+hx?5c+1gQOY~CRv8*I9>H|BZzc=jx zj=*G7Ox|^dcU5j1=`1!vJm(t|Sl9R<2Q0bixsD!4(8kAYX|^3=N}Wp}8_J=vfeh`@ z%;K;_$fjTGZ0 z{y**#RfYaLdc;W#rC5Iy%)-Fnsc7NZbBG!^KVcZ|$Sx+nZ8^FJgNwe^2QzOx8E!m) zYH|0k*4&YtwlXz=a=j8421cO8kmJnT@p30U*82{v``vw>weg@BVyjVYA3q&t&{O9< z{T`}84|C?tFKjCxb>db9B?bi&0+S#%qno`&ytXg& z1%`qV|Ly;o!v4n|)?OTR2?@pDiP%eN#nodW{BUplK$svVZQ69FEdDOauB5UJLRKmE zADwUe`(=}ndnV-~Z3_1*Y@pNsYy|7a?TnBpx}u^u5%(pFkaE#oZsoC$NljSfhDk%Y zHe%Rn0Py%(wA|AaXs_h|#Gp=)!jCTYjy|#po|_@Vv>trIpea4OXsY(Q|5E$%vBht5 zX)?H1Rx7yBi>nZ*s6CUgC8P$bUNIK;BbBzJ>7N7T{H~Q1ZQMO=p9E6Rzm{q%hcYH%#QtzE4%_ zXcKjOU?S5$uC?1QiCLj`V!5aiRo0%4*e-QU(hM0*i~Oi0&V1xU59Z47_-ACIy%c-c zUpA-#H3$|ABKokbQ?`*8Q;0`@>r8%QysliBN;(i_N8;<){%!2tH0Qu+e@-wA~+T&}@(*XuklztlwcCW3y0I&ZqYp_a9; zb!WRjU%DIbOvb9|Ba+aJzd}od_r<{fbwAi*h{_csndhUq^&SIR>eLpI%EO9>n8t-0 z{J4c$3RA%>c!M(!(!}JOzsa)8N6lRoVLqx|m2&o(UrVPSyE8`J2inYw7pSGH_!pcE zW?XcgGXc6Q#yWFZd(9qAL>UeuU=XWkYjsHh&5Z34XSo>oBbQr(4=n1$@+8^tp?RD# zF|<+Ul7&3s)aGDQg6f7}OCc%i=>=Nn&(wB2S)+cLgaFFX*Ht#+Oa^J?*EK-c%X?k})jrB47ZXoFe)I0bn)MTGbTRf_(HVp|l{3MMF3$6D;9OY%ZAXLTO|)K@<8)ZagHBKJQWxPHbd z-q`W8ocLtjNOR4qn=HLL&nfM7@4lCxM8|=Hmm7tjqCllh5y(&6M%tPdW>{S$v83oteQrFOvVt?MAlsKq{RMMAbRJ&d)N6F#>%cBj3dON!}dAgdMAC& z47F!(gG2RhBlGNO%KGN07l$IXhR@VSJ#{7b`dQLSYRr5P9bVV!YkXGEFy(S%gTM7V zGXx53jNRhv8gf|Uwhra`pU*LL46ulrS?*aks~IERCi&caxY%`eu52 ze-E?eoZFGGnkQQck{)560SlbLnsvPNzy&L#NTJWykXpcU4#;6K3iMo`xjSX!p%k3@ zoR=SUIVo)fe<9wSc`p(?n}l}?@Oblmq6PncPOIhqMfor}KYvm2{}B}h_nqAy28k_d z{^XAaSnm{K(xgO;(BiFw0pvzn+zBzPP*|>c^>cfDAi4RrA1}~m-SOO<$+VJ|-32%N za{`5=+kTlUz*=)5(_2RqF!XHMWiT0TgxSC7J3UH!m>qFaT|(R~u}uIBqU=_ue}G7n zPo(JL{)Vh#8G#bC=3-eVFXH<(0RKP;&vuCEw?V;sDt;1@UsmJ3XbE`gPnK5TlPO9b z{-&+tXSaD=#~Cc~E`D4~HBBGqnak8H?SIZKr(6TC)Wlb@=W;UgN+t@qR8yJkCbN@%vas)^rG zvd8;2ej6O^E0q%z7pOXtgu)_bG2+M6Hnri}s?|$n$V!pjt zg7G7L%w%X(lt|ox!{es5DQBw^n4Ne$4N2Mb7=NWKavwd@ASzZ3$IU$kK3Go6wuB0D z9)Ysc1lT#)QTy?7Eppi+iwJa$con#2rl$Jzzpi(F&K7p3^I7P4@7;Xx-byKNN3W7b z68PCm+V=XVVU{jbbU3jKo*b`dy)3svk>TTrPC$qlvK%40Ht8L(Z9C4bxzDaI{#M1- zsE#H*nZW1dXR_YX?AG4`CA~WUcTPC0*YJ)qcqNs*n}8xHZ4ApR@Y1vP%4+l&{wVW@ z`I}lcw0}j~?sI$L}M3QUR}w?G0>!v^cNIYW)9=rLd4y z(Itz4690Z|{dV1{LNrA@N&MLTUiX^YbtwUSUyR#{yi6+5vx3O|_u1(e5c9&yQew)NN zC73p!;U9UmUkxF?^3&9n1{n*@N)|o^n51_R>r;S;H(dY5M8t-2JQZ^p`ehC!aP(;Ls-A z1UrR{GkNsb<+S+I7n0}<)jcL|Twc4k|3*4N|TId+}?pmZs;t#+n z!bHdSWfro|>2H`;TmXLZ&2yEEn`0A776=&T|CQC~C_GFSm3kso1w>FAhx0_tG6p09;0=Q2u=7}N+U6E=!^8=!-RQDe&` z5e!b#W*ee^X4M(nwt1b_@pB_CM^5Q}Tdhb0G-YAja-%&m;g-P)@-b33ARy+Zznx|x zP0F^|e(1$v?0ViiF(UqJfwXWny5nfbDuuLjP^L8*tHe*@Dr~Nu;DowTq90Rl@_TDg zxsJOz0aS@2f=gegQ6J4{t$(IdH?Tp3Tm?3P1tL5&u`RnHXe_AaPS-cTVC{prepg>o;Lprs!|hg@e4gYC zFvXdWq%VnePNEjQOy~+z1y;;|Xg*ob0ivnE?|Lybg?WWVI$CP7s)gRz2TkVoic)-? zJ+~L5%S_35I-_2=FZe$(;i4%dq_F-dfGq9*FiXGZJ-;s^;QeHM@Fp4HY1%LghV{;- zpDEt;-wG0|`1||l0U6Jjtn2pGHczml%TV*e+gDn!rV~?Lj1_@tSPBT?Nl&h!!8N}X zIZckt_OiL^cX!uQ@VR%{kS)i0*w@%M_DcDsGf*L zg+j5Y&@ygQvxha#feo9l^v!p_cEX=0ye`4?H*`v06O!l{f%QlmAn1ek{f*+rHGUbA zLI2o$Q)t&NAt+-<7oBMUtD-SWOr}yMw+ZQU<7QI2ckHQ!z1mPL8!!CwuV_*jo~102 z1J^UrcU;bEfg3dQ-zC(r(hCqYvdKy-H3?VEboYbD$-tkp4iSznQ+^v`D>1P1;%v-7 zdBZ6Qh0bVfe_~YaJe_++2Yz>2iw;KIC*f7ccF*pGOr^5SMlej4>(7{oXzaH@$zXhS z5~437&Zi>VN1n>m1-gD4qvw}-)be4R>37&Ph#D3=huP`KfAnn9Gakk;D22s`3OFL~ z4shQ+EJh>BUDFw9^@Ls~K8MrXZ$bCBOQG0v_krE-!g6+=E2Re&bkQS=#C*awu6wJE zKzDK_>EiW`=!feSs=Ge|RyH7!LCXbTmlgWcOSa(MngHM_Vn&h;wqDfaU!}q6&UExk zg3>bt#WrckrvuO6Z|x`JV2Y=UwN*f1n`AjglVKU@-0ia#0H7dM-Y)LdU-0;A;IG^9 z#*f;B0*`IY92OI|r3GaV=5T`S1SioaSWZ9pnGL_um)0YePXG6Vq^Tt@7>u94(0-AU z|H`+MHa_m8?+%+k`WnqO`nQ)$sA&rP_{Y~BFS2yrW1a7~!2~snuO9cEV1dTM4Uj!m z-uM5BNM_WPuh7h3ec>6Y%@E9eI$%1d&|8%GRcxJ(qqCz?^nv;mfYPIzRmk+R`E z5~F=OJ^dTQ0t*)FnD**F*8+-z6%1fZ_37V;eN@K(~IMFZ9 zJeG`>IP}ou=xkH{&rA2W8^DIaBmoD!v3z2B=%8A{elkK3s&~jBMrVDk`*d+s$NGu) zZtgO@MNi=7fmJ&zh;-75E+$Db`3J4V@fPeN2`nJ|$G$%-r&1JS>(#>ZX+8<(Q@s&! z`)&Fx*|-88lo^4D2`9YmadV z;-qWepk7sFQj}2Dm!}Zcvif;)=Ef?q3CZR zJ_|;V_DCHfxMii1Y+S;_r>Ik>_5j zB3k9EOoN5X$%6&k4`1;3_-Xp^%I-gI-tw47?w$(^jBXyuNKN;XbV*s%_i*66ct8AZ zH#=i-MK_h=|E?ho*s(Lw7Z%D$w{qHj46}?@%%~R~Y>2FIp9Tm`;^1duf0>0AG4F_W zG1T{YNg#Z|Z^$*$rH(1WJSpAD#f~VN<7Oz)eZ7%<%jrOPK}n%A0qC8mVvkbR8n`0L ztOYdTe3b5Gw*hRUqTP=Zy<5W3zEO%AvT~~Uk`IK3l*B*$xas&%j#frd^qcsu^m;=D z?Bo*$n;@oR=!;z0$zxl)S2jFz-zn~i2YR*1XAaouq;*3pTSTliF8X}Prn|>p(5*;( zFl>@)I*kOhm#s*agsbc3b>RfHK5Jugr!vA+{JGfDB7$ziZ3nK2yJZbfZw*V>mxPyI zy|R$;ovB4eiP#r!Hr}LH0Gly^ZDBYPdgzk5CDHZoJ#zn=KaXVEcMg~sE^Xti!N_kZ zhOQAr8-ogYmMS3XruRs$H2zO7>HDUAitWK_2; z#MJ5T{w`0MyGeYpl*JggOBePD$ON+@&#N;sGwwX3bYT#_Kfohc?+8D(cpN0cJZ81_$pGFtN4a_W4n zI4LiPRWB6$$)e_zOOlB%g02{Ns`x%4#3cl7$wNvtV`|pO{*yrOPH2OsAaf`Mp1+|enou;OBSyetQ zspeqsD;ad^IO9keYLA28nd4jh_pc(-Pil)?N^g1r4Eg(Ih+m9@o0Pd1tWG3L>jo+e z25fMr{_$3_!IpFhOZ&LWR%<0>lpl#vIYnx&)x*D!RIZ%sR-Q#ThGMpLBPgN8$l$Xi ztI|VsFVoB$`uf!pKbAEUNbJKQ=!d{1Rq@g#Lu=OUqc!8Lh>HTJ0~|LRV4{+_&83qu zvzeWw>u|mOk34Z+gBlVw1J0R0qe;Bu!8tt(?{p~^p7^oNkb0eKjSikz=(?@|SK>9U za>WGE%}syzrtW2+kLVZl3AViKO|9Axh8It}Rl7_lo>N;M1&R9}g@^?K>zfz(Jn>l6 z2Y@dt$4B#((FyJ%OHwr*yW;n_YG?XW+;YAY^KW92R?m&%{_X~o(6>$3-3s5SMpM3$ zbkguVS4z6P;9ei^VJMAN@1*ka-nH9&XDN@;$ZCtOuB?`MlJ}%3h3|9&< zTYLXXqdcLvTc!$aL1N8c-{y;3mt!9;0nc2_y7w5lwsG6^agkrh(G<0yQ+fqFBtUjo zRQ{e7#VwLWu(+bTeh`T`7i1Lo^lm~fmQ_^C&!=q{(GXD)Rnb60mk{~-E>%>}(#iAT zK2S2YVI)L}K5<_h*VgwBs2vcXH+Np!dswbE+(tT%a{Vqlj_RSvK|lVcYPP6wMrwF| zcPiFaKEF84Bhlhyq=ec9!hKUGswQ}FFUMg=&KTWPx(bvoy2vYSQ`s`20=(gIW$%RZW3Y+C@Ve+CJ-7EFzi* z1q!P@b*G`onZ;{wC=N~CNpHQrcAhez1g0zVJ&?> znOa1AtfoCpJ1oFK6BB#$5j!hslEqpT2yuH`;&8r;kaC4)FF1n8Pgou>4&8d+x zik!>K_V;lZ!PaqZD>v3pqs}CY4or*|imdW-%w5|fq`e~j)lume2zB_26v z_uk&xSmo0mjBXKfC_#cN2^9=m>Lhl|(Z1ZPkT+%Z2Erp2&3B49z?U$G()z>NBC-{F z8N;MLN6(_?@66F@P0la@LO(8l0-PY*v3Y6y=m)v*gNP-kosFu@0 z1T&LaJn>D9FTA)BCmxr|E0#RwNmP7W!sUu~e&6M_OSRZBL-0L%RFM0^NuMiyBAw~t zad)u-V#*(3)+pYc*b5j-& zLlnFgbOwXkvPoRxRc@5>D|B#b23v)EL|iAe_3lH*_<=A%BhBjwhB40bk=&||i25T& zQCJGWEv|u%Mo(rzH*zzP?^s22+0EN z(^)DRX(Sa%G%6*j9CHub9W?d!MiAPZb}h>%1#LINdy zFKonNK2M*DSL(%=Tc-KP1`(Rh*5Y8>HFz~&c8>Sp77FYO^ww_ZkbnnjVI(T>3G0+g5a93SiSWbN-#H1UitEmvb}@kuV2!h5?PSqR znG$qEoAYrd7yB8^sJwBnqZrzniU{r zGDX(jso5HnST+McGJ5y+^D~pruN^b-lT%o;3$5vn^*l2w`~R%myD=_X)X2VXyo{my9EG{W~T5P-AcRr&>)nW~GHil-~wc=dz_0MztCPWM~H?IAAC3E5V$aWX+yI^s8i>nox4q^sQh^BCrk}^WT?~9nAwa zU#3I!Q^j=Xq0dfu&`TttOjR?;wxfXti-(6|FSN^5wb*JrXCw*c&Y}`*NCTk;Bv?1= z`!fRV|58p8?*y%+Ngduy;4Tla1U<7`j$DOC_qMYW=u!mrLH+Sh)uP9RpE7{_Ir+Q9 zTB(^sCY}t&*wsj0fnNV9UA(P9MA$Wdg=7g=GUzp0#mG-UDS-V_t!i-(>;_;5C;Qeo zK)q^#zh|y7EF+q6nRDdlwYc*viffH*T72W2q%r(Oh4*&e%$D2*UjTjuoJrI-hg~Z( zcbzlJCu1n>QYgy;h34qa3U6inZHfj3ijtj*G_EUtHuM7L{N9$_w8Us;hDFKOWRe)= zqoEv2H=b9CQwgp`k8w@2prE5FB@$csjDGi)8W?aM*lz8R77 zT3ICyWTrAa6NxF8{XPm|#=1H#UxNKC$s;yB`LGjYh0KaH{iKr47ogmR=vUYG4> z`Qb%S{{ks=8}jdP>DtnK+pFeL4w0V*uTHMxl+wOlgOq;{2tzXfODjpGV2LJ&frsA2 z@qPeYq)Xog15_E<3Ig)heA40HR(ctcp2#=DUnGFP_9v(5Rq(D8mKKA0bPjLdc zI`3V*CuOQKtZ&v=lA4X7mLX4J`NKx3Y5z>&t`0nS#Xc)l#12sN8LU7a4ADzwWz?aD20z5(oXkZbwy%*+{}&8flrG*+r8ijwZpFF1zqJn^Ei9O z#k0Z|gJpc;{{!Y5fPt~R8Ma`?AS`3O@Z*W_ZVM)D)`32tH`xm@vza(UkwwAD7w#_ z8Kvodk~-W!7q>_c5?+DdT}FbDsG1NbcQu@0}Ivk;z}zDH@JI)#yQA62;V?+oB`fSO?wcV&Oap- zFMI!{UC=g9bt0tJ_xZ`G-GhxZf!`p2y7Buy_COElLSiZ4xBX1Rk2phk!Em zt*UE02|ihhS9b8LJL#&^ABpo?L=3Uq#7WOqXHX9){c2>hr5);NGb@;g-FHxxv!&T2 z!0Xf>^^W^TdQrqh_0S?sQbsJ|p6OkqjZzEIkKV_4WX05QwLXr_lu>erUAC&DxuZIU zVt#JVA@5**tZ!O1{y}tcdI-OAMts;LZ)9ielI7WT{fG9{NwtJ9&t4yDq=FZN*UGm` zWC=*6mrUCys-MQxTwDEMS)Wfgf3Tj?>>zt!vr|4>%2*AHZYhatDYE|&%H)+m_hlla zrIlmITshRL`I#U5*juOHIm5lUoyHElRyQ#5TQxek>C}4Ma9r~9gp!aBszouNH0FlK z?iLtOl*+?~c3Oiwz#txjvAs2NAZ80oS{nd=`;uZNr++`Be;jD(gtLlKLjkIi?|frW zh7EYHk@2TpLaX@1<{T+^xC;bU^cOEbcAnEPb*Pr@5$a!d8i6H@=Xbpi9!OEnb0C&GnxmpHKMm7~^%*ZpJ$a!RX@!9Q9i$tX{{b3TEBQLzas)D$UJg$gn4h2L*nB9{d&g7@i!EzXQ8zUT%dS;_mY@7`YAO z2}e2^V@aWvmWAz_Q+v6GeD0jIQ5vwKS{i_y2fD2gJK5GPCVhd)gHl6ZY=xx31 ztl#0*;V|EKUoC3mEOg9%6ga(8JRJsZT(|CSA+E^d7GD|>l`aWEh;LRiar+8a%?Vq`je55MG&5MS!kZ4 z83t6KR9f%Dbp09uyT4Os-ZIg*WgJ4pP%QdPsp3Of;7>}cY_~59vb^TI*GHv7{e z&zLG74732KF#yWJqxf^;SKPPCM*!_-t<;AiHLB&pyQEunvc;t_uexzpO+;3=*c@XB z22unD&nP<*qv%9+HD~N^y$DC{nkQ$>pF`wgDWlB%;`#AZ3x5pOwt z3p%K;I-LA7J#n6!;4fBXvS@t}&Uxq>nyC=j<^Ll3kyL82|BTAYNz8axb`85q$Enro zI1PDZ%8>K}>bCU~z#aSO-=O&#%u#hk;^L8{LlMxJcbsgR&QH~}mJC)@--~0kly}w~ z^dm}dIo^w?{(Ux~0d?Rh{u}8ct_{YdPBdoi*)8vqZ+c)0(enhXW)s zm^~*48tcU>tH%MWtffJ8c z;_pprBVA81vxWA_+n{)F8tM{PA&n|RIZi#``1ut7evqK)=h^widNX>;+!Q+C6RSm+Z({`7r- z$Ew%e&UG`=DO)!eDh>O_f~xc*!$vdE*5AfCXZ!gO6)kqoS|m)TKj-(^wZ)OZz1%W} z8#A(8DBXkS`1WUp194Yx=W27QN{9qn$iv7t%fDo77G~r*7aSGj?E@4{YsR9J^;eDWen8nV7W}RDZ&);TXYbydCxWF)4+44a|_9>TzY8Xls6e2T-pI(yf-G)_< z6ybrYLW!J0_XmD))X>ki=K2zbl~steQFRbkdlcTxqin_hFCv*&jhj=zn5FhverygW?I%Gx*y5ySE{Kxfg_jih@b zZ!-!j)!k2RJ%U;4Q4Z>2MyossB<_FNzNdN%jBMlv2)@6N+~Zx0ao5qBlJ96BAHR% z8PiM%lzWj`oFSMekEzPTI`BiVmPscx=}EhKq`j{y-X{Ew*1l6upF7_tYsX@i-(A{@ z40G^KNa+!Ua^M$Z#txSe(lVZF{kg%ErLPoG|F~C*<$eHqYs_1|On&-P-nwalPwJHA z`!ZRmMpyz}YDa$lNvBXyO4q1|kg?WwgNj0shSiNpDmnBJNVhi%Q^T0o~w}aQYWV9On>GgI7emOver1$ub=<|+B@AovP zvgAnA36qhrHj!s7m0s#JCxn9nM^sm9b!BScZK~+aFjG!c7P;1?v(G;kYDS^b${B{B zyWAOY4b&*d{KrVq=URgId4nRrwm)V3haK3#nfP<3N-s*e;Q=y zKJ@EudRAtc0*<{S#BD?e*>t`O^rW(lK~LKK+PeAIzVci1o|fki8J@Tr)zmIji0N!D zjxQ6u3+bv+bL1JXn7MZf4*D-qo%W-wisF93qb4|c%PZR(`=afZjwd)#92F@n$yoqB zd;;3}k4f1prs1V(uFydLYaufc+o0Uc>}TqGb>}N>7Pb2W{mNR}s52k1>py6vRvl3C zs{tv?M;8~M7oJSAj)QsKEi*Uice8{@Ec;~o)fhjkl!IAA;X?tfw&YIchT;O^5sJnr zc1G%gw^?zP_|d%E1bCz!cVtm2*@I{Q`aCsqwe9?TBb#*W60Niivr!>mTGK@&mD^Ep z3e1FE!pq+r!cL0bHk&x8296`;jvG=Fsw&Z%z3VUxC!|I5+Dc7^_gvX8+oUREKr!7%1SVkdC; zbV##rJtqs>hJmyp+y2!->1^d!zd;>d`rjK2r6?Y0IL58#k_zhdv$aB!TWKa`MMIF$ zr}BWa5J3rC8U#6V}cr$A~an^p7x!t zQ4zssu9XkG{N;BV=)Xv~;y2i7&0RcS3vF2pem_?~*(rfhaj(k8SKJCCY@XqV?b031 z*F6H*QW)`L|6=EFW53dLhew6J;x=aOjI|pvvwQDq<_02xt>cE0o?!a{4R{jAY!O6AK@SgCBPZ^u5s%dFkdfpg zH^0ise?I$lZOh*PUg;OY9&YOY`zNd1JO2w2{1+pyPvl!Vw-17@3P=Ox-w?Bz!dS19 z3_Y_7;1W!{(Nhnm36@VEJyz@JY&$1n113r;qi5?EK;Aj{TiH&ye+XK1rsErFX_9G~ z(XoC!@@=F}#d$x;+%LvffraZ9N+Fz)#6=u2Euxb0lOZ#A_Tx38@`PDNF=S-^tlyTw znRn4lfiG`b5ZJ)k^X>;NKR{{<@xUZhe}mooE6FyIyZ3i0xx2Ua(m%6qH0wLCj`UiV zsM-_eacpzB-APL?iX4+iGEcw#|U*W>GQa$CoQJzN{9*drmimsQ-&vwj?`q=tCHaM)YK==7NgEQkB z4gZHzJhn9#F3xgudm)wh4OO@a)v$_J>L`FGbyA?yW=yDqEqp5bhy32!Ay&n*+(KHiylN#{L(64&hyzGV~x?|x;HwiZI{OuoX37s;; zN+8*B^qa_cr{`-t2ak;l?*yMLhKzH%<2P_P*ZlAe)NbnT`1gvFX(jq9sYM3KRzSs- z)_mkzYhSjoqQ8v+bL5h0aIJg8g09Ei>+}mGaG-N5&EP?|umkEq{B*tDODBxPnnY-v zkQEq;s%M>b?$tG`y=*@Jumtot9fFsxFksD_4xP~VZ)R{RRQK59H%7&RV<;w*@S8dJJ7*}c%MC@2CfR_+_eKK@T2vn3D5NNMlOUx ztp-^h&YvZ<`N*7c1zsp|w4k2~yF@lNFXP$rX11jvA5C@|Bp>grRCfK}Le$BGu0lZ0 zNIFj{L^wSd9K|U-@eQmt$7Zo>plA!RNjDGSm)_(Te+IfAGI3KqbJw()Q2fkxlQ9j^0oVxb)ueSMQCY@FG_Io93HJSN_IU*NBg*In;|a=)exW zicvl6{<4a>L|Cl7t`R-xUYQ3Lg)8kS>qd5SlcuzBsEoD=yr&OfjKc_j4DliD&~|ZN z3WO8#Mf%IgBC4=<)RSEo4ts>irx@!^)ns@;hM`|7Lyn9FjTliGI)Rl=Od%eH_dJiE zlc_4x?!vJ@@Bq&7)i{3Yr2mhLEG{^e9I??rbFHcv5|BoS{iGdlSv2H-mc9Yzc5L;A1OUCDLu{8L(< z&{NWKBvVBGcjW3eMLA<51_e8#QlDqXd&)x0$I6_A>yhEjR{1=XoC)n75G-znYPgV9 zG26EYZ8Wix8wSv#agoaFu!}1>rTV9%%M?BY4NU`s7U}thM0&n13zdcaQ7PJ48c{rE z_)%{w9Xn+#8kH(sl>y3Vo8L~i*>^9?#v9Y)7YlA1f4AWV^UatC-_%M#ZR?rcdg&F}s%OY{ljplS`PwBb4gmlgZN%S?*kbn7dH|LxU?N1$B#>W| z-~_2jh(O#u5I}2Ocf29YxZWk~p=S&XyiQT;#x-N@k{(NU^%kt63_Ua(_3P3gp}(3>FE!fuP?> zQD}&&6qy&05}fOf0}iMV%E=?PP=0&nI7@c?Y~iQk4lyThDdG^tf>xr^B}qPgkng!4 zu<4luTXDxO!2#op)E%XN`w=ZhG>}Fd(G${6$Y@!hS^cl(kgG02SWjFQyx#`POeX}< zr@1s8rtYDoI)PM=>vlLnyUbz0Z%ptZ63!5c(e_F5#kdR=$PVA_ut%nFoq+#` zr+12uwC%dKJ006r$4SSwZQHhO+ZEfk)3NPzj0!roo&33vRIA;jS=XGZBHdk9TELl-^@HGcOt`%A17KHNM_$+FLH#9|n9XT|~x~ zoylj{uCAS6GbR%YEdP<%8(3F;%!P_gJM~{o zjvIbhF-3?dq0uH5PqoNu+55SkjhGl1DlLC^dxV|A8sWbYDe-5LgIc+^u5QLOFRAc% z0(9L16Uj2nzy*^dUa_&is69*a^L@iAZ?gr{{GwJ>g)kNLn39w@7^lBlTA&I;O9Ox!5`~wRL#w% zvw!PCiJQC>-ow|!H3X28IS{eedY0kp)_?G|9`ET~@>($mZY}ZPYaoY1<)=h5wdc6M zu`_Rf>gc5oMTWjrJkZ^BQ$IDc{gk)gCrYzyN zY~;99abr76CP@d0M6deHh$?Q^;XK(&&nK7oba@FSNkJVXbVJ3XU|<=L#3Hg?ZzJQj zqej)247Sdk=!1^|;Yxd42DPuVY~Eg1@nz14W;#aSnh5YYXzwihhfCuiHv?Kl-*O7R zzO?;%f=al<+ZLF6g5GG3m1qDCFaS#=(PNs<(O|N$sGRT<#l0Ko5%=6La-;(Kr+>ArP;iqYx;p0mbdAnBn!z0L2e)MC ziCccAK=I>!bNDV-!?qCFev_Jto=M^eucJP48Q5PV9?)aO_R=Whva|0oPVutALo>#j zA`}f0fd;@t;ka|r@k9|UXKrQcDJ3kg<%USM7dsxho$Ee%p(y`7VypbMq??yZU>dJSk&Xrv|IB{*s1Ayc zRg2vc)^sN{rDdlR>M>%uZ_Tx0b`L!uawyCw@+%xy>I#^^nn1=<*4ks?UcfwmcQf)j#P&y7TgCw~`Mh?AE=3Hr?dMbS~ehscV{yXXiqC zoFIrU0t;g#rf#70F_l+q-#bI%_Rt-cyK%GDk>9U2?i^g}h=7{dgX=e{9_nkQ8&zG{ zDTQxPg2ucw@CR$9>r`2l>rqF!024#Tn_x^P9iP?nTAV*g>Qce|+gXZb$w-`{E!Ejc z14C=>n(O^_JI8)nC9P!?I7#=c`|^Tl>SNb`(OiVKRU5Y}5?NpPV?>xLUkG_ZTsl;2 z5Px|pPy9O=|A%)mlKBQ1Jc>zbzC>ISc+`RUJG)aAKZKQ5hy)x%r(^AK zzN!3QIPNCPY#~#$5)p*7Kkgk@daQ?wzZrIEs7rRNSYnz>XSB0=E=54$cProi@wAPu z$f9Ithu?)JRE->vffx5rSE3F*S#6PNA`*oz5_M!~wxllkCNf1hs^uN8eSh)^y9&V!C6Axjlv93|~`Cu#XCCymHj!|)P zIWSGn&++{4_pU(A2qPM6rk+KxAlsoDcnk4a9%RsCN)3UG4R5U50=i4xo4nEE5FhvKL6EWb(Tf8@;v)K==}jkO;d7YaFo}Exong$ z;H07u!eH1U!qG!X1c&xOR>zk9>sE0kL~^zYiO`I1972y(?WIO8e=iV)bR?itzm+7o zqQ!jkIm>t=g)B7%N6NDAAclokUVw}Vq>3RFPye)ti%+!x&m?-gTR65r;0|nN6Ui{)( zUUcMSBPhu|N1U3r?xkq??i)RxuB190ITZ!Y2_SVEvV8UT3W8WChoC`@kHciCOBz{c zGSO3#*dnOU1mMft^!B&+W|>j@ezIdsywf7>tB`-?RQlLq!P}b@pPCUYSh+f6u2^f7 zF6PEny5_cU_{kdkk9#WPLR^l0j<RB)5Kjgr{-* zJ|&fkX|{>xTY(&K*?1iIJSCII!UZqYuCZ#*ZJwFP%VX;mo!%);=_7+F7rBKagQaon zJ*bL(HdQCnkn+|d(T{OXd>9I{^n4htWb*oHjum8t)w@9%W)y_gE$Jw{SXzk_RaVp9 z@|mp+AB{HPXvi+p90N;3#lRvM#m&6Zv+lBckwU1-XKOY`gx1_8xX#!dR8gdLTIkaS7k^m0V{4)iq4agh3f#Tt)bX1{jdPb$mtp#yhGH8S3F$LzmwGCo0 zqk^o2Wmtm=X4X);1_)oVc76NefMDCs^9EMYXHDTDS1Oq?DiWw^=~(NxKXprLfcYTQ z)Q8rGb^z|)r3Ig=IqI|PYx{uc`uAW6CDn4!M|~4>Q0n+Fg~Ymk?Yi+{s7{_hlkBJB zjf;;&Lvpb~;t&J!@Uyx%!smOq=m#o0wf<(sFZ>FflsCD8RP8fxwjX`NOnzxae;N4c z97f*)m?o@I3cc&P&KxC9&M{*O?n;LJFW>sm=rC&ub?AQpE9NAqCFob>54yF{c>kG! z^RK4-4ZYS-F|lJUV=x$mWrK=Mxm|97N83#k2EsFf#MU$#LOcX+zu`{|%Kb)VZN1FE zsanZfBHj(BC^c|`c+G=s4e&!A0AE~ooUaMe)pxu(5Yx(zso>oyzpKm^@|uV`UW812 z0-XD-eLHch;pw%_`MeGORbdX`=H5Y#jH8J<7s>#a&BIQnQKENjj*AThhtdxoRPNp| zf_(iVSJ~Hs&J&}W7gZGdHv8%5X0!GmOW4~#rutcBQ3TNqM#Z(_5(dDK8vMdP(T?OhRAPB2IdsA&$EU?DCqsLcd$W6&y-ZjZ z?zb&>KY}8#CMJkS$9XXSl|BeMTm00r)}61kQo6#~?K1d56?f>7c&HIW;oxJi{Fo-~ z)$bvrX-rND&Z@K=f}}$WTJYda%YTYD_E6nadWRW zQf-{mxCHyD=lg2goSBQwa^GUuYG79kR+sOQ+=r|*q*&n9Sql38_M;D+Eg|p(WteeE zV)~5397uE~AB&d`G52$0kD_QBvD>iwZM^c(O=Fc= zQ1Vbg4GlXEo$*=bdaEKZxns|bc4Es&7Tfscv@Npo)PdlDDp`axXyB#PJ6x8UQxT4c z+~XO;&%oB(DG)oW+)jBGfHqLi5^TuPZ&csy=RZsLTKC8K3_LTRLiEE}HCf&Ny*3 zu+8ry(D~55r<+Mb&tDaWT4Aij@S^X?Bbkvi>g^hpx^>CpXy9nDgSE&(NB}7=SwjTo zWci%g_!(`)n#spZ*Ue&YU*4sPPzIlDpFKh+clN3^J&jWd!&ED%hAV6dQN~avPjl22 zxOqBxva`On%k|p}60ZOJBYO)*$1Sf@JFqJ4-&7LM-Pt;y&b@pkG9E-AwM^fIE~-WN z4-AeSg4rS;$Qg|%Q4T%^TFaWhR-et()ZnV|2?SEzuNHr+x?CTiakx9q!0XgJ`In({ ze!hChNm^$_sc#6_Dp>gZu$l9QMv5;^`3nhu>_!I8D36kVwOhrcg@E)oE?E@5+o_lh zSu}Ab-%Uk1gMV73hrRMIu20zkxpPNUDcDq&H_`MkY(fX>b=E%4g{_htYQ1pC>B?=` zi$X8!{7zW|SDpod;fp5`TR{VdJjgRiH+YI$>K zIA@BnzlX051FrV=;BFw23Pw_#b8#S&#&^EbEF##4u=iphiipM&Oz5_Mr+>twL$mO0 zJCI?P@klcb>A$E`7LB~Ecqa8*sHAi{74YDdk?WD@FJHB6(uh|sM&7@1@cJts$eK>! z7EPUf=r@e^cKO>w9vDiaaEQ4mCBGw&K%R-Cu->z2FJ`E}J@W?(j(%fs_-n_o} zmhYA3pM%xBo3Bp}hFiNzaXe|g<|o7_35~kH7EXKjoXdolwS2AM{SIh2u;Cpu;3*vN zN;Cl@WBFKa+9^;sIVuS4h?-B^S**4D@`mwCnu*^$0tQ$hnJ__Bn*>7MfW~xK(Xv)J zt}O5!?Rp0NcO{XSkvh-nqw_N<;t?Lt_%5mwpH=HxOUK~z-vz7YoRXLy{_!JsDk-=9 zSNv(W#}F=Siq<4a``h$a<*=3-KeP80A|x7_B=?91*GtAdbMvoN&24{|&~v{Y_1bjS zBQ#?r3y_8gn`ZRy2K82!U@Y8OTYFc(@QRO?zonZxgcv#k#1v4>8-BfIzN8F3#mryV zw2W4Z)hf@5AD)C7V~H4$=^2PhO)pN?DnWe4-FMzWCw|mEuRE2pP8N-ZNVs}WR zm`SG#uK}-e!E;9DHvq2zE1cYht4qI1wssV{2~v7zV(P_uX_z07N+j0t^Vh)-Z`yjE zL+zYY9x2G++)_%{UP0<=)TfwdL$0nDB#Nc1Z=~VJlMTw0w2Q=4QN$zk8~|4i zinUA#6W4hp%M1S|0{=sBo;$tzkQ}xU-2o3|LulkQ>==`*TJ}$qPcus)Gb+iSk1iVE z>jEmZzeuf_vRjsMb9|z2$b@`#0#;|&-#9yuxP1I9r+Yz;cO9g*f7Z!QTpaCuJk31C zPwA*Gh+b7f`F`ZJlqp@@-{f|FT1c>Dkkt7O<9gl;{7zjJ zM>a%OA;t?16++z_^=bp!q8+_ToU{x7zG!#dbCpRfW6xnj#eQIq2Jz~?S9Z9stOuHd&z zK^cawk4P_MxlqQGJb*!5QXz^GynBP=x_bfTUi9qK^U~k^5@JPlq$1HdvdT~x=9aW` zaAWCe&L_XDZIZ&%L@r@n$KxU+vC0ht{bC%(1~)t2?^3t5=ks5BFRccs#MckogyKj* zS>Fs1%Hh+MGZrxmhcsomcJ3^M9I{okq+micZ}6=TW2ULY#A!8Ul0` zK_X)m5m>UA2jhJWs0;~wZl=FBKXM0VMA^XJfu$O`h2EYC8gyh^lo(FT6XDse8ey^b zNC3NAN(4Uj8Y9@vC<#jxtDf|w|z0UCY@tp#_J%;t11c$hEiJl z^C1a9@ho*}#2xOcf812LOl7msy@X#Ui37kgmxyy;tZ&crn}NaGPS-2Wb>71;ViiuD zJ46T@9j%AA{I6I++Xz+SWXtNqw$>t|pg$G`+lcw$gy)ki1$a7DgEBUvoZlEs8_--=-S z^)H%fBflqRI3Z@M0>J=2BEbXC>R&Z6S5*~>GGQv(+v@oAw19pO1Q^y_rszo?qA^NY zBwF{F7sHK1$iONVP*XZw$&z()a{Mv8cSVk+Hd2FT{`{(lJ*Mi{83jp09&+JK+qJ=2 zyFRzT#ROmwB>yiqY;uK&F#yU404V!bCH|jy7|@|OtrIw+yr(^PF0_ADC`>3P zB;WEo51RyGSg;_PY_7`iS7cAnRz3CXmJ}npW8d%*9AuEu&}>Y2cJ0`mXiYdZ+n8u) z!gGlTtXT0uX^FLG1kx%KP1{>XP=*%Vi)q51i&Pb~?mc<}*zk+x!$qY%TnDPx6Y!0@n~MYdiN7YJ? zSIQ#`^TwiUh*hk(9x56DqqzdOIdL*df#SgOKF_sHr*-w8`w3+vDc+Nw{%;|~_V;rS z-v86`iJp43yu?UFz<>@0EGjLw*lkQ-I*UlDo&B}643P&GS^!B&F@wo1_}|+*F=1A% zO}X)x4z>v9tQ!rO(OGb&x!MC1egIOezIlKh5`R05_$o$hE_pL5R zNF?gVW>!M~m|4w|OW5cTjk7Rbs%n^Jzvp0KiksiLHBo#c{wa(Qb6cgbbTc^h?uHzb|F@=O=C%D*|j26kUhJp_|`=#7&;UMqU9>Le_h1i z<6V2P;@K)obF*CDWj4h=u^;!j}ye)Up&Apbrw>D*89uihqMneOTSv*u4|_N@G8(|>s|!?*uF zGgl0|d;gzjpHn?;^!rMZ|G_WS1oqrPS*x?YlGHI@HD&>M|ZdO=FwYvGeq zSNK{ysm?%!J=ZLoBfm`?U{+e(2pFNhzAKopwpp^8TS20j0q}Zozl?OU`8nM=% zf?nV`X$MO{Xe9i;*%l@IT6+e|sXC3j;C81%XWG};d(Y~g_@(ya{K42h{fX#29qUi5 z6Q9r(aF_Pl6H2Aex;*h?2j=PT$M}Av9N>SG_Urrq9&2vbENDbQON+Y< z;D{`B3Wy04V;gB{bQ4t63E?4wf2^0!f2NLbSA)bP8$l|)mgxxKSzH5*1Ks3_l(~KEHAjt<$QnI z;q*X^k)D5YRml}T7?|yUQ^!^FL$}P%PHiO=wHbR~5y%Fl4D)DCwG?3)9c>x)MsL6-nR zWC2z;%j~p(>e$KrhTVVi?#z!tZ24wq=w*I(?6qLgKHPd*E1kuK0EM|9odTv}LJC76 z@iXqm^%tKDPE19M?at0%H&0k5SqHU;t^hV#zi5!4Lq-TmN_QPj1zgLAWi`)TAhv8W z#Ty(^niD_oy<6mh2{+wbW6V4p_5OW3_&Mg2pQVhl^A=pLdK^G!X+oNY?1ch{SUVv0 zJ8Hntt~2?svDAG5pnryk&JwT{Y``+1ls(22;_(05uFHlh5_%tPhHRgFU;EmtO_q*r z!NO2zgpJ^2NuVSLZwevo=w#w6W9aRqzg+DhJMydqe#ewhWtK8Tl}e-v1`iCXvRlc5 z4y1mWpU$64^~Jb3MG_=sqa39qbB-%L5)gb(hku6p0p^9m30-cA-)j8j&(7y*_GLn? zuFgs&fD|UdZ{seO2jnsv?xysh(JZxa5la6LUjn&=a{`e)tc+x29T7^DJkP^3_HFvi z;j{QG;Zo6v>A>n52ov(2qrtv+49dJ~J%i7)n!uNdgbZg)3+Pu!rtdaMjC6iz(VAC` zi7)sJ<5IyF&pD-Qc$SsRfcAAw%CYru1wVx3HsO~Zg-^=j5pBc+{m@&)tozS8s1JLV z`ql$y-O@6O5N&?4)KLwP5~{%c-G@71X~Cia#?p-2@g*}*|5-Q%c8?_%z#+*@DU3{m zF=R$f#gSI!)c@Ez8~^Be-i#RY*=~e3@%z+))5i@>lgsh=u$q~6G0F|*CJ+um4j!3l zXs^Q4?ED0{pJ=TjjWHW~?%XQ{ni*^F z4Vq<_6VOn4f|YHMt?{yi6XVfJhmbbZC%dRKx43pxT{MmIVlGd?&<95Tq;8}fgyJC^ zFxCIgSvs$6O#-@iWit``;K>OZamHY11QjQ2059kKFU$R>42;BaTN>LtJJ#4fR(76} z%WxpuDzR88oILqDB~U{2)%r{@+PIzWvK`)14XrdfHrCxczhY^Rn1i*CK~RFi6GTx2 zvG4>%?G78&d-yxoQ-9*LH#qHdz)JwjInlk=+3@c1JLd|#pe*GyHx#q?HB%ETA`2S7 zmk7GF4_(l$Xl$aCGU;%dt!96eQ{nRn{a84El0Xq8n#N&xUFlzWUNh-}v!p7R85*I7 z+My8RPSb2G82YBg)uQ#JNs5#*Dq(o$26_KsZDz1Mi1zlZuQ@>cs`>O2CV8MW?U~$t zY;q<{vmNEYF7Q;!w~WiU0gly-TKnW=Vw{Zp(E0!vHPf@<>6KjZzDQngHO+qO3GZE9yUa^eOjB-q zoA=3(o#96|G~f5|sa?G2{p%@UPPy8n!v@g3&HvP$I-*>QL4#51=bmk9dEBPQGVP06t_H}Xta!>s5~ zm{eM*Ndi5vJxd6pdHek0*)vKO8O(F36Rv*B6Y2a6m?Et0KkCwc;WRcWvs|HGh5H^K z7n2aUHf0=|wm;`z7MD&|lAUnklc7$q{PgtmfZwRJ*$-UWCc%1Nw=3IoYQn(%DEnYm zx<4F}YrKH$tCZKyVV^RU@(M!0{xyy`u*G+OC@#|As0(|biF4pJ`LXl%lCXcdRB>it zjnx|B%0+s;FEM6_F}sfmuJ`}>K$Q}gAKhf(FxqB&#>)wT1HcRG=YRmUUuA2 zgk?5+-~$-#=fqbg^+q@forQR!3aubBHlP1r}h% z6fQ>&e8*m*;S7Uqgj9|MNnZ%|49!=hTbl>jAl#}V8amsS|LMP;eFTApBhRmNBMQG; z<;(-7?k@-9|MQ}1%L@GX>t3dvDOK8gsXDmZ$h*As*8guBhYgh@7zQrLuo}x{LEAG! zYt1g}?wgH8MDAbezDKTPQ4+riB8%RuDWe$9p9-r<0X)=hvXP>XT- z-SI1lNQ52!1Lo}W)iR*rRSYHdf^OfSEjp@EhpJn)NI&~&%0+0SD9Q){4|uNNbuVX3A}Z1Dc5hw zLtaCeAH&d-Ak8DnOk;J<9>K&Bt~zALhoNHA^t+E*sawymTEPNk*dcQSIcAtLJ5Vxj zO+R8k0w$`{<|vF$Qtz4#%4|CTgBM_s_YcXJ(+vUH5*m{Oh2n#&?|%rBz@_G)MCYB| zhP1Yy*W)5&e;@qsKR$;Wnzs&BAw0c- zu*CYvBvGI-1b0HM#*CqVieBIC*i<{lvZ4v~q-8D|S^!#Ac$;>A{)xg-iW7gtsZdQt?b z1VmR%*kpMroBuu|yxT30wM8M>OT%~3O0V^dD7NAX_zJ(oKpy9Xnc~%@nhp_Sn))ZF<`%+_ z8--}dd0NWL;yh1kdwbU)KI~6a=%ROTtx#Lco04@$e-GZ_OcSVwP%FU>n72}&Y>TO^ z1;*=vfe(ZBShdG&5`jWgGDu)CDeKF8w_2ocp)2_;>%b)g5vn(5k&rj=BEwW$k;6A! z)Q#{?A6eLHf%*`d9U4ge9ywLXV0POkTar_LM-MyvU(Uq+ay3qjnf21BoaX*?^zta- z5`R49W++^Z%r#%LBcyR^3g%yABz2{{5MJ?h0@R#84}vBt5P8Fa&K1e170wO+u%-#p zM($n}dJTU+l-B@G9c%*v+p(uEFa$kYEo!IRWM4ZkfQ$Q?0zujm;LtOSOrc4D0LkKS zNnSHLzPrr=7&nypdr2wl6e9LWE1|MMGiIq&T|4qNq~;?PJo;<;C+d+y`aw{>M+}K( zh&hl9ZQ`-sQl-83BG(}p*Z`(;4V|@&Dr-o@C`Pn;q zb{WG7L!Dk)}EuTaTeg0EWcGiHcw-5Ue0mGSGq(29Zt&sz3-#P!9o#gnDaFy*?7^BPL6L_P5>#d>a1UP< zr^k!DrRLUhk?A+_j!!rxtBq+a=SqR8&G^op)2;Q7iO{nuKb_9Mt%n!>T&*a+6Ria~y+C8zn%sP2hcRy?7zm z1S91DfJfA!UPD>k6hPm$m6>=uPcI+Jk0i<%H^>>XKb#LbFHvU8IItDm@o?s1uMtu> z6vaWDfEG5vFc1fyre`Sf^sf7CqFYl2dfN|W?VAN?yLdb8KSkS-ixjsIN;N?^U_^5( zyLY!Tu%aXyPR675@Rt#$<^(xVq>LAMae=?VG&{Y)S)9{RSxK`=Y14B_`dXsuXV@JM zCB5Do9zGgN$(Bg6^`)Us+NjJ|W`_TxMc&MwRbkg4@Em1Z_HZ4XgDt?|9IP>jPT_|o ztyit~)DVef z9kpwZfo~P>xk<<;=N=oaHllCH`u0CN16&JOxrg;?8FTv_GW!^$#J(6N&;@>s`Sdb295pxQKitRL3uL`IVGL5?dhksA?@6V;i!<-M|Rb0MTU5U`KB zO<1O2((=_)(_GY|e#+Gtx2-N*Iq|=Xd*vX7lZTpOcB+rlBj`}Gmk{Mla zWSTc@uXvQN-sP!P;RB&F`$!4UMS=_sg?HMaSV4!6-BuraTt@ft=e$n4h|>h1ItMAf z|7yCMnNDZ1e~@?~+Pe2Ce!$QFy~eOreWt(Tr|&i@cWFz4n=3Dp$45A`-hL zDV0=Xe@n~P>POk^Eu}s}qkp74FokMpDK1~$!E}?F=l;9NT0z)xDlwh0>Rma%FDdX2 z(E&{mS%S(*)1#yS5etuMiC;C&a>U#CoQgwYPx$GEjP@a*HZTE@4o>~7#S%WGw~tBh zPy+>xBW8eD-DrQcs$XG4^`*V4`YZ>v#$?-X~BW z4%ovQNT3Ncq>)tMh!IqpVM(oWngneninpy?Iq<-Tr|N7P-Ov3?0wfDzY5>+d3k$#$ zaT;u_w|(s70VUzYh+*7*@}>S@a1_u_@#D1E@TZucS7r_2K0vX;S3xm_Ad*zVh%U0= zc~`l!9e?&ElUltUF~VAVsQ| zRTYXyIi`k8h#`6S^6RsbGIW|I1^JO9Qp0|p5er$mDP&gGmaVGHZ= zY}cZ3?&%gA8kr&*1=i1gNescDT8=tZu)QPI8iJmdMBhxCZAOHc=K2r zlniu2xICVR`>e`Tf``eR^7ysvXISI1a(!=6Y=0=KATq`vGf5taU+ry;%d5Hd!%s%e zy<8w}81|V$)X65_2@c+!cs>0+I(h7qZtlG&(rFZkYCV;D6bh66s~GLbwOJ0nw`pLM zOH6}Os-D}ljPKq*Y{Y^Q3}4%-l}|&a7mss8olB;6R0paeJZ*0+1(77O0S-b4fP*Ae zG`fE0C(Mn@m>TNOY6uqYq@|@m6nX$&q*T|hh!@?o_yPz52@4SPO#$NrJEYx-?O#&R z`GPT|VLB;CKAg&OwL}X^VL+Qk$Mu9j;1ZmkiZlfHcMpU)G9XE#V6ap$K1bV@T1zuf z5TyhFfjZ8)5yh*seP&HNk%WR-@G-R8UWnm7`N)%3=EOufbx;>`7cc&^`@+Fk zw%XU0{lT%#g27mLb?Z;%gAnyJbvv7OEga^YI6E58)wfrcK3=t> z=?4D4v@9-O?a0R?<%>-S>;YXBuC@&mvJ3oI6+CTX?esBApN(A;>=niAT-EbspR(X3 zu4gq@qjhzz(%;MCcE{(&_0ap5lA$u!eqJr#q}sd=zUST>2+MGUhR|ZH6z6W;s&=in zC+<3>uQbf`g3k`kK~ORsiv1Gd;dFYfxV;Bg)wDZ%@)u>oGHY0Oy|M?kGZ#PQAV0tA z!RbDIm(QZQs*d-nS(5+6$iqbW2UlT8{968Y#e;~b4n!usqDP=-@LVvr*abt1vwynX z^~=$Mg}CP%x`Xcii&x9Yv`g%BxSDUF>|`{*TC%qkd$iw5@ycCkGKCA*^7q!>?*3c; z4r-&;Bcr8Gc6rvLGVuLlF}b<=I$ESGzz~2Es1s$(H%>!m2qu(|LOY}LIPqkzzM&+r zl*>yHVdY@-T#4o_{x!)~bX6!DZXFh96}<v#X`VT%nTN`>%NsL3P2mVZ-eLU?D?{S*m+^YLX0@HG8csqq!bZB!s&F+ zz1mU@KdRb3lZgQIpsMslKXfsM7Zd>+$APU{XKMtVT&!wWUjsjw>1GITre>1Bg7Q(s z7?PpFt;ffgiSdL-AdBw4th*RQ{t?#2PueBPN7MXn1dBK3$;!F=s~b;oL>~AIHeDT9 z(T~KXA2XBg_*ug;+8m7^JP#iBNcz8BiG%L#D(?%O|JXyI=jWJRHtLYaB*5o|U?m}l z$8tOU1oO3wM+1${wPxY7J-g4V?`6*`gQ;VM>k;Eg$IPKSs*G;h883E`l2~H(|A0%= zv*Q1^*+EE7%AU8m*xsdgK_pz#Eap&2K*ABVM93Y4MHNcR$tGImg_rwSm8(ip9NA_S zMHOKO3 zdqBpl08zalj1Z#}e!(nw8Wnm;R3Jb&UqPJ!LL6{g{M!)pgqT=V$PKv#OCDvtb@%~Awj}1gEf$})eF-4GHA{Q1DODc8m%J8O758D^I zMS$5g1r&4OiA!|u6~R~f}PtgFsC5MC2-e{e*^CKnOlO7=-W^pgQl!73Iu zs+#n-IvD?C+^&%z(;YN;T_FqG?B+}PD;|&<5weJh!HWsU#?bTIH5#j>Wg3P`VH=wy z4^jmQig5h1f|n&OPiZKV-a3I4V^tX4jW6ODCwg@{hwHzKi9v>Y#YR2Np| zH;%X6lGe?G>dc&Hk(S1zHG-Q6)tR<336T#z^4*V_s)6*ur(g|eHytCtrHM+!l8uNN z`#-}>$lN`Ydh-bO07-^D{vSLxC6ZtRs9`DMFli>5A{D0cmJ-d8+u0Se;%!(rNLbn5 zPPHiDxj2T-;GR>_MR<<_RA4$%y=APY=T=;BYvRFhHaSc+kb8zf4tL`) z0490f56#zBW}tl4p11Lx1e2#B7K*7;mWoZAyL}+_O0y8lMGPR7{sk5pCFrQiY;C!# z6<%BCK3etNr2NM%8E)aqM&Y1SBdp~jx--wCoU+_~tOSe15g^K_IDqA|p9_JX#($?X zL_qjCyPY^Xsp4;bc(Fa$G;KCZH@TG-a^7`LnmnT0vx2)l?PPE1J6Lp10ihSC_V0s90 zrE&CWVfnn(22W*V8x2fALawW?V5`&0&A(`n8+l%C&J%+O~28^2Fs3N92KV1WjO08AoBr)ww&> zdv}wEuJF&1+j*jzw(1N|T$+xGfbs{4hmr!$71q7Me85(Cc0XVvuJoGL%6vOLW4Yr6 zTNdJ0oiZvJ-7z;sLhF!Brbq(+wm^6(o_(X8Np&AeL7ixR+pzCSw9pWB|HPlvmc@m+ zSE=fu{mrj`UP#~r-ztvKeFC{_n{NM>r|-=5u)`g`rKUP*o1RE3o;CEWzRYv(?Wv3J z4wbtD=Ce~;NX-Meh_a7bvaI)c+cS-w?6J`+D;((gwGl?q(&EPfy`&T5_6*t+9mG-@ zUHD`C$kii&o!uPH;(#>r?t|Q|(%-=O;NidrS3V}su6-t?9z;qU=WC&{ zDi9d|*qOn2sJ%U|l~hpor_gaKm=Q0r6lgtne~2e5`=Mpc~>wwTE-4#P$|_K zd%@Y@eOoYf-<}%w0E9?K@!X$~t0J_Gm@vOXX_=)v)Li(w+o5roNf03eNr>R#by(_r zIx&d!a9^j>%}qT+``_Sl`J9pY&>06i)z-gSXdyCCfg1-liKQn|E{K{J0b<2JB>;w+ zlF5PR4js2nhj_<%)0;Wj#mGGH`413firwsEJpJShyoaIPP9u{1PlGU6VoF4H+0)4N zJ^JC9gubC`Z!2`Nhnca(Y>u1rgc5%U{#eUhuKFmUdf>~o!Huxacv+76im#mMSn$=j zO|UDhSfAJ%E%$az@;GbF`c1}%%rTE8@*-p#zCRiFp=#X4+4RFYN9nxG`}x{-e3V}x6bmeocLTpl$A@EiHzn5{ z<1&IA&t+%W*w?+?q~qf<0h+wc0Bk`CtikW|d2er?h+3Sl`CuPTL-~4iy<|Udx+J)UZ=_0z?3p;((|CW0T0a0#@W(PcTU*e{$3Y20Iy;Ws_oT}P1VwtUL zwyV_IsH*O3*+m56Ok%@FQNJg`Uf|I}bR0x`tVf=6;fl2w%c!WB_$ml>+8=)(v5TBd zZ1FnqH!{oBamM2C!Tn3X=q`l7WztztScxM6rif4( zZl*YlkSG!VhI<6!TQsFWlF1<*GLk z51A+KOdW*x%M=e|L&4Cbdkr z-`}obXXyo!ym;ah!6fJKqLa{SjR|vamS#pXMwO97tJ(6#GoJ2?8P^3l5PXrGh{X*G zDUHEGV=tR+uojQbOjb1()|h-Yh(8F=yoY@W!QF|c7U(I`F5ZJCMVYazr{wRy_U~bR zJRCv5JyOw01JO8*a&K~3K67%>o0}@TOQcj>g;or6JSRT+x#Fs-BcX*?+c42l8{wv< z@Q|qRP)`Y~*(U3{>yYEcGj2U4L038*M7vE17Izx&=i?2j?9~RSGQj}Ej9e4if?DrA zwrXbhAA{~>c=}!SWEk&sML685BSYIUYW1D$0?gN19lG zE4Lp3zuq6n_6nmYIp1N7pO2`c#?|ekZn`ai`Y|4Qj3ZZbz8`^qWNRLoJNUwQ?5JW! zHBwDIAoihtu4Hsf)uNq<04?|!?97wQdj&BBk-#Jw;bw11hp(&UChg;2jmaA$;-|_| zAFThntE_&A8-nMKpn;>_w}sM~EPsa({XuX$=i{xWhVGk#A$gf4ObyeO{3l9PO-18W zwdQsc;i;&8QOP+3UJ`ANzs+M<-PyL|90vm0eV!wS`0TxJ|1{fiCMBel+z8@=-kOCw zga7hAsG9HuLQFA7Lj{srnV|9Co@@{VzhOT14w6 zT0u<>v5&q|yWUG7R5AUu_!U>1$?&M*)LfS*!LKodGDHtBMo68l4PU1g#wM7lxsine z^NM@7XB@S>=h;Sa@@Po2w)imiIk`o)lnw{o(a7$9K4JmR z-`BG_PtKd`(n1uU9OsLFmpoA~K0W+91c|qQ-w{Vi_kHUi*Zhmf#jD>_vk2R167PB3 zT$cA-37*MZ#sC=Li0iWi4BsC;qola;hnzojACm9KAr!D#cjw}t)*mqFA%91to9Zo~ z9ak-1x!cTUicv`-B?g~*KYJ=4<0hwR7wu}_RloWBU9W>&Jeu`>{&L(!+jju1LmcDH z(aUqUpM-sk*E>%ySd-OL<2C^%5*~6-by5Z{j8+Az>FgG~Zk$b+f zcBhObg_sNkBN5G=zifW(Rw~hk_O=Fwt?90|CkfEz` zU}D=(2YSGZ0*tdNDVrM@xj^P~X*?ADHzyF+h#zpLB&a!7iqefK*g;nDJ4 z9;37qEus6--0Z$A?3QgxjCR0aEZXvM{!6ZHtv-Mi+_A|Mj9+L zm(@wT(G*NuZ$wo3C6vVF8Z^27r*0xuga5bx%WqEyRSL$D1?xYXCog-vPh+!o8@{vf zHr(eCB%oc0)089sF1+)2x8QP0ot@r1ziXVvKTcVHt_oL4>({YK;jsqu5(_Kj-yp2k zV3SB#Cn=r|hV&AqD?~`g`#awM|Hb|{8GbQ$d2s!w3wJlrGr^&58VLf&a9WfllI6#4 zn~+;^{d0*LDbmguj4PB9=ktsC#DS_q>;4q(QV!refpI(o2!@6)<@#AeW4&zcSM%zh z?(Y9_JFPPohqun46_ONLP7r89*!vE*Y~`L~1-HfjRoGF^>U-QS)S{@&^3eT0GU_+~D3Ew}=?fcMcyUJlNEh!AA z7>1L08tAMiO~@OGi{_^?#H^7fT>b>28TNk7Q|!XLzW^L$U$^fWojCO`sN!y*m3Dc#LEg=EPY(&6-Kw__c=Ugrq6 z3%Gr-m+n^#KL=s`(570Nec@_<_MNc)02tnp=W)86eyxa3xo)q|GurPpwvXrSnk(Nf zYCxC@Z79*kZ`8g^wX_;K?c1SGh1Cn8WKN`68B;inhxI}%#$fWS34&ZJ5@N(MYWvSU zuhtKHU=R$4Gqgft6cFLH+GA<;kXcu-j2$p(-%19p?ZI#q#)>#Ya1uOeVs`;l$3sjekG>Gzi&NJ49#VJyW{1W#~0ixUh1 z@3)t0L~2X}OK$6<3qO7psr%tqZsR$U#%Y!&Y2BT8lDeb+j4Yvv3MP(%i=mOnfHk~SIb&x7D7n!s@mr!ktP^n#F+rbr#dTe7^VU(f0r#$^bDVGPNz z6vL7vuA|HoPX+Mt3aBD(wNzX9Thhdf4WLyWL_Bg_e$3l${s%6L^BfOxR2Lw(jJWGhW$fl!^qtwOHWXziEIhHWiz8uHW7=iIDMN$~A zbL_G{P)HTzbna?7xp6iv&d0S(Z(2zg+R#mSLtb#!v*# zGdM|6IIpYyI(4{PAp5?T<-Uh1ZhGWXZH|Rd&d;}n%k^{-q-=-8DKy|&1;YWhWB7p; z&Dxw#f&F7h#kA{<_PY~_vHg#hPWQ3&AJF{gzlKM2jg6Cz4ql%>z^!8h@Hxhjg2OGi zfUJgk@xlz^?!;(AQTDZby?gMq)3-ClsDj`bG1@QcM7!wT$3$C?eiq}qzqEPd<$4f< z9?E`65M&I9G$s)wwxQ3yhR^NXnqt2}PO_dal}$eANz~u+S{v!}mwrWCI1+xDDam65 z?+>u3TcmHQ*D^JcgEPSL+Q4_(y;EK5oNDfdepb`gWeZTqLX%!KkuXKtU z+LBqV-A+OOYu6#$qa-8}3ZMfP z+ll`T`O5Wbht{8a5`)V%{XGz*}Y+=GAC{GHKybM+Gd6g%*=biwb+9-%|p37PRm@5%!c7D!Y18)wGqJfeK$ksZ7?eu_7g4gF|8;;-gV$nb}T9LINS|k#U61f+0Ezi^*y!4GqVRZ;Og=aYd z!$p};U>(8(HwR;bA#}QkLwd`1gLk)hwvV<=guGoM9eIK@N*Dop3og({=_~lM-M62- zQuJy`tXkZm_gT&vPk#Q*v)Z`q)YqUe@RW<5`yA1H|;iUvxe$?4w~y@u!sVf2)^-(s9Py35{|s_G|YQ9t!K zM>K1_&*InH)!Hyn?Sxo$%o7ZgEq`%czDtV`W=x@Y8ju1_iWH%X1%}9bvSotdt49yq zid01Aa1!t|hjX&X!g|k{#^7^0QbQ(NHayn7`FJes79!JtV+C5F1cimS5SLnDIz-&3 zBS-5Y%V$Z|JP-a7wn&NQID#cfmZ2E9$P9>9O+wJFg+)%aeEHi)=RbX?zJ9O@i^OP- z#CV0oIZV{}*y!y_9=7zHT)*j~X3d?_T9o_=XE;YEA0WM0_-nu%-l=Grd zqtZLJ56=1xpx7t{oaQ$&tuWkmqA*kSqY%dVs(#A+8453+q@ zrcH*&EQ*x&=8vI#&=!eQi77NC1BD@Y8eS;pe=>%hWsg}ZGOH7>q=emSNs=J}E8sE( zbZ%m|r3GVyA#}QMTFq?m<2AFjabZ173p^&vtiVW=jJHl(m+6tA0-VQ zlU7E%UviZH$Epid+CqnLrmCi(sWZ>=SEXq`)fuUoYTOnkY6C|2X>n0zdBKowe!SJM z*HTdqdVL!c!=__}{!xD4KgMz*xhTIW#(J)ZaHtDG8K7 zDp)?}Q~gK-((j2{n_itE3@Xt!a=ro-E^;C+NumUB@xhVp z9tstHd4wuf7ixxnURp4xLdo7oZ(<8A&;K}Tb%z3ftldM6j40x)#Bn@<3Doo#SO0dV z2upTTR`BW@3{_m$*q%As?oNg&+v<$osRv9j#c#Re^IuaqT%Rqk+||gus~2SOay=vV8Ur-Lae>D z)Uv2uy@|V=;bReUf+#VPj4=$YQ=-pRHwjP^RmO{!SKBO8hzG(Mxe`EBNQ%QG0wZ7} z*E$HSFX<&q=ONE{vtEwYu?jCr3{YrV78#x9ep*(fzI)ly_ueHN(_gKvFD+ltL~ub7 zxusl}%c-;Vp9o=nF|Sza9C@BP{Y5P_kME*r+~LZ1@fZ+(zPMq!ar^k+O_|UI+&>NI z9ekCg+UzrZT6PU9ED?Z6GYZS|0xqG1B?FLgH&Bdnntu>Yri>EANmm|%g8G@k+nkFcc<2b!Syn~K(S@4?0us?ZS(r;nu5yemYNsPpi zA{CMz`R2EZK^O+@Iei4RA8xQLe}2rP?Yn6+G?b$eg5(@yopQhth2Zw>9DAsCvbArj zmdgpK)Mh0-+BR4od9_EqElOC5fKVusRahS51QMnQ<~$MDe{y;Ta8osCQ1jOeL23Q4 zY_iA?9eA}_dpo*26t@EdI7TU=M6o=1>HK_QVV`@_v>{oLo>t1sYqRCh?5eN)>ZpS} z6$>rrB_StA6r@oOyyoM-U3A{%O-V4sI{81gY*?|w^=RD&==+kQaygD*FrJoaiKFO& zw;#UX4-sZAUcHJ2Dg7?=acm21<8+GnU zrQ8o1A5mK8S!R^^8Dl(8V|7-PT+Dg)Uphm@1+1|EO!Jkcu zP62|FaS{izAoBoEFwDNTricQ>O(`YogOYw938o~3e?BG3>!X!1YCcpl6fa-2zxW?4 zBeu)Wyv2vtgC%5K!URbIB(1>L1PhQ(at>NPw|~>>wnkds-9zV{uSJA&EXl~QnmMWB z`Z3OZqv4RHUcc9|2BapY4XqffFuZ^RM&d*~U!s3($jk$lRSPO>v{rfqtS|Sl#q@o` zqchfpy?v1>1+WAmNdm>9ZeQ-b$%H84sO93|Ui-hCi@bdi6iOs9R^~B|h82tlMoG06 z7I)k-f7AOT9zBWnFV2uW=XXSe^9+wMIDGx`6&b0BlNORr8T10$X&yX00 zv%0I(ijM|7V@UPo9F`5{CQi5(S28DbPIYtJ!KZ*f4bo!X3M_UZ4tm*K+ zys1_El!-$et`i|+G@P|mJN@xF>eYgKz>q!~FdCBymZvdRWS5?Lwnx)Ohcdd9vM>SG za6~Z|FIRlLqZr0Wg!iu84;8{`DTMGG?t9ydHxFL=#PRnyNI zgWnU4!T)C(V-xIY-zOrTmsdbBBbO|1-gkKS!^7&M*##|XtAE0G&-MBO9BW(e)i3>e zI7tx48hhlKzb!`&+_C292+d;rG^z?k!v=VOll-78cn49D931SX-t~b_ZaF4@AZN%P( zoa(HPdG(pB@|D|8pIQ|@zMjMqfW&wn$8gZGZsNm!wQr3q`Nmz)%>Z2j@{E&Cd^ zkHI~2Km|$fp7}{cVNXO{ZC2~u+0Uh2>ei&lq=zd(u$03e7EAD3s`eE;f(!V7XW;le z;3bo9we~;OyugCI1%!*+J67w(JZpN+16toS4bNi>w8YVjBJjA(Gn2A*+uMI@5Hy-A z1ATTB1(Y2G>0i?Hxyq6QCv`3!@EWLNpuV*WTXn+bYiJkq982LOhcP71 z@C>O70=6(AG`&$+M04xcd;7L&-C5h@LzqKJ!srp%KFtQh?;Sk$vj; zOAER~Y#)5}^%?YFTS92zfziNN7hah>q~(tAfrv%f9{~}UM3E49%eD+*L7i01il=iK zvCy&Ri#9W8Yqd$pQYj0G)E(K93;zybcc#WN-dok98Y@ zuRpddEeR^h81uqvXJwl$n?H1IST;zYI8G8Vio$S77hW0}l%j(**|&FOzy5Wh0S`Xd z*nn<-7x!pa2T1~6@1VYO5u~rq43Yki zL-Cf1$vFRC{5kic+k>$j#*!?~@(fSYI(xS~cc39d?5HBLtmCdd zGHfv${z65O6`Ep1S`q=*X4vTU@BL8O)HTM74h`0+hqxJP6wJ_}oOZ*eszVX)eY_?> z{L#>Iok9hFr`1PG-=g+_<|_b>dGWd?N<$DMy!w0`^ju5-Mg(IxUleHX{{(#pr_19q zP6#^j`da6m?tf`#Z*8Qvg`oLKjLnb1;}?77%QU=WK5F^)!T|yizdv}+J7{Zvu+lrF-0ILMN~jYZ-Ap~M28KA(CJ9treMKJ#|Y^T zQ2I6~-7Z4<))>=mBJ3w{nval%T$mZy7}HFQX&OqC1!FPDI`i4Z4-LEz9T$vXF_NS) zlE)aDWOYomS7KO+(&E4Z$G09JG!<9)!$kur({|a?|7jBlM64)i{Oo zioj7g#uRv-w~zgB0kLLPftNHZ;+(KXO-T>6rVmNaSuZz0UriL1N>T(N2m;BIETwE* z_edY*)-g$$G1AM|Z_~KP`sq}8k?+GgXjaHY5TpaRoW4M0>uey68oYZ(ja6+&W@u;R zz*2I+^uID|r(nJBfvrnks2N&xL*N`dHUC5k&$F#_8a)0>n;I5WwX2S2~lR;OP$-y90hU<^yr6kvGxl77#q&{*FWPHX*kH;-)JU%O4L zhl<+f@i_!c;xLH=q(Tt$j-8x*1stth&rrVL8{_p_O{1)Jr=D2dk;BmvD;G{V0+A8a zE3qtZt~>u9O5!m}AbDJ%g=&pYI*R(dSUV%us<^BVx7^t1qZ4T%w_==P;CY#jlo-3M zW9Cn(w`muepP(_CrZF~OAV#qad~l?zb2$MKFVt;)?f9GbUwv2GVe^tgbQ@3QZ$bln z9;bW6fE=fkPsFX8_xUFizsC|*meJU1}I0 z9W}bYUkTO;eecO&3_p*Z7V%myEqcHI#}~uL$0iuT@Ain{1QI3)h9JFN`K-nlI&b}` zTY)V^c#cTIDNxACVG-~v?T~Emuy@*DbE5T$3bkl36>WIKaRkOvEJ5QeN8-9`Y+GtD z))z6!y1&U|&%V5;e)t_H;82>yF_~jzMj;r}};W!~udnT>_IrY@VN)jY3E~%QmRhYiVr^fOayBl;GJgMh)x-D?)gumZh(jFW5Qoy> ztBrF!Yd;Cu9> zCWiV!^JmrPTT8qK=UPW!&HCt8pjjPmE;3bs1LqlkbRQ{uU?0=Wm2F36z^b?pLD+!! zKNE3Bn`jKi1#`(5`v1fTRBIygVr`+d&B9$>J~!IYbI5;lByj@8ku=8(;^eMP|2R`b zQE0gO<6OOHJ9m-wf!bA1UA?BQ!*QY3p&&^VF7XP>2y)1E_*hbO*kA~qZVIhKBVrvI z4KG-$Hrqd?!xkXM8)KXdUK)izFBVV|bb%36|68 zKDAOq8YUrwA-!y^zyHDWmES~KhhUP(5F$g!yhy>;A@^2@Z84b)%dKZ0ZQcFIK5dTu zl@e->u@vR^ZKzPJEOP9dHS^|ON_MJWtlAQMrAAx|+~zL-GtlU|F9z_N-2(q>>v6Yw zMGmXZ8=y^38*6wuqEw$Xtho)XfOu~=B92X^p8{8b4)sQ`&11o{Z~A}$esFgH!*|yk z-VR_*)w<8_(3`lHYiWnm=@zHg$`!PR((@7v=SKeAw_1a=)1gr11?fkJc5|D6ETABgQm*9#?_aAC!jI7p#K?ukW-7>C_UY%ew#T$NN8I`uq<| zwvIDxT;0;3=P8OpH7E@$c2thg-ik4{FQt^z$q{%C_#8|qVcHZWPqW;*{`N_28cBMgxeTQi>#XY!Z9n-&0VB~jG&d+?P?i0NNg!W&joox49unrP8e&VIsKbMxZp;Pv_4*XRO?`T|YSyyC67w_(Ty zQCQ%c)}AlbZP>kiI2#>W02Hp^lqm2DY@@^46GCD=mHw9X$FJF2t-T3*B)@788`E2qd4P$cOmnmX$Mo)q1vZBMYFb=o2ukaV ze9zis)U$(?h2dj*E0oBQjKGl;OU^mapKG@=t-#C4%!ti;-+F#Y#U&HQgmt>hNECq+ zB*p`Yf}QTBswUGrR1XK&)b_rX5}ei-y~Wxa-?3r9TN(koGnB=-A}TCPlRVB76v{|< zk1-e<458DJjLQ?_>3<|`G<;&s-tp;^7YlUW7l(8RB2$!v^8_Z-3c2?kZrRE`#|lW3 zI0VD0?(shOXNl-ft^9*IC--d7b`pR$5uU=z!F6Y+q2Yw+zVf{K`7L=b{F8&qH2RFn)(^fRhMD z5#Wo8-RcE;w4SHo|1sT667t{daoTiprOwFV|jzh|FJQzcAfgOT7>ee-C%3L zWcc3NmuUVjJr}L7z+oIq@&u1zG{>+yuQJ272l)6k2sP2~tq12bQi4IR5*Hc6C`ADxFDN{Gm#)E{s0Cy{T6>@U zv)Z9s(CPs+g;O+vkvvWEBn9_a0)+J?{A7Ko+r_WOk1y~X6Y6>jCumM&FoMKMQM;b1 zTEE}1J!=}JXg6fmmce)!RHPNsP>OU-B|;in_dsdbhw;r&x>*F;6;>#NjZo|n(r|s@ zyVXbvX7Ku~5@Fx06k|FgLK>D6rxc9EQS0ce2X}7RrnPvwA=FvLVK_kuK$LKq{pFXz zf3~)Ll%xsu;0a$V0^PhFs^f6<k1Wy8%P)A`D6-s8YiJi(4*gP$NArEvOJ;afFIKYBU_TuB`Ipq|bVUQCh?Oh6ohp zcZh}aB)p|9Q9~ZCLfQ)aZgnohCwE+~DXr~K)Xjk)&ua|9QVK>W7|wM4+Pmu$M`q$& z_0yrH)IXY`$uhOlm|CR=lOi1UG2T0ARx=|J|F2TFgbYiNv^gaR8=&XWl9KIP2UoRc%i#2z&@$`|rEi1M43s9I^aki?x&uo0fzm9L z{uNsN8=>@KC_M{GPlwX?LFutjnt;;#q1`tRO1q)70Hw2%w6QpA{dURui4`X`)6Y6> zCa4O?oFhMI0`PPdBtZt+lz``4CUSzGx4z!~l=Vpk$(ivA$%-r|vXa8Wcj1qzKfZ}_ zJ)O7ywE0r+Th}yz2-ct}PErEP$QUhCqM)_MA;Xj0Rx21A458DJj6W+E{P%}-@sBg_ z8P}u%beKalu#zMAdI@SWuRmM^@0D#HO;7E)!iKcVui)+&OKrB!tA zEh0+xf2=SgIl6p%)hL_()bfSPM|&8!Xgy-7JsEr+1;a#%3Qw~bhI0x?eQ(u>SBo%A z<|s8RO6xsyDQk3~q^twV=wKccHN$k-icfghzT}~*NTF7~J{E!FurzC>ddlrJqV`Oa z?de)wUTNG&Gj1G**eRSjKHzbX48ahb=nr&4Cm3d5^E1rN5YmoVp^Vl8QaS=Zk2W-O ztkW*BnE9gSgUL30PXFV37HIrW5z_&G#1ay_W9i*Xi<$~(@LG+~xVRK$f+4}y=#FNX zApvdmPZK0g`$Ix<6vgto2#RlR3jEqX1yO{}bXhr9@u^0TG)Ol)-Et4N48}Pqh65sC zNS0xR;dA(XlfE@pM1`C?TTJ;l>bug)54BS#*e)L#FemK|BzZ$i9N-yFkvW`!$(xoj z4zAIVX#0)-?0EGLG{HqvRQMwoa4`Aq@nwmiaqzw`Yxad^+bhkrQ$${6bmO1GV!yF?^D*QCgkLQ0Wwkz^@>7f1zDu3hFo{MmXiBLfl|%~f}n zfmm=_`+r~a@WQC*>zrZRIKA>~tBeKbp}x*8iXj|Aj#Kas9G?ermEQTPuHIwQtG2FR zXLzEv?KV0Wj7tj0ZNZRft8ncJ;hXe&`fa$-rIN#$U)?@=z$5r_J$^$^m|A#0Js88i zlWBYSv#W2MrosnophyPe6`aO-oEcVy++-;duwj0b)CDZriR4&l4{si zPtVyn_|C@Y0d?Ux?QjY15jmh^u7938-6Q-q2zkH*N8>nPinfI|+l6T>GZ#!iM@r)f zmLX`K!#J8`Xx$CKvs~!)URXp;TgD^XX7yhh-lPzxMNDEumc?)uHYqekY(_2HdE>)p zCjF)vzKlyiO&N@J1a=93Og5h&I&+-9@eV21l{eZ4?sUq)4dkAW*uH;YLywB15alxBiaBUlweX8xBryJY3bUwTIcIj9k?Rg89^uvM`1K3ivWkuh{xsRkXXOT)wM0We;To=X9GRE zStMLGEfbi`;tVg!=*}64z$h3PB?V+O)U)}_b+S{BAPHN7!9{{5Nt{(^n6QmDR%2nG z)VD43)>(L@qDF8XMzf_3hNXEK$5;sm_@t+N8&~e1jr45RVtR0T=p*54q`eP+7jcU* zll68!plmOY$PliXu$7xuF^FHbxqZhPIp5Rz5I&wH z%{~5GpUw%e82Im`VElHEgrIe$J)aHTsLV#(hZpzwhQAveV;Tj64dn~aV%OHTD`V|x z?RG^W7Y8f}M8DanM93&bqT<>QCzSE~vC1{e+K@78IjDiORr#P=p9g-aA6_~b2ziGq zEKYM2AbDBYG5o;bq1%Tipd^DoMJXFXz4uLw`9%9YYTqSoZEoq=CH4IfyRKK=bz6<* z1qsLm14sf$H@!b(nWc!`HmRQer_@bGyJ;YhyDno({A)vPfNMKr2+vtXHLL`ZWJR77 z8H|xvCO%rr&nasZN1bBMsKUyywoxkv=5-sQiHV1YJOTt+$n!Z!AmW512s996htrjp zQ?2pI*2}J>6x_zn91&gdC{itBd#@F**(SG3F8GhP)vK}M?N0`x*lBF=5 z*J(Z9;tKp)UJ2C$x7fh?8Ql^`po?H>oTga@qbQo9NenKc0)+KNw6XPY?r&A+R6TSj zyI6nx)*K-D`i%DFjrR2weA(WnV_Tg(zP@@vPJ2sf11YRoTie#=)gSn-mbOt(M{m>$ zz!{MQIDvEETWSG+srQb`u!Lq%)d&}NRZHmtuxi=9ufY$-*q)ab!1<$3+IF@9Z>>H# z`m-p42MC;q`L#GimLiW1Svm5dEgxsVdfQkAT|QtHH}Znu2gi^NCE3x3^t= zdeOe257g1`(nXw>d6B23!WlwcfrSLk9RA9`%+rTu6%W0q%V4rgfwCul;y zCARPee%+jmDx$k>Mw@QAAWI`art3|*3iaqPipMBi030uq;~F>pb_Cl$v6uScfEZ;y zb;^hq8(Pc^QS&+09jmN7gx)BgM{g7;oWfbQmBQI)`s@fNNa7?x6nL5wMNTJ3deamd z>r3is`_p&S`AjG63T9i8l7NFCut0Q*83%@WpLb=a!^#PZ#s?O%<@;bFXkQM3Ha}zw z`mT#&2*Ul;e6)0DD6Qc(YJM#t9Jy-;+G?*C-+2GS0wuigBr=7u7()}dC^78F=F>(w zo@ia!j*#s~3))3q^$71Z`N!wsAlt!rvhIC+A3EGTj*&RQaX87b7^Cw8MVt)ac^Rk@ z?zGKaU-RJCjp~Ox3uziKJm6T4AUTvy@~_2^ECe6RLu~CFzSnYABE^-s!qF5f(hSDo zu()!HBcO3LMzx$sj@Y;N*tR}8(0e`;SD%Eq+H~QRBTw*n!2rJ#HlI_<^5(kp|G_bd zVR(t)fyDQFuWc_sVW5ek_8E&e+zAHR<{A!K6dFS#gmxGwVYDcSK*nLA-G+qFdCRuu z(#1E1J>3AEb3kpyQr7x0V#-9b(s@X(uU z;S;*nOxjk$)tro=22vqh+WE(!bar7wjN?=(!Z@W~=XzgnKwa`B$M}7uU~F+H8%cH? zuFv{ZY~7w{n7epPcx!T=0EEP_GB0z=vpctsz4}FFnr2N-sgzQR$~@d!DHy+C492I@ zgVV*QOLJ^1%D@3k#=9-NjrF8s)2tb}olD2qU(;gRne@$TAd`*G9eCmt`5sjm$&@(kwi0B>&2 z7|=V<)x(vS>+!M4e^zMqzlq;f(&Q_L)G4ER%xJA@7_>w5LLaqeJyV0z8lGJ0{M|U) z(tFZUwmHKS{20v=3Wakd#`5qa-Q_M6~jgrj%r^qF=+<&62RyXpt|E&rqd}4T-0=y!!3L(J4r?IMB zWDJD$y*t%rsp@&|Z0`_TY?0Zg;20s|vP{sr*>`aG`7cjgdf2Ej^cnR6r`SbR4MoG+bGXQ9wpB};w7on*n<=vrLh{Zy!?QSs zi#Q8T&CGgh@M5W=8yXp?O@_=U#k{aHmKG30P}U4uoB=Eze1C(~Ln8oRQU~%?WAM1% zgcxTT+C5>XLbb{XK|Ia2dh_2uI97!>q!3AtkpPKPfFmC6pS+^z&ZoI4(=e(eli_jO z&MjLiH0+NStkNt)Qy9&X7=>{<|6vs$43yC7{?HE59=9F8MZRg!?P25U&={>KxJXN! z0N}Vf|NA14an?Hl{Df)_bxajkK2Zg=sXt-E9$uRA%LU}AOc5MTP&iHVBuR1l&}r|z z8{V6o(eR|L@-^kK(5x;lk0MNK`-FT&Xqd}IXO>1zIwjzV*7-l zm5MiCitBr*q&|y=mT~_7G^EGN&4)-4mTQ-CJ^tn(-uY49%lWTD z+%1ln01a z-zZLBln;6@Ro(B0#=GcWO@|LHVSP&LdCJlM*7(J0KT}+L01|;CLEBR5hbjn+Dz9%T zj|1Fq-C`Vv3dJ11k~)-&mTpWzv=a_0(5;y5>;&Ox=VK(gAmKW#!wLu-36i4hr<4-b zD^fq1p#J`+?Sc{_th3Z8=W9vFGum~S8s-1pO1Q6-7JVEkpM>i?56YVznkmBihx^kQ zVZ5|-`VH33czt4nvbtB*_OoWCw2r!!^Ys^NKi??lT6wc)H^w+WW2KW~ou~iQ`in%r zrIymVgdwqrW=H#tzTM{^SDtduQTHfzRt@^P7$Xs|C#ggpVG@rE8+kD zHt2@H<&6%wQQ=0t4{BzJ!;Lsz-TtHN>fhqm0kx0bsQYUi;t+?j-~XG%&)pkh982qY z9R8hjQJn56+j>=uPvtnoA@wo}2Ao)}G=*d6oai{WHfQ4snP>9O4j%IK&|i zaVRT5*+tbWB8vCM6 z2%Hf_9+%;er;kEeM@knKJ;(O;rmp99tkwE2)u`)77r`=)QSRKa?k*lruBTJ3D^Kt^ zy}9mIPLilFW5&&5n+q8=BaHOE8O9(S34WMXXCz87X)? z4sWgtICx3GIGJN5fD^529eDl4aYHg9#gGb}Vp5o%F$VR_Jlj`w>Zh;o zhz@p7atubWI7iV8L69sQR(E!#V630UOKl&uysPSu2Ma=&n?h{|gu?S2P63G{#4koS z|9op=b7N2S3zVtHnqqbjJe;MKf23*B>>nx*hMMXKT!Gf{b1Ih9=dzk!ZwO8gQt_53 z|8I$?#~>)(5>fw_|G)-f3_8+Yw2ghgtz-EXZ4M7NhML11!*hTUWCo*%FSVuW+$kb)u8lLXwETE`YEWrPAJ_%#V^{1y|TFZ_UT%4i-c8I2gK=i`W(D2 zn)+U2Fh(E!D{M#qTxnRxw^E-B)}I=ILl|cq1At3#`JztL`IuG`@OK4FAIqGg|OS{ZSlPyZt33TW<51m7~-A893y}mc$`v4 zr(1TqNA&doFK|m>fG^hr`n}h-*Q~p)Bxs`+t6ffEW!|;fxQXkoHPp`D(;+H@v%F)B zkTV+G?sUsXI^R9JSKA}0+AgH2#%rx{K}9u!$mIG6suzAdM8(?Hp)H*O(0k9Sf1Fp- z+E%7DQGm{c*t=+hZQqYG=e{}fCOvslI9@pB$QHa^b3HD>Hy{s4PQ?j4a}M<9+O148 zX>F^U6uvBz;RD;9gI+&#=rWQNA{mmUX^x;-n&ugnhDo6XDm%0cQN#zfWd|;?+vgz* zASi}mDVD%klHgf=0Snaw{}W_?ePsJ}*uK5vE?7}Ta16_1JWf+2%P=$nm%yzL?23=4 zpi0^Fwsya<|+NJ>^HPUIaj@cKNtn1^fBm2JpiTOh0+g0>06;R0i_#4=~_@a6-w`e z_J^%ddMK3c2c^40=?YN#ByQHKnLJNl37D|o#A zGbUT`bjlID-YWmA&h$8ZDy1P}-$_Q$8gN>}DAzVEN{Jp#h1OUqw5qQcXytxt`_bx? zcbwHWuoV?ynoDsz7z&V>%qSwx;`d!@(eJslyDF@U2Z<~en967%;}CkmUvJ1P;s2!t z(Js%Ve@VaJsN)@n(t(6{7ZmH9$t)-Rp7|f0x7WMfnPoiRBAr8(qRg+jHVj5YKH52_ zF>)CYHbAnUBuF3=X*^NyNBS*IS{m<#XHE`40`8SWlBBXB$EYTO^9aNlv10 zni4f(i$k6{x9R2zbYX?wNd$oCp7siR4RQgrOU3+MTKhQEXF z4!6@c5O{qTmWh8>xF@6Hg)-_~%XQj(jmGjp^!!tX21$rby0r4uz+J-pVCj%6#_uz3 zka4d6FA<8M;FfYCOkqnYpYBlqt}kO@OG$+QsWA#Mq9tbAs#IAmHC+|z=Vw(sU&Wes z!mTQ954~?P2CrKd(GC+tbQZTArYQR(TDZ|1RTdI0J8a{2|IlT-(pi0iyr8Ek%F#1- zEbsu2W31Dc-7Rpv+u46#hk0-89t zMp$6l`zK=bkiFJeviH&S-Pg8mr-iO_e~zYSB#u^Sfs;v!U?cU+AJCD}I6{rJ_y36T zs440D=$`q;c6@4&#q$>xTpcGB^i1K+ivT1-A#jFgc>b64wgWofx4z=iIP>$b;M7VB zCP4U~BCg`_?|^aTy#9s6#9`Z{)_;Ed=MT0b2fA*H#c6>OB?)72g@%n5l95^eV(aqD zM>mb?tUW2B8z)N+9J}wt+t2z{1YwHyj@AMEXnIK-_nU1|#q*8+Toq1hhm=KJWJm^= za0=GiX@J1`l8)Pkv}*V*XnQ_>@VhPjg9j(fXm8hd zXHokST3~Te5iy=7XFd1fGxPuOW@tk+t(e;!%EI7x+fz;H(e1a^)ud;}kc5j%$a4UJ z7bTnrG($3}@2wi~>ZZ3UXzDD{>dBSXdvYl+CL+e?rClD{0OX|Y*G{h-UHQ9RKmUtN z8Ie|iO!ACK(Q@*xyQW%KEvTFjCAV6*0?ym&UBd4f|ARIe>Y*nCM+<;tF^u9k z_m(y)7j_OYco%F5PhC6G?{7OK5(zE=_wOteC2}laCj8K_!`UL%UK%9CyhUHLRm$z~ z*6AGuW-_76W_g(xSRnH(*gs?X*^KqiCBhq~y_h3mFXs1!Z7|p~zI%7t`QNR2hTJnk zQar$~vB@he5ClS$ND|i6%s^n2=o8H_8SVSp{&q_vUK3Jovxe$TlE7GomT88N2?rSG z*F=B&@(YFqweK@kD`j!IHOlw+QYvrAbt0hR?J6B8FK+I~mNNqXzgpj9hz=@kmAmqu ze`yP3O6#~tH2gcEOI%hGhd2~_AB?mwm9bfb(U4|;xKqQg9J?ZDRVV^2$UG_X zJgimG%ZSQ4!~Ws3sW03=T)W~a;{K@6WQC=0il8Mxa3Z0Ztk}nXxPVx*DnaWm)V-HI zOjifrHdVHNwwzpT`3>oI1*b`p=Wz}vSP~}~_+GL%6TlysP>ro>f2nuR5mXbc|3X|~ zhjOn3TuxtK!Q=Dp8fsfvC%s>ScHHbShCeO}ORjFG7G0COpRwpi&?DvKx`D&Pv64s< z49hZ%0FU3D2?-%HHW{q;>Xq$nUF)?A;K917k?+BaAldzo2+jR2mrxc)#XZ}t_PJg6 zyfAQ+wnFkk%^(>F9LFd;MJjBe(Gxs}>O$CnNORB}GDVnkNd@oP?Zbq@;;74M`f-pY z2f^ZS&v&bCK=gcF``jkKwmbTamIc~Z7ezXHIu+n^xn=^ap#!s~V z-l^{b#qE#@Qeqie!6laHyQcmY%jdUdR4-*hD=`8tY5r(^3c_A--PGl$_aJvIf+jG6 zqB#aj;h-2WfOzor`7oz4A z%Q>9he8ULAm+R>TTq5wi(cz{^SHH+iONX*dEh8qWu*z-i^FBSg`|wlfEr2Hoj=&g} z!#Rr3AE~wO#PWY`&FGFOqP@N5?y;l9ZecVP2@b<(k|8*Z!dRWNw1yRfvA&3o_8qm~ zJpAq5VW}SyV=zjTM1tc8cuc=Lgvz>`{U&3bm4DpdFkIGxEadqdq>K@O!%2|^q{HdT z%YjR2QKu5(q{y<52X*#0e!Q+Bcn2vub4Z+UNPhQP{ec2Jem{xcxu3o5HGX_oie^I9 z^VZPg-BWWjsZKD>kS7v0#Q5Iz0-J+NuLT%b2Q4y`IlU>HZz3@ZbX9o=c!Fs9Gf$*_OptO&!C73DBy#W?I) zr8Ipel(G!0xaFetXouKc-ozO%u1EXGBnTE`35sM{oZv|g-ZRhT1%BlqImV&(ug-i- z)x2Aq*K0%0Ye@ot;xGjh6mr(`wV#fqXQhQ7a5%Uh#<&q=#dZsAY z*K@P9@V!;oOM<=f)Dd&Kuhe#;ze12mBuhB*@?8P@y5s;qedkT-IOg8HUp|yr6Cu@w zcfwnY!3A54(S2t@e6RJG_J1RFdMMhhhT6qDO~KCxn1a8v#CX6N4T|0MHzvH5hv}s+ z1sz7?yhHH$fGf|J|9~K5jN=rN5^2F9iI_h~h44X_?JI|USsB(Nc=pfKVzD(wL$-bA z{a^QaW?gu;0~0ubAz7X$1rer)sv}$NwAXFc>5blPv}tl%7()+5762h^%C+N z5@}bYq{$ai2Kqc7k#x13MMUrlc?*H^C%SF`>ejceEt)r}e?P9jOHliMA z!9$My*z_gGzMR?&O&;s*_Wf4hy?`$}SMK8;kv(^Hry>W)V@ph7x2qicUFQ#MwV1-w z<2XT4vdBpiMkz2oPB%40*bqJTE6**dk)0LZ#E8QgiBve5BzOQz23kbD`Hr@)nfA`t z!;)%*kbbzqSij^0=Oxkah8w3F?-=x;Uzo4$unW{5O`;|t#@Xf9F75kYvbOkEB!<07 zz%farNrs~Y65R3C<=_Y|s1YPDa2$@YvdqF~QOm=LL0DhX1NIlXcIo_Gj}Rf{3JYRM0+(eP2NZ$Pxo2k< z4LM>eb|WX*4^gMwl~7}`K-4oWwN((oyI z6>866D7_C#e*+64p!6mvy%r{+q4dj8dNGuq2c@5Y($k>yLmE$1>zXv_|Lh%id=y3Z zE*%mGy<7>QgP?3L2q=W!2?&Ddv1K+nxDxIzkO>TAC`AQ9K@bak0)hw# zs33v}*uVz%?{~S~BsX_+C4{E?{&_dMw==tMX5M@A=FNM{cGkWNy59#1y3-3P4}kvP z2`W>Fm97T0H5*%=WA?%6^mO=~TmqtOG)y;5YJC2OCl6RdC$vNM*l>cdIRzi^*ae6E zPGFPVPN&@m&t`2n+=z5Tm}z==!#ARvMVrJ(mLzeUq!^B1IgWy@9|zV3>Yjw$?3!yj z*;$#l=KF}A4iZU=K;~p#5g3%GLpXIjTp7I%d(gCL<>+7TPb^(rr-Wl5ET?b;#{rC2 zm^I(sSpWJ#_mmFghtvtV?}0$gFQ}YlPQL(t1bUZYDxHc|o5&AY!8&ht#{g~wW#gEa z6nPn@B}YP84dH=1P)nMpmdB~wcoKAAA9iGXcT;eAiHdK9JXQOvjPI4PbXbTufl}EAJFZvTp`-loU8rBTs?VK* z;x*Pz31-lnARo`pFy@* zt)3NXz1sh@=d^y(>U$f?)&<{>)}D49{=ZhwwFW4M#RS7V)8^$9-siV#yT)Mxr#NxU zCb*=0w+G1nREu82r>4VW<$cMT)_#@<45x2e#1=E@xzs=}Zdn{??A?#TQ*{+0XH>Gf ziMnq|dJxXKA+`g{U#RSkQ1zSdbm)=fTx}O_W~lAh$zV3%@_C8}3ep%M4-E9U^E`qx*X{Os*TngPr$)n5CRzUe z?Ndi0Zz2k`0u&Aani6r?nDk+dX!hBsP440gpWi&PG;CRD8%~O_jdy#-cnbsx1l)AJ z1C&qKSm!@7=?R0jBZvyNAMN^H74Lya5NlYPit1@)BzVTOv_p$&hYxCoz@CX^#x9>n zko<|&1&RYe#xY4|XmaN1Bd>2Qb@>^W6dsrMZz5z*h5~)T&g@mS3on@3+j4)YR;cY&jS9!6F+SiH z-^=AK0Fuw!S(br3(Bm!u9-kd}mmSPG+pb*DXZXC&#d6XYOj)n|b7IQSNFkqPk>EK} zz(g5vaLDI%?NYdYj~2-A1eITc%DtfSA;=Xq1v*i<0U}reRNe}0!0oIXT)qJ+H?5-$ z*JY-(j<+|E-iz#aDT@*%Q4-GatOWaAuC5h+C@(V&8S}=RW=FN1yij*(C(iOVySJCi zM-qMQKHw1?+4bsm?6#tBhBmLXjm)XgfSHD5h|5iT=cII=(Mj{oITgBD?xZQq=J0!{ z4fc8LuDrg2*VoG>gQ5XSj^J>-y>j-BwWi}qsGz0MY=l&la(i{vc-yJ)+FT0adFmp0 zOSJP}Z6TZ%Mfk*e9j-Upbsa8`#5EdLm^y*%v{$!BJn2U993|os!w6)E&vg>g3igue z)0=OreRDx%z9NwXDPyES$y7*Y2Ib!Hb-!dHEq@jb?yl85CH#tx=O{&xG0y+q17Az& zxOhxeO{P$Z!T3G|p*~Vshn9n~r@HHS7@;a1M!FlUF(uz=?ak#0R4iQD-)$ z#kgXagP`oMan^%+K9WT(*qLaPDW}c6!7F=eu7U@{C|DFj*aWW^czi%sPhIr^pul^J zO9qPF1>~3J^jGSorlrHDQ#D7t&mauLdG(#Nqg6cg`42(lI;WPkG?4KB$0i5k_E82h z{QO6T;QB|Z&%=&)TD>C?ScASQ9tf3nxcUsv!Hi;y>8_J^w!G^$M8p@Gf%TmAsVKJo zw&~&SKX@L>j3HV8L$Wl^5`rjV;iCmqMd~K+nCiUv=!?w`SVBz>Wrrwfs>B8p*xv*4 zpS|u{Up_EVJp>MI?R``0TbeIFzq%3HUgacd+@?4{kzI6v-rjEGfXjEf%IxXCtv`v?yFoZ!i1u9Bhio(b?=-VcR2rid+%m%($0-b@urxu6GTbw0+ur|7lY2e4_|c6q z^uHt%JS__pA#r%v{vU?a7(X=KcE_!cU$_H@NEvdj3+HS(`9K;2JlzFJkb(bLtpa>f z{@`M#=yrJPiKDMC@9>@y<9Zo>r4LQhm)vpTyGI+NU#N_-BqmCfh~YFKm~{)zwCSHd zqtrR@<2aKdmCI3UlD}w+RZ}7#3nKw5NkAqQ9An{7U8|hI65^IY35d4#m~QKIfO?>r z#xR~Llcx^3&_-bMXm;@OeWy!h!G8^SUED;3g;#w2aoDuuc(ZdUk0MVtVvPTQCd~_^ zK>pGsclM}1Hk6)h{KgT$yAon;?o-pQ9S<#d_7}8=4U6+MMdLip(j-fSIKV7Yo%cH< zo%fHJ{yB1RaMfY0AR!&f6iM9H+uKVTZ1(}LZ44*|@({u9kUxIy_H}#t%%Ak(se=wW zTp_UPB+x;JICPn#rp?_R;Tm~0L-CaQVHT(i9oRn{0=&LJcnkl=;rb7Ldg)cqOVz)< zO2fD(>-~IL;7VnK+pV6S(GJ7Wkk^8?!hBN2F6jC1)g6vn#{)Q3?@Api0Es#YbkIQu z9d!5)LSNOV_5)k+^%|F`y&Ibcw+q9GBLV#U@$mOg?Tk;3kE|Ko?&X4~bbUkz9dyt^ z2OV_KL5CpY{V~&Hhi^I2`a~Gd0DtsA77GdM>1XWUYiOXFKcm$2xCHgMWW$^Y0l2EcTRaf%JB@I z-0(v9b9({-Qzx}b1Xgd`^n=T8`ha|}b^Oo*q@8|nlBNcY(vOn(gDw(4L_ z?O?z`L)h_Naxj3wWdMLcN+M298r^9cedyMz(83MA|t({>a8eW>c)6t{vH5>73%!}l*X22 zut+fmcfv%dcTgGHv;);C>c)7lYLST-gnyrmB!dodK$RF(J`KNGGkBidrScImN=WyWhdJw@E`bO#h zCF${fU$pBX+Ek45XnvG>v|uiy5Dr&YDn@MI7%>Hv;pjd+p|T8pFZ|unzLzz`HXbgv zOhvihAjfW-G}?8R0xW8;=nj5P6DK zSj;Ag_`=iQPyGv=D$V0|t-zQ|e5OL9Zn}A1%kO4dzthIemc+2;IDzLmLgZ+HCO>c4 zY1JL6=?2ebqC`Qw%p7q&!JxzCgtSXkZ!4%=^&;y-jSDUHU2kKsk`AZDgV$D*q4Ij@ z`eekSPy?nCmF@6ys+xJv-~V`@`P~vK*8OsdV`IpK_j_tE4wXo?%>8~Ss=2#~W;9+Zy%jcp^;;06I9~>K@_=hC1fgr$05Xxeu)=F)T-5JjJs9 zM4=Q1Yf6u)I^k?Y>Wn((8P4Amo@_I@ccux9$4H*VIhtTYnCHu?rOJkM2x)AlGLQZK zEUzu1!UT3wLqy|*%^%aHD<}Xi8Mq`n@Y+O>XLn6FFsXZk6^k;pHro7^5romKsjc~i zCbM7q%YY1U&v7))kQhS|97bRvIcIYr9NNMS=3x)5YJ1BKk;2F0EGKiaB(sF9z~SS! z^$(9jTf)qi4Fgj0SD}OT^AySOBu%qC$?_qNHMf7D#)(DBIoiCS!wqYgr!0^{8MJXt z@HV^4VRwOCslVU^u#?)v8K|gRtT}0GJ9^;KFtv{t%SEyD6&C=v(%I!54?J+~bCArR zH~(|?f8QM)hzy8Cu{eQ~1Whs`3kO8fAX*ZovgSIO2Z~?aR;wdAn=wP+JVsJ1M{o?q zF>r4TQvE`zBi)>CG9Ts_+_`0Zq>)7^G9|GRP%ue^N7kJF;c;k7{mk=fTZCVTtT41I z6X1$OF}RFlI473~@YBO*9j?D(QKm-3&0{0u(02QqYn(s!eEOe}z7SwC4LDKYX$ptG zaK+4wusF1(LFW3OJ}`OO66EMmB%G6FSq3}{;L)*7jr}~q8|bU9QAbCvc@y{cj=7tn z_1R^9vVXr??bq_H+U7vi}<(F6-uW(+VF`g78fmSy3p3rXhqK8Wzua;Kw z8Lg$4=*(9|>xG{~3&D}*qCQK1UOO~$Z;1lUu>z-%f=I%>^@S0&`~hZ57V9#N*BmMy z3_lVC497^E;CM#1iS9y|4CG-Re}0COw=eAd_#7>Js-YXi|F)l1O_1M*Cqfehak?c` zY>5oaFTa!XTC;bN^N3^=UY10Tr3nh2M{afZyGzWA$2{``wTw?U&C_~jeL^_uaXgQ6 zGDk=(OYG=!=(~d4b=3w#b;de~;Qi~-F+R7cf>z0TF*;Dd4nL3!u%RYYUZLU+(Di7^ zJ#T>4^+{8!ZdGU?(nKfe2!Lian7!>|%K zK@k8DKo*GXdi6dpABHs=#mm}qo7-2(JM-hnQVV<7wn$z95+~6-PDuwJ{`#*DqkANy zmaK_!&iYtKMZ6~w(6Xk$d~6wWz>yM}zN`Rff}|CR;lz}WZkt|y@zXSByUbX#cL#GL z`%YxJ2562^aE=9l=U};32U)krY<+cpJGoJ~nA=VpjfLbExv2`Os_|x`)&SeW#SxN_ z5g1Dl1kKPSLx*goE;mLtXc-Mf=9%O6&s(%AGSP8Ba4f)Bj25JOa#NO;*EA>F0u%Fi zzpN-kFE$sPdw9mozGUb`juP8B5BPH2E*~iJ6$%c&SMWzuXmWEeS2Aig@9h#G!HTA_ zjfh0Uo#ykFUDpl2U-Rle8zzweNm4f8@wh!|3bx{0Ajs6pkSNQ!KM`3{L)C=h;Uo31$-WDtY`zt1sU6wC;JVf@`hE5@TCF+-c4mwtMvYha;X- zq6HS`Ng1PgIpmy@IquDgyUa;o>ER72wL+zf+L3mb-Dkro3f{hJXL^ z@(uNUcc%LcI{cR*;TnJ6ge&xYSBh?BbN*g)uDj2{qW;a%mOv-L(>8Cu+vCd@TymE} zyTfO94HX=Pprtv_NAAifH9P!m491uLbLN`6Dc@XIZ?U#(J_@zYp>f=n3naHk?(T4p z&+%t^240)H0Jwns+pKS2d3eL1>RPo&RtA36RFjF-e8_l_ulazv%j0`{jHuo?RFNxZ zSK&pTTDF`4pu3z$<}v2tyXikOx0s74fO4a%z-v zN}MK?#L{n@XYO*(6CDn;*Hn`*E-U5Tm}C;81%hV;StO?YGh*}c21hcgK`%`p`twW$ zhwH(lXyfA{GZ^n|P|!w?4F2 z+kEqVRrb!ZZP65&o?&f^3`>imASi-D&wTc!ug{fpzW(G1p#+clBY0iQ%oM|a zf6sa?;!CS=8Z<-O{K@A7j(za7cTt1KAt%IUS zieeN@W_bMbPQ8ZYp1!V{MuLfmpp$3j$Hw%RnCXoP`!@E891Me%F@_Wg1&AcP$b8^U zb%COO{OS3@<nr+=s`anOhHurocY}$&d&~INA^9G7+T;lS!8HYiP!fK7BU#(eykq8 z<#NxPH}^Nr`QP|R-k$_V@FdI7ERQohO!+@n1_<;V@*vJibFTOFk(~{+Ll#ek=V6N7 zCEHk*Ab63KIUF!I*hym5YrP-*s{N_zsBN>H7(ck-MP5e>ht=lJd)-?evS?O(enHl6MB_X;(!2f1p_>TV`RH&t%$_~?x+H@w6+&vl?tA*ubLB*U;1Xj zoObAUa^f^m!jO8o?7o0fBX=qG0spk^Vt2`QSDv?ai|^Y#_g8A^0_S%!wiiPkl1yK* zKKj{?;awXdO|Sj~j4Ua$Bqq_6D8Uxk9}=Un|Mlj)B@;8JJ>NWx zYO9KRm3wivAzpSc@OtfT*FcXu&m%ZtH5aQN&|Zes4c<^&ksSFo5)7Nni5vGeKf6R5 zcDIJ>5{9&SK!M=#f^J0xo*n1b^}rf#P1a`h9gQkyWxmOr^G>f3>pnJx621I_24?|B zQzTCl#Qej#T&Lw#5;Uq`7ggwPHT!z(ov{8lw9w@VmZwRa!8n?w@R0Kmv#UpI;vMt4 z8pG!Ks7S7X9K~S@!Sf<7hPVdKuO1$Uw)C!9K0WJbgPUVGH6UOZ&v7^}(YTB{H4rWR zTVQscaSsUS51e@qCHI@`=l!#DSJ8q*HFq*r+YOW6kJ3k4t-Twcli~|vs zds%@*{J=P$FZ-;YYtBC0Wj30L`FHJToaPChBX~T-pMGvqc)h5MwQM&(-HIaCexvc? z?O}PbOmK<>7y;n2G$niOudm;iShXf3`B509|6D4F79pYR-v7+MJRp3R|A^Mj1tG)H zN#V8vk9!<&2`&i?6ny#Km2Cz;Fl#YUE!LB(`z!d}Ws-Y`dD_su%;1xeH~CnSmSmp7 z$vI^I7`|XBWjF{V;+gWQN2AoL9y) zzO(O*KTpeqrJoiOp|T*>`YOBKSYe+r7+%f9USQBK4t#EL8tEF}`6 z1VmI6;%5_rF%0naXsjWj^xlVNv2V|_>H8x4C1U>3MqmoyBpjY}Es!jCw^?5HpkeyQ zZP4nkD*S2Q*4NR^Y4`bn#|E5s-(a89*TpRt!}{>i6G>5&)xG9g`|sPcrbd%6%4$GY z)s_IZ!N4iFe0FJ|$2}TIK3HvSZ3`HbVI0c14w(1Ntvxqoe0`Mo;u)Ir9|*%ap1?xm z&!|D6Cn7%TfH|*wmEW=twGFlB2D2|3<87Ti9-+9K12}=pH`pim)3S&2PCj4^#xQ8t z-$pvz95OGE9^G+!LTR|!gos;CeoL#O;1s3E)LM4usMhS<)M4tQ^|u)fI_Pk%LK!DG zYz7~Ux~2At?9lxV$m6&~)97w@0Gq?^_0?|iz0DtDDG5?4Vr}`bd2XAo?#H`m%y@km zqX&c8fY<3iCo1=H7PvjWzINA`61V4{t7mn6jl3Zf-tV5LvcidRx+3nc7UrZ0##Ul~>NiHVdj=Hv>~5ELP$IQz|E_7JR{TT=#|nv+ zJgz@CpU67c@3HAwk@Ogz<}hAX054!z*obf^Q)9yhL-;aU&pKjWHh1gwwI7eTa9}x( z20X8j5+%Vpj0LGq95Z|FthPP%Y+7j5veU+e9IbdF1y$3R=Hk2c)!h5$CO*pk4 z8K&yZOUy})hLh&*Q(ku8-mEoRF;&S$;kMkOf&RJVu}N;1*XJpeeD09r>fMn|ePhOK z#E);KXy@%}7?Djew!V&Gf@2KucmuTS?Y6sm0!IPxbic3npRLnZr$lp$PKtuB7050( z4a3<8jE1x3M_#v%7~3IYI0j5naG9rBg(P7Gd`fb79LjOenIEeouIm4sw$hlH6v}Z) zo(g0o>T35ExV?ht0E2ykH0BmB@Ozi^tG!|Or{e9^?!U^&Z22g-JavyMlj~hxYm*K- z=y2)R5a-OP#UGHb4bxT-Ul_s~0ZTkwWC8;+Pl&jP)AfGNue0Ld!%?GSSB+9e{XbSS zaJ+#Is~Td}@_sSjXa8{W^=-5@PEk0un!#;goZu)Fe4xMJvyTHgZfAkd?gU?7_x#-j zi#Jx$JV%l*Q-2x_=gqZWaold)+6b*)l!ii+I1B)il4Y8h>zaSt(2ovQhjr80T`um$ zqCFpP{f^{d952Anp$EVPbHjR%|9M9f&4Hwx*S;*-7=qk6?(l&IJD;dl{W8zp1f)IS zck|S}E7yFsCxW+)6Zao9kUV`raZkaUpL6P`pKf%%U+RvXaW*hRzEGn@9BXrV#_jLs zNlRy$b~sJw+2(h0#1$Tw30dNJ^4FjH-GAp>ccsJrK(&p*SX0glqbySw8)F+735LJS zHM%9eRPa|sFH=V3WuQlU18(?5MiDUJK9F$bsB3dYeH=|AQ!PxScqe`}(M#*%1D3MXI$!IL7U zaP2IIUwO7@ct$kQsBP?^Hn5`IM?pn5r1lwO<%|iI=kd2c-t!)M|C}Otmc%%WkCB@>df1zvJ*U-`La1oPeg~Vk_hT}4|eldVQ$qO%9LOUkS(j}=iv*Fv637TeR5@tw)3))R@1U}Wd_x)$;D~)(M*S`4rL|i_^Bg zj&aVeKrGDbhg%Z-+Z&w^r6v25jA~AM5Ap##SH;tA2>#9tb*N;h%wk%jOEcxP zk8EH${MD8T7jD(e<)b2-%Q=ZsBv!ykmLsbif1#V7-@(TW@|srGtBtp}UiHvD5rcx_ zG+=mzVHJ#}!UhGc9|ebw?S_^$55N3fum0LVni=N29>ueMv%BO0K9J*fIDq8u?EZqs z;~p=q>Q$xDmwQWHlct{zjGr%`55(AL@KYcr-e*vt+K)2=v#HH10hg_xY#qYWM|}={ zK5a(j9su2UjT@B`3|W@ht3G-%{esC5%sC(#PGPu2@B+oM(!6=?jPFnCm1uz&w&qxa zs~GlL(IVU0RlG^<3QS!9^ietNuh8DouZX=S?fS17mzQQ)mOiucetU;PiV;8vI87-O zgA)=gAMcuK3{v5JnbA5Z+cIgab=!pf5mb1Fq$z@=aGvrX%!T#14?YOsT!hC?w&jDH zi~1feL^nW`)1uVD=IfWCGY@Se>Y z|5E*OVqS~rn|){G<{Dc*8ba+o^k-y+g26eGB7wvZJP#`r=SL;SDC3)2);4<1^wzE> zk#whWE(U%N(w>4#b^v%_Fe3xq(?ApUM+2?oAc@+{@(Nz-v!=I3_RuQ{Z6pf}AeoSe zxZh@kue+J0-tjkUjV854UpcqfJW26@((^hDZyQ{)t6Jz090T26dx^IKY|DUM$=;2k z8>01?=9cG=<);j9f}VOf0E*y0a3V>t2G>Ac8?=jAgKKR`AG+nptxrZg--0Wc0whwv z2^!v~ynw)=EnR1k7xbRGa%Gqg^ZJCm8wv$RkZD=MIf5ke@)t~esH(Gy_F+R(gR#L7 zzFgK^JImr-qn5wfH$s$pmgYzrBXF7|Lr+4dtARuh)<6wT-16M?4?BW+bD0AlZK-YhOIP!~IoSzT*wnLE#ZS(Oj8)Sx}{QeyRP8MCCc`)(llPL`< zNgkv?HbDbazFhnGW!*|yT3mSl_Uk7^j3H4z8a;ftZnb*4M2kZIkUEk#qy(2k`@5rM z!k#o|-UxJ*HNTAFd6JwY(j*&Y&sE*4MwC4?H$k ziLz;T<#l%01%E`FlI6X^$qYrvGRsR3=A6%1OWu%~SwY$#TV1(*$w3ZnrN>x?zSr}v zvQ4Oskvav!*Z4ek)&-Ay0*kT+d=GOA8DRL`oUe z$^HG>pGKt()Q8hm4S5Ow%`x50GUV%JbNhAfz@u$TV0( zEH{0NKb5(;4SMBnclq395xLaRYq-pdK%xAhis7aF?CVgCjj-$+2Ob-^CmTI4{T@bR zK(W`R$OE@Vu(Y;g#p|b^tD?=$BGp)M77DSW*$^(YM7_anmIvoPJ-hmc+U(q3 zE%Xf-%;swA73VKTvR*S_h|P~+jAcq zE9ZSb{+D|n!*u%Ccx}<)O80MN(`A2@agVwW&+BO0*82R==f|};KXlMRhie!1>-<26 zYtSBLG~8}^|K+-d)%B2DjX22=Bun!=&CoO%vJW`@tH7@(hoM>!EcU6tC*FHr+dB;x z*OBCG1rGlv^*gVoZ2DirzDC$j)OgV!nrG=+yWV3b7shfvi=-tH6J-*JA{XoVEF#V~ zBjS9nqV;Ql-nGxSe6;WWZHUds)4 z&3kUyTy282ij-3uFf6M`BE}vz3x^4^&11%6=PEvfMBhfIyV)^~I!7Xlz z=;ADM0>vr>DN|fXWX-no!#kQxupFlDFZyLyB(tzY3Ie8Jgu+P#%(K?i36DeDnS1w- z{YSTn)Q-Xk63LN_1PBFgXYYOCap**vVtM_mt<@&EG?VUjx5Vc7#~k!xF9QxL`qU|^-~`{SWrFP6s4sG2x7zwD95T>EBRz9TpwDL z&9g{F2WGL;vO-5+VDM>26G)ps)W;CPlLvfWcn}Uq4v%9Ugm9cF_#7XgY zCk&saxmxcD>t;{e#@l@^;Pnpi$1Y(L27hJviO*!>r0T_P#MQgR^hmicKdzx(;X`O>|)hoMx(Gt}}yD4jr^i=;tMI7=tw zF9^AdhQuS&o}F)5^wyCcpP#7}s)Cl6Pz24j?{B%;pMEDqc{VR8ud!-eM><8qI8`I(9+NMizw<@j5j1^=Olb0BO zop)w^ozjtg`0fC{y?ceY0)&no?$dW8e?s~ z;sPM|wflfaaO^zT_@;F~jY`uFc5AuO=BNYOs1EoC(}Ne?byaVF%_$ysj_*)47#~-~ z_!#y67_}ZPPKyLRuiYX%{FWR5m_w_l|Zi~}*DB&{A3LSLNK?fal&_Rc*4KDXdo}^3kehG;B6Z9_DK?fal z&_M?su5l>aIa_48{=)HHQ(J`zELlD;yC8Cs%(A3Fb0ybgy9Y?V`G<2)ef#@8#!_{u zYJANvvOF>8zSNx!&{3^OnjkTZW_gTfSsI5OPe<+!;PZ%>Cq}~)mLvO*)jhB?LW~=N z;7FQgXp*8?oQyYcmeKI6kNMkvlva9Z}|>TB;u=IL8%Id%Ba?f8e0 z19?k=fb$fC;{r`|z3u5b->k1=fKGrK8qEmqqPmDf!o4aul#GTI7SFK%rQY-jI=l=^ z@-#zG1W7X#M)EMJN2%@*{WDRc^(D*rdwM;ezBF<;ElCC>%S$XFiXq{&CJqiCB=aRp zhjl$~+oFZ74Chc;ax$JLC4!|nURGZI?S`rk|1du}B?^JoM7fXlj9F>v{o>)qlb1wD ztW5GO#rTIWN6=IVL1{HQa1CTgpf#2a=eoJpW;6{QU*(dVauS8}fTL-uH2$egp0%LW zma2_@tfKi+9WsW;D1h%rOM9v@nKhPX3p3};_*SDzIUhW)`pUtfxbDeKSz6u+51wu4 z*|*m6*iF4t7B|tT6UNuFd{9w<0~{k2h8HDz+CL*UA8&A^G!ua4wbAtU@YGnK_L&x} z@(d!Btq7F|*9^RU738#BXK8rPBJ<YzQ-2Sbxe!!RSmZz-b4)}APYJOa`A>2M@ zzO=!T`@gnr-+!S>=rnT3g*Kjo^VAxnO3gPdiHnynmye)X9fQ#rP0Q>7pV-2y7Rdbr@8S38UBrrUXeA?~t z^#R45J$c^w11C)E>9SXOURU^ahyd-c@%JC1ci~kDUqIulE!1CEd%tN6c&laYgSkx` z=0rTUgVQ1=F(S)ic*wDx1f*1a$Fk0x>8dw1vYsOV0Z6Qj$&4IQw+m5sqG7wGq2cDy zb%!EV2p-39mL+hSqF9OxNvrdQsu`eSa&Nc%Gwjuko$u15Qkbj?PKv-w8WWs3KDTFZ zzEA+_Bq(kDx$Iy+Yt-SwXkm@2Ly9r{zuM6MqV@K6%bXc+4V`^H;`&O)Fj-PqAY!-# zudn)_3)mQZLj!n1ZB*~?wzL?#;E6GIbf{>VRTPFNSb|aDP|;p>;h7QRcO@A1SX#fZ zaY;eH$eE^jiN{F5NEofeI*#{P8voM$?$b>p9t)!wh7(wYlLY}j7FH91Ln-!=rAuea zq=}zKOqNEnEJt9nOk;!uCrj(3e#>yR{FNcN9NOeQ%bHtQX?3a1CA@`@mT{buI2mvx zS-Zvew(?=qry1kpH%7w&%dp49trs#Qre%>uK#&Z_QKBTE(z1MD48{gS_%hlEbJ)_# z^tIfmdt~Ovv66xl6c5OdLG#(hYKX7=-16#)MQv(|rcee|p0c7u;WEJkiNRq5;!mm~ z{B<&ll3!TH{PybMuO}l{swB(cJk4@AfiVO|huA-BMeVFFEj9<=?D=2AWLfvgHiCl* zl4(Ru(Bqb;`llTn@Ub~`Wm@Jyi7@FTinl5=hXX#@VKHf z@VI64i~UUQ4iP7wh;zJ%V>Cyz96a&TOXU(Qr%=>5VR_lM`QVv7jnNa&NwJL0?(Hmk z3JZLLeS!}-fy*~}!zb^SPaQM%bf7ceWdhhv1+cS8cw6WR%c$DNkGod23uR}KPSX?! zo-uY;UiU&*NfH_FMF@_3~668C$ z>J8}Kh|oa#(r9l#w_NA|xj^X(3I-^$_m3kjHl$U7ZH+f(T%12s*=RavxoPSA;?IB4 zRN#Dcc4SGAF`NZ5Es;t_x3tYKZ(ds!PFNXla^x--dB39VYEUoE>y-udB5WZAM~nEy z(#x5%w{0Kvbf+1fqIia;c;26E2cGWR0=d2ngOFq3SIgp~YZ|=15WT~SVGN7&1kO?n zP2(8c#NJ^6Ci;92lsx#|vNPxFhaY)Li%c=9PZ&u^u{MW)CghgHkM0ACbAce=Img)i z%iFo+{3;b2376aPuVV$DyW9s)Dw{4>n(jL2po0!NT$}RfO3Ax;uj}%yay5J%bkO0- z>+d?~dcoD)Zh}6)bkN~HBd6*@_+p{8iW9HW`Ytv9(fQfsfwnpcVxmt)$D_7gTT3V9 zzjFMyzRJI^#(zv-*WuqGKNBvIUUjw4n`=#8C;Z39>9qzm{-xigkE8!49c$=armyRC z(D}!I3_2p{o_>Y&WnGTw^HS#@l?PpQ62t{fu2Q;HG;nO!D>Sc?;;b(r#`@z8h^smE zUoL;FOT~98nsKUQ6nbB7ew=Wb+kx9N{ma%haQel1F|OZ?2) z-tlij@be~d)~DOcbR6%t`~Kv*m_3?9dx+%K=%9lRI_PliKt=6^T5PW0 zExUiNv3SAln*DLRx)2LW^1)FyPz0o0;4O6ca)bh3p$GI6ykl;#lf-8;rcRz?o>Ao% zwE`_q3LF9#6(ZLR{jVQ%y=IgTf$ukp5oboJ2L+ii-q#&3u1;u#m^n%L5}~jT-dk+Z=a@pOS!PS zveQPBw>&fQnOl2(VT5DoT~K!?YepH=@co*I{9ZSZ7k7xp>2l_>weSX>xPLv?*Wo+yj}L?+kgm27RO}@CjlJLINN~wo>VLU z!2I8PSJlSEl<;FhA#qj$l7Nfk2W=)Nz0!YY5}Zi@(?Bf0?^{>pj$?Gd>nhgM-F~{` z`@|?Y)_8&?1xXfIJS4#LW+XkTTHn9W>6bRkwQcQ%p>;bc!sY>9w__X_=Jt#Mo^CFm zr+Bct&?A8#|E|9Ab7#*qZTt`rt|(OW`LYkov|>kYb+r3LBN`W$XgDqtBrP$dNN{k} zd~L{U!NRK|+p1xGb7S*+x75>~n35E6k|>gZ;e;e&499F(N1ScPElQZ9K3eZT%Eiw5%)qHKzCqy7mKs`9 z&8e%J3z~T6jOAO>BKC8%KwuQjOFXaTkbslisYx_TF%0na3y^4qh^ft`UVfq(v#GLS;C_J(O$0P?k2)Y@O5T&u{Lk8Zk)%M#((jWL^@ukR%B>#E?fu z9Zyy(!7pp~#FNMrGK|Q}K%sD4q)9l1j4|%vn`OQCv6cnZ+9R72X~2;b$B8mW!_761 zvDvcbvaLTKnepws`@`hoDbp%sUXcY-l5tXDn@e?$me0A66mwHetev0T`t=R7w3j>; zs=@d}xhr;;+{-0{A{$8oiQ+g`p?Rv>@L|V3d1z?0`szcC$De-=l&yaUKi2>v z*8NR`%i906_wEH9l^EJ1P{C>Ff9uqF@JV9$=PC-VpsB0NO7POecn4KG z>x{Xl#@J_Fk6v+yX8W*vyExp^7$A4CyJWj74_<^ZYrD(t zv(Y$p%h|cz{auGjb{&7qN2blLIeb`FB)x~G0mB21k5vExPJ%3mLF)>q$I^~vim zYDtfmh8>)g&F%vp!RPi26&!_NLDr9b-g@{%VkScKts3VtxiXDw!RkYMYm3QiTxW98 z84n2_CvcXRFotijd+4O{S%ive1uJz4QK{L%dRyko&I{UTEH15H7;55b;*|b{P7!#9 zxCi?@c2{1G;BaiDo^Xr6khCdAI|;09cBmlznpg0-#2DWz+Axe4QZDg$ik6uEa=%w| z!_@^>s^6~^q!@I#n&*cOIv9fFegK-q_eER%6G3exH-o8 z_-_L3^A*Nk6D^nZ~8DlIv|Ar(S)r`g>)|5fnX) zS2vWE)%W(qAPj?c{qJMp-=mXt(#hJ@PT3>+mrxQ( z13=0+2LS9}(l$oHR%Su(V!c0Wm3eZW=7h7QtVw8Z4&!Z|JszRBn*%t3%Qx63_<+~u z6pDx2fkVEZ`;m+$;OR0QDr(*SL>ucJ(><|qFoskN|KUn>>e! z>#aRCXO#wtp?yqnludHGygpB%X8{AeFT!HeRB3(Bfja_2wIr zHXmLc=0H+8C5vPQg27k{!xYV985SLTjVL{Cr1jwFjpO#*qlt`Gq31R2E}y$pr?I&T zoPJHlE)6Lz0NsiT+#cURhv4de>g{jaUbiFjrmJke!5%#O^}rOD1yCL@BduGf9GmoH zea$hr+@VO1&m%}B{@^^$k}NH;G*6Q=Pak=GYpJ(?8Uh>2DRVfFA|iQU#W44v*}98drpsc<|a z^D+-l^An(da`;Wb*E z7Bpq%2b@-;A(v1yJGld~Jo~LLI!#R$}NqC~%Q$1P>4lDIo zmzu=1=Ap~}asz|MNJ`*28Ym)Fa!s~-faDW9zc``16P*U8)L2)PE^E~VwGaMd*IfRK z!mM`*mbdvl#U;+U-HHl4!0WZUU4Iu3dhG9=HL9dXA^O+3v2|OTA=Y;;u8IjB}cK=!|k}HS}VFZ~WjMkQTndhbsmltj>*JtVIVG%M85=yTZTC41sP{invD&iXBHOE|AN~Fqj|3H3XZ^f? zQNNUk(p!;vnvn@Yz!^E#LlK46SL%3%ymEVHsL{{^Y&gdIwHhh^iTbU2`0d%6=*Wrk zUBjdNuZ)3?x7t_zI(SGE%_27iWoE`XTTVWZ#sE)uK@w!(U#@xVF0WmB@9{_K+rFQf zp;dZTW#^+ItX-cGW9PJjIz#)t^@k_yD?YAXyDS8Ik=6I?=F}UWiLAge3Qz=!H?eMQ;N@#3hHoOtFwuHP?vlwr--m31j4oDQX*!!4&qa@yQqZ6&e@Rhy(nHlC&$~8nQ1Vxf8 zpac=_@x-VNY;U=3Y5h-YAsZ+;)Pu7eT=U;m!!wt%Rnipem)D(h47DMZB#LDfoW^)s zq$pTPx=yuod19p06ziG4i@yRtL|6&q9EJlCNUW?#@Je{r?cs5(D`9xO5o_6KxZC>L zpdatQ=S0L4`z+4_ft3jk7vK~74eEu*p;K?Vb#Cnyt-JlBNy{R%w3G!_=6H?-xC9Dw zp1YkH@No*9BPCkMoLEEZ#2b32vO@I~jfwAiWdU42`ZUu$)_dvIO*c-AG&E!Z=OvNB zc^RkSp|K`8JPsWi_gde*XK|DFeUU{Aj!UA#^MK@724)A>BRE@G8#Ap{Ot&m4B1>g( zpU_1NMR9?{QiJo|9$${#BNf_xoxNUrp3A@KoAT68N z;B!|hE#2h;{ovM>1wE~U4wsXU>ht~b^aFK`^pEK(uTP(E`h2<;=hd|`Z*=`bpXd7c z(8r%Xj&#sLhie7kbmiB&{LR+&g#R>LYWgMpOX)`GLq~^7)T1j)&#vL%KhW*%S0~@PR{0?j=XD*fO+8TO8~^R~u?{-?7xW_?bhsAevM!Hx z(B;1l**XdIe%Ile>96en*f{*R?%O9_Fi!q8p>hqVToo#7;kJy1`>Y%Pd}CpYMNQQ!Jyl#1$up2bArQ%n zBW**x>|l4HM*;%{j~94mKKs(w=T_7$%>y(!Ilhl9izN1twZR5#VLyxZTIJ%D%8FC)qKa?2!SIGZ&@`ODbk!B=@3I(+i>=>I zp7Gqq4bi$ssMMF}i8q*4NR^Y4`bn z#|E5sUyj@3?&WgWU0|Tc?X-JAXNMzs>MG$vzq=EjLNu!fasGEeW%c9b$~{^o%KIl? z=J!sFk-o-Cem~=7?q3~Xk@SSM+W7k>J|QuF4??1PGUc~s|EDsnA2LcCV43@(Q$d7*7 zI%&~cc~w8F87jxh$025DIPPe*X9E}=hWHul`LV-2v)+ml;+ViOxbEeNk?VfOn%{r# z+^nA>=gR~nE@CoE^OOkZ%lvFtAdAg+EdpiF?BH@Jou0F{Jvznx@M9Y32O46M#{Mtt z?$49?)Xn*~lusGDp=$uIQy~{mef9l*_0x4Z^X)w79w6Yu3V}_OGhXY8X1O z%jF&*NtqHPNyJ&H@h8)<4;uD0Y9qN;QZSC6@vgJ}b!zDga~f&!u?M2#V=J;k;GBdj z3}8+eo_uTLy1{91mhf7aSYp(Q^L|C&M_U?MF7kch=h2D!-nJ(6?(lZQ$)(v*!*_(& z?F2Sb!3c?`Se_<{4ZSC{+r8-FR4uQ^I!LLjb&>m}>n>5)>8H~w=Q(sF@prAJ{H|?l z^w20;BLYQbS!OW6kc_O5&nDb=@{O^JQ&4@sPE|TaB}cv=Gli35du~`-<@Ug^v{=XH zcI&ytxqsNcCeRCRHMt{2*-G+N0Z;ifzBvxT>&d?Zp-J~A{CazDS{R-VZwn)C;O$(C^ehBkQi^9A6XZ=2OjwONLJ`l zsBA?|%c2A*T*efIE?H66Ink6Xzp{S}!Z2vpTNqI4#vyBxlYRMk6)iDmwlR#lfwMLb zklY@*r{Enh-qjO03V^51iz6ER*|NC$#rn6#+kYttT-ohh?7TQ+-TmqpJ;pw*X?g`^ zJv@56ji8x(EQxPU>2SfQZN$Nu|6+UDV9byLS#L-pE{%)=NNlzCWk zJDv6r6?UmP7>73VnRV2mKC`-g6*+a9q{swI@PObMe@3$m)9-&KYtu;EgR2(Rruc>R zHFo=o9}a5y-e-n2&nY;|D~d=6GNwwK(ye zHozVXJHRkXU__A-aT;)Uw*15X*$3Il88Hfvgi2x}=r!gE>x#i++Yib%hfWeT?U!oB zWBhyU0|j5c7f$`PIx##BCD<8jpQMKUrerXo+YMr=ecb0p+mF)(3h`kU0aNyaO6!XvAa>bW^eIV;BJLg{$UTC4p%FTFip z%R0V3>_io0p}=R8Xr5*Pp~w^=+U(8(M{fNl;7GL}N_|NRpc{Zd+3%#|4~Ba1=)}GDf2~ZbFQ+B*E~Tb>Qv&MuXL?yD8N* znzVZ*unovVjjfInAAm>bd%v!zc~O%fTDxU~`Y-DZhaP_ahpC#%(JCBM;y4K>DV*UL ziPTgMc&Bt==kQG=8WOXrPQUx5rCX3Pl)`9+!6<^KC;}sh5S`%Bp20YziL5{W*l#U9 ztx2DSVHRyPMcX`uuI?VU%LiQY{g1uf@!mxbW>hm&OijI5K#9`Ctn;mZtm#`7QAXer z!HFUufJ9(nWyC>aWE?sSGO{M$vwQ2ZXONSelVuTSWR8_2xyA0GlYU%Lw{()uT%;prvfSh8<0XoZ0yVq-XyKIt((d5iSS?Plk6JuQ6lr`Hht0tZH z^HiH=0Us64pg`j`$?b3e$>Ȑt9k6i}dF2La)|6;2iU-|VDt;+U@FU^I@MnkNW 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

0n8;PO+|GJL< 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%0DsH7X?j`A@W!=`W+JG4VWYUC`O4pK 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%0A3fH>pQsO`t<97)sV;h2r8 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

S7zDpT)IviIZ-pYd?7tTuPrKUWEbWyYr>u!Tt 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�k=enncIpVse{ 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�*Er089Uq%U)VgzeO;q@MU4O56u0EQv@f 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 z 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�QO7wMev~+5%^H*C8Aiz%MXUy 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�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