Commit Graph
3779 Commits
Author SHA1 Message Date
Chris Tate be48947dbd Read a class branch's own-property bag from its receiver (#1727) 2026-10-21 20:03:14 -05:00
Chris Tate 706eebe9c6 Keep constructor types of fetched provenance sources unmapped (#1728) 2026-10-21 19:55:27 -05:00
Chris Tate ed5f54c936 Keep constructor types of fetched provenance sources unmapped
Constructor types declared in the program hold class values as
checked-dynamic values since #1725. A fetched provenance source counts as
a program file, so the unused `@__PURE__` const typed `{ new (): any }` in
the provenance fixture now had a mapping, no longer elided, and its
initializer refused (SC1090). Fetched sources keep their constructor types
unmapped, as before #1725.
2026-10-21 19:51:21 -05:00
Chris Tate f4ab3572c1 Accept file URL paths in synchronous fs functions (#1656) 2026-10-21 19:36:18 -05:00
Chris Tate 4ab3850579 Keep named properties written to arrays through checked views (#1715) 2026-10-21 19:34:43 -05:00
Chris Tate 029906d861 Merge main 2026-10-21 19:34:10 -05:00
Chris Tate 62ddc2fd35 Read a class branch's own-property bag from its receiver 2026-10-21 19:31:56 -05:00
Chris Tate 5bcd68f1ae Address the third review round on array named properties 2026-10-21 19:31:44 -05:00
Chris Tate f8f315cc03 Warn about likely-hot functions that use untyped values (#1724) 2026-10-21 19:29:04 -05:00
Chris Tate c29ce641b2 Count only the repeated parts of loops as likely-hot work
A `for` loop's initializer and a `for...of` loop's iterable run once, but
SC6101 counted any dynamic operation inside a loop statement's span, so
untyped setup there produced the warning and failed --fail-on=dynamic.
Loop work is now found by walking the IR: a loop's condition, update and
body repeat, its initializer and iterable do not. Locations could not
tell them apart, because lowering gives the index loop of a `for...of`
the whole statement's span.
2026-10-21 19:26:00 -05:00
Chris Tate dc1ff7b00d Compile TypeScript's UMD module wrapper as the module body (#1726) 2026-10-21 19:25:37 -05:00
Chris Tate 3447e9a1c1 Unwrap a UMD wrapper only when its body is exactly TypeScript's emit
The wrapper is dropped when its factory body moves to the top level, so
any other statement in the wrapper, in its CommonJS branch or in its AMD
branch would be lost. The check now matches the whole wrapper body and
keeps the original text for any other shape.
2026-10-21 19:20:54 -05:00
Chris Tate 220199dfec Evaluate an fs argument inside satisfies once after a URL path
The arguments after a URL path that are evaluated ahead of the
conversion were keyed by the expression without its parentheses. When
the fs lowering read through a satisfies wrapper, it lowered the inner
expression again, so fs.chmodSync(url, mode() satisfies number) called
mode() twice. The saved arguments are now keyed and looked up without
their type-only wrappers (satisfies, as, type assertions, !), so each
runs once.
2026-10-21 19:17:07 -05:00
Chris Tate be23f71266 Compile TypeScript's UMD module wrapper as the module body 2026-10-21 19:02:52 -05:00
Chris Tate 7b809ee8c9 Hold class values in structural constructor types declared in the program (#1725) 2026-10-21 19:01:51 -05:00
Chris Tateandblurname 5a3fbcc1ef Hold class values in structural constructor types declared in the program
A constructor type whose instances are not one program class's, such as
`new () => unknown`, a type that also names static members (`{ readonly
schema: unknown; new (): unknown }`), an abstract constructor type over a
record, or construct overloads, did not map and refused with SC2001. Such
a type declared in the program now lowers as a checked-dynamic value, as
an `unknown` slot already holds a class value: the value keeps its class
identity, `new` through it constructs that class, static reads see that
class's statics, and the constructed value checks into the signature's
instance type. Library and package constructor types keep their fences.

Refs #1372

Co-authored-by: blurname <50226652+blurname@users.noreply.github.com>
2026-10-21 18:57:17 -05:00
Chris Tate fa7bc7c7a0 Warn about likely-hot functions that use untyped values
A build now names the functions of the program's own files that compile
to the dynamic tier and likely run often, so a slow program with a little
untyped code says where the time goes:

  warning SC6101: 3 functions that likely run often use untyped values, which runs slower than typed code:
    advance (nbody.js:22): untyped JavaScript file, in a loop
    ...

- The functions come from the tier assignment lowering already makes
  (Lowerer.dynamicFunctions). Without a profile, a function counts as
  likely hot when a dynamic operation runs inside one of its loops, when
  a loop calls it, or when it calls itself (lowering/dynamic-tier.ts).
- A function is named only when its source says why its values are
  untyped: an `any` (for a for...of variable, the value it iterates), an
  untyped JSON.parse result, or an untyped JavaScript file. Generated
  %dyn.* helpers, module top levels and functions that are dynamic for an
  operation without a static lowering are left out.
- At most five functions are named, most likely hot first, with the
  total; dynamic-tier code in npm packages is counted per package on one
  line. All of the warning's text is in diagnostics/dynamic-tier.ts.
- SC6101 opens the SC61xx band, performance notes, with a new
  "performance" category in the diagnostics envelope; SC60xx stay the
  divergences.
- scriptc build prints it after the divergence warnings, and the
  executable cache stores it with the entry, so a cached build (including
  the CLI's routed fast path) repeats it. scriptc coverage reports it, and
  a comment-only edit no longer replays a verdict that carries it, since
  its text holds line numbers.
- --no-dynamic-tier-warning leaves it out of build and coverage;
  coverage --fail-on=dynamic fails on it.
- Docs: coverage.mdx (Dynamic tier, Gating builds and CI, the envelope
  categories) and cli.mdx.
2026-10-21 18:53:43 -05:00
Chris Tate 34f371f829 Address the second review round on array named properties 2026-10-21 18:43:03 -05:00
Chris Tate eca0cab8a2 Give the sanitized Effect pilot tests a longer timeout (#1723) 2026-10-21 18:33:42 -05:00
Chris Tate 2054ea51bb Give the sanitized Effect pilot tests a longer timeout 2026-10-21 18:31:16 -05:00
Chris Tate 4fee347ca0 Address review feedback on array named properties 2026-10-21 17:57:00 -05:00
Chris Tate 21a2bb3de8 Replace every match of a block in one-character replace chains (#1722) 2026-10-21 17:40:52 -05:00
Chris Tate dfdc610c59 Replace every match of a block in one-character replace chains
Chains of global one-character replacements (the HTML-escape idiom) run
as one scr_str_replace_chars call. It searched for the next match eight
bytes at a time and started the search over after each replacement.

It now reads 16-byte blocks with SSE2 or NEON (8-byte words elsewhere on
little-endian hosts) and replaces every match of a block before reading
the next one. The table of characters and replacements is kept for the
next call with the same immortal operands, which are the literals the
compiler passes, instead of being rebuilt from the replacement text on
every call.
2026-10-21 17:36:58 -05:00
Chris Tate 1d5a0c745a Speed up JSON.parse and JSON.stringify scanning (#1721) 2026-10-21 17:34:58 -05:00
Chris Tate 79a7120e5f Speed up JSON.parse and JSON.stringify scanning
- The number and whitespace scanners keep the cursor in locals and write
  p->pos once: the runtime builds without strict aliasing, so a loop on
  p->pos stored it after every byte.
- Typed arrays gather parsed elements in a 32-slot run and append them
  with scr_arr_push_many instead of one push per element.
- The string scan shared by parse and stringify takes the index of the
  first quote, backslash or control byte from the marked word on
  little-endian hosts, and checks the last 1-7 bytes of a string as one
  word, so a short plain string needs no byte loop.
- Typed record parsing computes once per record schema and parse which
  field names hold no byte JSON would escape, instead of testing the
  name on every direct key match.
- The mantissa converts to double through int64, and the positioned
  error report stays out of line.
2026-10-21 17:31:02 -05:00
Chris Tate 4cf87366aa Refuse elements on Array.prototype (#1720) 2026-10-21 17:29:26 -05:00
Chris Tate 0950725949 Refuse elements on Array.prototype 2026-10-21 17:24:17 -05:00
Chris Tate 3d1c422b1c Lower a Buffer view of a dynamic typed-array value (#1719) 2026-10-21 17:23:58 -05:00
Chris Tate 8061060aff Lower a Buffer view of a dynamic typed-array value 2026-10-21 17:20:50 -05:00
Chris Tate 75436e9c86 Walk a file once for the references of its function declarations (#1717) 2026-10-21 17:20:00 -05:00
Chris Tate b22332e4c9 Fix the compiler crash on recursive type aliases in generic signatures (#1718) 2026-10-21 17:19:41 -05:00
Chris Tate a7a42640dc Stop the type-parameter walk at recursive aliases in signatures
mentionsTypeParameter walked union constituents and type arguments
without remembering the types on its path. A parameter typed with an
alias that reaches itself through its own type arguments, such as
`type Tree = string | Tree[]` in `function f<T>(x: T, ...trees:
Tree[])`, recursed until the compiler ran out of stack. The walk now
skips a type it has already entered; a type parameter reached through
any other path is still found.
2026-10-21 17:17:15 -05:00
Chris Tate 70aed0f133 Walk a file once for the references of its function declarations 2026-10-21 17:17:02 -05:00
Chris Tate 8428bed383 Call an observed prototype method through a bag that does not hold it (#1712) 2026-10-21 17:04:57 -05:00
Chris Tate d0a581f837 Keep class methods on structural views asserted from unknown (#1713) 2026-10-21 17:03:38 -05:00
Chris Tate 238b08352b Keep named properties written to arrays through checked views 2026-10-21 17:00:19 -05:00
Chris Tate d6f857bb1d Keep class methods on structural views asserted from unknown 2026-10-21 16:59:02 -05:00
Chris Tate fa7aa25078 Call an observed prototype method through a bag that does not hold it
A dynamic method call on a class instance whose method name the program
also reads through a prototype (`X.prototype.map` anywhere) uses the
observed prototype slot: the callback descriptor read the method from the
instance's property bag, on the assumption that the bag answers every
read through the class prototype. An instance whose bag was built before
the class had prototype data reads as a fresh empty object, so the read
answered undefined and the call threw "... is not a function" (fast-check's
`integer({ min, max }).map(...)` once its result reaches the call through a
dynamic value).

The descriptor now reads the bag when the bag holds the name, own or
through its prototype, and otherwise the class's prototype data.
2026-10-21 16:58:37 -05:00
Chris Tate 5954d475b7 Record TypeScript 7 baselines for the string field corpus program (#1711) 2026-10-21 16:49:19 -05:00
Chris Tate 228c64a282 Record TypeScript 7 baselines for the string field corpus program
The TypeScript 7 parity lane checks every corpus program against a
recorded preflight and order baseline. 6950-string-field-fast-paths.ts
arrived without one; this records it from the current native lane.
2026-10-21 16:46:53 -05:00
Chris Tate 4124e2a501 Convert global isFinite's argument with ToNumber (#1662) 2026-10-21 16:37:03 -05:00
Chris Tate bbb37ae03b Read a spread's elements before an earlier argument converts
When the Math functions evaluate their arguments into temporaries before
converting (an earlier argument whose ToNumber can run valueOf), a spread
argument's array is now copied where it is evaluated. Before, the
temporary held the array itself and its elements were read after the
conversions, so a valueOf that changed the array changed the values
passed, while JavaScript reads a spread's elements during argument
evaluation.
2026-10-21 16:34:37 -05:00
Chris Tate baa9af6be1 Speed up split, indexOf, slice and Number() on ASCII fields (#1710) 2026-10-21 16:16:14 -05:00
Chris Tate ea4d570e59 Speed up split, indexOf, slice and Number() on ASCII fields
Number() of a string with an optional sign and 1 to 15 digits returns
the integer directly; every other string keeps the full StringToNumber
grammar, out of line.

split() with a separator collects its first batch of pieces before
creating the result, so the result is an inline array of exactly that
size, filled in place. A split's default limit skips the uint32
conversion, and pieces of a proven-ASCII string are created ASCII,
including the scratch pieces of split loops.

indexOf() from the start of a proven-ASCII string searches bytes
directly, and slice() of one skips the UTF-16 index map. The one-byte
case of the byte search reaches memchr without a stack frame.
2026-10-21 16:12:52 -05:00
Chris Tate 2ca85a3d4c Give the fs corpus programs per-process scratch directories (#1709) 2026-10-21 15:56:38 -05:00
Chris Tate f6f00d8b05 Collect the compiler's heap as lowering and LLVM emission grow it (#1708) 2026-10-21 15:54:44 -05:00
Chris Tate 47671d5bed Give the fs corpus programs per-process scratch directories
5568-fs-cp-errors built its fixture in a /tmp directory named after the
program file, which it deletes and recreates. The Node oracle and the
native runs of one program run at the same time, so two runs with the
same name deleted each other's files and the program exited 1 on
random shards. Its root, and that of the five other corpus programs
that name a /tmp/scr-* directory after the program file alone, now
ends in the process id, as 5571-fs-cp-deep's does.
2026-10-21 15:54:23 -05:00
Chris Tate 692569a804 Collect the compiler's heap as lowering and LLVM emission grow it 2026-10-21 15:50:32 -05:00
Chris Tate 621b7cfe58 Build the native compiler with profile-guided optimization (#1707) 2026-10-21 15:36:42 -05:00
Chris Tate 2b48451cf4 Build the native compiler with profile-guided optimization 2026-10-21 15:33:37 -05:00