mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-31 07:23:06 +08:00
Keep the charAt unit reads' origins on the emitter
The charCodeAt reads that stand for rewritten charAt reads (one-unit tests and switches) recorded the charAt each stands for in a module-level WeakMap. Compiler sources keep such caches on their owners: the map now belongs to the emitter (charAtUnitReads), and charAtUnitRead takes it.
This commit is contained in:
@@ -1826,7 +1826,7 @@ export function emitTryCatch(emitter: LlEmitter, s: IrStmt & { kind: "tryCatch"
|
||||
* case, refcounted/boxed case-body locals are NULL-reset up front and
|
||||
* the scope-exit releases rely on NULL tolerance. */
|
||||
export function emitSwitch(emitter: LlEmitter, s: IrStmt & { kind: "switch" }): void {
|
||||
const unitSwitch = charAtUnitSwitch(s);
|
||||
const unitSwitch = charAtUnitSwitch(emitter, s);
|
||||
if (unitSwitch !== null) return emitSwitch(emitter, unitSwitch);
|
||||
const B = emitter.B;
|
||||
const discKind = s.disc.type.kind;
|
||||
@@ -2518,7 +2518,10 @@ function nullableStringSwitch(
|
||||
* one-unit string literals, as a switch on `s.charCodeAt(i)` with the units
|
||||
* as cases: no character string is built. An index out of range answers
|
||||
* NaN, which matches no case, as "" matches no one-unit literal. */
|
||||
function charAtUnitSwitch(s: IrStmt & { kind: "switch" }): (IrStmt & { kind: "switch" }) | null {
|
||||
function charAtUnitSwitch(
|
||||
emitter: LlEmitter,
|
||||
s: IrStmt & { kind: "switch" },
|
||||
): (IrStmt & { kind: "switch" }) | null {
|
||||
const disc = s.disc;
|
||||
if (disc.kind !== "strIntrinsic" || disc.method !== "charAt" || disc.args.length !== 1)
|
||||
return null;
|
||||
@@ -2531,7 +2534,7 @@ function charAtUnitSwitch(s: IrStmt & { kind: "switch" }): (IrStmt & { kind: "sw
|
||||
return null;
|
||||
return {
|
||||
...s,
|
||||
disc: charAtUnitRead(disc),
|
||||
disc: charAtUnitRead(emitter, disc),
|
||||
cases: s.cases.map((c) =>
|
||||
c.test?.kind === "strLit"
|
||||
? {
|
||||
|
||||
@@ -1201,6 +1201,10 @@ export class LlEmitter {
|
||||
* (findIntegerOrNaNLocals in wrapping-sums.ts). */
|
||||
integerOrNaNLocals: ReadonlyMap<string, IntegerRange> = new Map();
|
||||
bytesBounds: ReadonlySet<IrExpr | IrStmt> = new Set();
|
||||
/** The charCodeAt reads standing for charAt reads the emitter rewrote
|
||||
* (one-unit tests and switches, charAtUnitRead), with the charAt each
|
||||
* stands for: a loop version's proof for the charAt covers its read. */
|
||||
readonly charAtUnitReads = new Map<IrExpr, IrExpr>();
|
||||
/** Worker programs: typed-array accesses whose views an enclosing version
|
||||
* guard proved thread-owned. */
|
||||
bytesOwned: ReadonlySet<IrExpr | IrStmt> = new Set();
|
||||
|
||||
@@ -286,14 +286,11 @@ export function emitArrayCopyLoop(
|
||||
host.B.line(`call double @scr_arr_push_spread(ptr ${dst}, ptr ${src})`);
|
||||
}
|
||||
|
||||
/** The `charCodeAt` reads that stand for `charAt` reads the emitter
|
||||
* rewrote, such as one-unit tests and switches: a loop version's proof
|
||||
* for the charAt covers its read. */
|
||||
const unitReadOrigins = new WeakMap<IrExpr, IrExpr>();
|
||||
|
||||
/** `s.charCodeAt(i)` in place of `s.charAt(i)`, the same index read as a
|
||||
* code unit. */
|
||||
* code unit. The emitter records the charAt it stands for
|
||||
* (charAtUnitReads), so a loop version's proof for the charAt covers it. */
|
||||
export function charAtUnitRead(
|
||||
host: LlvmEmitterContext,
|
||||
charAt: IrExpr & { kind: "strIntrinsic" },
|
||||
): IrExpr & { kind: "strIntrinsic" } {
|
||||
const read: IrExpr & { kind: "strIntrinsic" } = {
|
||||
@@ -304,7 +301,7 @@ export function charAtUnitRead(
|
||||
type: F64,
|
||||
loc: charAt.loc,
|
||||
};
|
||||
unitReadOrigins.set(read, charAt);
|
||||
host.charAtUnitReads.set(read, charAt);
|
||||
return read;
|
||||
}
|
||||
|
||||
@@ -312,7 +309,7 @@ export function charAtUnitRead(
|
||||
* below the length (bytes-loop-versions.ts). */
|
||||
function provenStringRead(host: LlvmEmitterContext, e: IrExpr): boolean {
|
||||
if (host.bytesBounds.has(e)) return true;
|
||||
const origin = unitReadOrigins.get(e);
|
||||
const origin = host.charAtUnitReads.get(e);
|
||||
return origin !== undefined && host.bytesBounds.has(origin);
|
||||
}
|
||||
|
||||
|
||||
@@ -648,7 +648,7 @@ export function emitStringExpr(
|
||||
// equals no unit, as "" equals no one-unit literal.
|
||||
const unit = charAtUnitTest(e);
|
||||
if (unit !== null) {
|
||||
const code = host.emitExpr(charAtUnitRead(unit.charAt));
|
||||
const code = host.emitExpr(charAtUnitRead(host, unit.charAt));
|
||||
const t = B.tmp();
|
||||
B.line(
|
||||
`${t} = fcmp ${e.negated ? "une" : "oeq"} double ${code.name}, ${f64Lit(unit.code)}`,
|
||||
@@ -682,7 +682,7 @@ export function emitStringExpr(
|
||||
// the code unit, as the equality above does.
|
||||
const unit = charAtUnitTest(e);
|
||||
if (unit !== null) {
|
||||
const code = host.emitExpr(charAtUnitRead(unit.charAt));
|
||||
const code = host.emitExpr(charAtUnitRead(host, unit.charAt));
|
||||
const t = B.tmp();
|
||||
B.line(
|
||||
`${t} = fcmp ${charAtUnitPredicate(e.op, unit.left)} double ${code.name}, ${f64Lit(unit.code)}`,
|
||||
|
||||
Reference in New Issue
Block a user