Commit Graph
4679 Commits
Author SHA1 Message Date
Chris Tate 09a73ab6ed Fix Array.prototype calls on native arrays, typeof on ambient names, and net connections to Unix sockets (#2326) 2026-10-26 10:56:58 -05:00
Chris Tate 6e4fdf95d0 Link the exported bootstrap package's helper and runtime pack dependencies
The native bootstrap's package checks copy the seed's distribution into a
package directory outside the workspace and, since the CLI packages depend
on their LLVM helper and runtime pack, drop the bundled copies. Nothing in
that directory resolved @scriptc/llvm-linux-x64-gnu, so
verify-native-cli.mjs failed with 'Cannot find module'. The test now links
both packages into the directory's node_modules, as pnpm links a workspace
package's dependencies.
2026-10-26 10:56:27 -05:00
Chris Tate d5dc896576 Merge main 2026-10-26 10:53:46 -05:00
Chris Tate 9b96314c20 Tear down self-recursive records and classes in one loop
The teardown of a type with children of its own type called itself for
each child: a call, its register saves and the segment bookkeeping per
node, 45 instructions per node in a binary tree.

A record or standalone class whose every reference field holds its own
type and that has no collector header now tears down in one loop. A child
whose last reference the dead node held goes onto a pending list linked
through its own count word, which it no longer needs, and the loop takes
the list's first node next, so nodes are visited parent first. Each node
frees its block as before (dispose observers, the RC audit, blocks of
other arenas), the calling thread's blocks go into the teardown segment
in visit order, and the segment goes onto the free list in one step, so a
structure built parent first takes the blocks in its allocation order.
Shared and immortal children keep their release. The loop needs no depth
budget. Other teardowns keep the recursive form.
2026-10-26 10:42:41 -05:00
Chris Tate 4c5c0823ce Address review feedback 2026-10-26 10:20:11 -05:00
Chris Tate 928c30e908 Bind thisArg in the array callback methods of dynamic arrays
forEach, map, filter, some, every, find, findIndex, findLast,
findLastIndex and flatMap on a dynamic array, and through
Array.prototype.<method>.call on a native array, called the callback
without its thisArg, so `this` in the callback was not the second
argument. These methods now bind `this` to the thisArg, or undefined
when there is none, once per call, around all of the method's callbacks.
2026-10-26 10:19:57 -05:00
Chris Tate 0b12340ead Merge the libnode loader and mark e04 as a race 2026-10-26 10:18:44 -05:00
Chris Tate b926722ad3 Evaluate writes and indices through missing asserted elements in Node's order
`xs[i]!.name = v` threw while it evaluated the receiver, so a missing
element skipped the value's side effects and hid an error the value threw.
Node evaluates the array, the index, the key and the value, then the write
throws "Cannot set properties of undefined". Such a write, in statement or
value position, now evaluates them in that order and then tests the
element: a missing one throws Node's TypeError, a present one takes the
write. The array and the index are held only when the key or the value
can assign a binding or field, and a key or value whose evaluation is
unobservable stays in the write. A key of any number or string value is
named in the message, since the write holds it.

An index that replaces the array binding or field (`xs[(xs = other, 0)]!`)
ran before the member access and the string conversion read the array, so
they read the replacement. The array is now held before such an index, as
JavaScript reads it first; an index that cannot assign keeps the plain
read.

Corpus 7395 covers both orders.
2026-10-26 10:16:54 -05:00
Chris Tate 5a14c0a3dc Merge main 2026-10-26 08:37:13 -05:00
Chris Tate acb2d23df5 Attribute slot causes to the owner only for types without their own slot 2026-10-26 07:59:53 -05:00
Chris Tate 7e6327740b Merge perf/static-objects 2026-10-26 07:53:16 -05:00
Chris Tate 52a228d0f5 Keep declarations a removed branch shares with another 2026-10-26 07:50:59 -05:00
Chris Tate d1a0bea84e Have the native CLI packages depend on their LLVM helper and runtime pack
Each @scriptc/cli-<platform> package bundled its platform's LLVM helper
and runtime pack, which are also published as @scriptc/llvm-<platform> and
@scriptc/runtime-<platform>. The CLI packages now depend on those packages
at the same version (workspace:*, which pnpm pack writes as the exact
version) and leave them out: cli-linux-x64-gnu goes from 115 MB to 60 MB
packed.

- build-native-cli.mts --platform-packages, which each CLI package's
  build:native passes, writes a manifest without llvm_package, runtime_pack
  and runtime_packs.
- loadNativeToolchain resolves a missing helper or host runtime pack as
  Node resolves the package from the compiler's directory: nested in the
  platform package, beside it (hoisted, or pnpm's virtual store) or higher
  up. It requires the compiler's version, and an absent or mismatched
  package fails with an error that names it.
- installNativeCli records where the package manager put both packages in
  the installed manifest, with the same checks.
- verify-native-cli.mjs requires the exact dependencies of a platform
  package and checks the resolved packages' versions.
- package-native-cli.mjs bundles the helper and runtime pack into the
  standalone archives, which stay self-contained.
- smoke-native-install.mjs installs the helper and runtime pack tarballs
  with the platform package; the bootstrap's exported package drops its
  bundled copies first.
- release.yml publishes the CLI packages only once every helper and
  runtime pack package resolves on npm, and scriptc only once the CLI
  packages resolve, each wait at most 25 minutes. A rerun skips the
  uploads npm already accepted and waits again.
2026-10-26 07:48:11 -05:00
Malte Ubl 572e7e3eac Merge remote-tracking branch 'origin/lf/l4-expressions' into lf/l5-polish
# Conflicts:
#	packages/compiler/src/frontend/lowering/lowerer.ts
2026-10-26 05:37:00 -07:00
Malte UblandClaude Opus 5.5 ec9624997a Attribute the dynamic pieces of pushed-down types in SC6101 and the slot operation counts
A pushed-down slot's dynamic operations act on its failing components,
whose checker types are not degraded themselves. The lenient mapping
records those components with the declared type they belong to; SC6101
names them ('hook' is a dynamic piece of 'Plugin[]'), and the operation
counts go to the owning slot. Causes read a binding's declared type, not
its narrowed flow type. The coverage test uses its own fixture, so it does
not depend on which interface members main can map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:35:58 -07:00
Malte Ubl 3bfe3f7c85 Merge base branch 2026-10-26 05:35:29 -07:00
Malte Ubl 44729131df Merge base branch 2026-10-26 05:35:27 -07:00
Malte Ubl 55b20ab200 Merge base branch 2026-10-26 05:35:23 -07:00
Malte Ubl 80b5fdeb54 Merge base branch 2026-10-26 05:35:21 -07:00
Malte Ubl ffff3bfc19 Merge base branch
# Conflicts:
#	tests/harness/node-island.test.ts
2026-10-26 05:35:15 -07:00
Malte Ubl bcef522b73 Merge base branch 2026-10-26 05:34:58 -07:00
Malte Ubl f2fe256f45 Merge base branch 2026-10-26 05:34:57 -07:00
Malte Ubl 99753193aa Merge base branch 2026-10-26 05:34:56 -07:00
Malte Ubl 797650db73 Merge base branch 2026-10-26 05:34:56 -07:00
Malte UblandClaude Opus 5.5 91b437c090 Keep path-mapped island declarations out of the module graph
A re-export from an island package that tsconfig `paths` maps to its
installed directory pushed the package's declaration file into the module
order, so the lowering compiled the declarations' own imports (SC2013 in
the package's .d.mts). Such a re-export now adds no module edge; the
lowering reports the island boundary as for any island re-export.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:34:47 -07:00
Malte UblandClaude Opus 5.5 637d78bb67 Load island packages that tsconfig paths map to their directory
A monorepo can pin one copy of a package with a tsconfig `paths` entry
that names its installed directory. Its import then resolves as a project
import to the package's declarations, so when the package runs in a Node
island, preflight refused it as types-only (SC1010) and the lowering
skipped it as a project module, leaving its bindings unlowered (SC2013).
Both now treat it as the island import it is: typed by its declarations,
loaded in Node.

Corpus 6839 imports an ESM island package through such a mapping and uses
its interfaces and generic aliases from typed code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:34:47 -07:00
Chris Tate fe244085d4 Run native async generators as stackless coroutines
An async generator whose body suspends only at its own awaits and yields
now compiles to an LLVM switched coroutine, as async functions of that
kind already do, instead of running on a fiber with its own stack. Its
steps run on the stack that resumes it (the loop's after an await), its
awaits suspend through scr_coro_await_prepare and scr_coro_hop_prepare,
and its yields store OUT through scr_coro_yield_* before suspending.

- scr_async_gen_new_stackless creates the generator. The stackless hop
  settles an async generator's state as the fiber hop does, and a step
  that would start below the stack guard throws a RangeError, which
  rejects its request.
- Calling an async generator's next, return or throw no longer counts as
  parking the caller: they queue a request and run the body to its next
  suspension, which returns to the caller. Bodies that consume async
  generators can now be stackless too.
- An untyped await (async.awaitDyn) has a native coroutine form,
  extracted by scr_coro_await_dyn_value, so async bodies that await
  untyped values can be stackless.
- An async generator's return through a finally region takes its await
  turn through the coroutine when the body is one.

Debug builds, libraries, worker programs and Windows executables keep
fibers, as for stackless async functions.
2026-10-26 07:28:50 -05:00
Chris Tate a59df23c71 Merge main 2026-10-26 07:21:12 -05:00
Chris Tate e9977107fe Use a kept layout only for the binding the current lowering resolves
A const that kept its initializer's layout records the initializer's
checker type by declaration symbol. A function body lowers once per
instance, and only an instance for a wider argument keeps the layout, so
the record from that instance made the function's own lowering bind the
wider layout for `grow(alias)`: the argument converted into a copy and the
callee's writes did not reach the caller. The recorded type now applies
only while it maps to the layout of the binding the current lowering
resolves.
2026-10-26 07:18:25 -05:00
Chris Tate 28b61086c3 Merge main 2026-10-26 07:16:46 -05:00
Chris Tate b221a13369 Reuse the completion callback a stream passes to its option callbacks (#2323) 2026-10-26 07:00:49 -05:00
Chris Tate 75e48ddec3 Merge lf/l3-push-down 2026-10-26 06:55:57 -05:00
Chris Tate de17158254 Merge main 2026-10-26 06:51:26 -05:00
Chris Tate 5ff9ffde03 Merge main 2026-10-26 06:47:53 -05:00
Chris Tate 5ad9c266dc Read missing elements through non-null asserted operands as Node does 2026-10-26 06:40:02 -05:00
Chris Tate eeef447216 Merge ni/1-libnode-loader 2026-10-26 06:36:38 -05:00
Chris Tate 6589911a3b Address review and CI: aliases that kept a layout, recursive layouts, divergence scan
- A const that kept its initializer's layout (`const view: Counted[] = entries`)
  is typed by its annotation, so a call that passed it compared the annotated
  layout with the parameter's and copied it. The const now records its
  initializer's type, and a call that passes it binds that type, at function
  and module scope.
- Comparing two recursive layouts (`{ kids: Tree[]; note? }` against
  `{ kids: Plain[] }`) recursed without end and stopped compilation with
  "Maximum call stack size exceeded". A pair already being compared now holds
  for the fields that reach it again.
- The divergence scan reported SC6001 for calls and consts whose layout the
  lowering kept, which the coverage test refuses for corpus programs. The
  lowering records those arguments and initializers, and the scan skips them.
2026-10-26 06:28:48 -05:00
Chris Tate 92e42f7c6f Merge lf/l2-declarations and main, and fix self-hosting 2026-10-26 06:24:09 -05:00
Chris Tate 067f146e87 Read builtin globals through the global object, and support Node's navigator (#2242) 2026-10-26 06:16:08 -05:00
Chris Tate 7ae99f63bc Give stream option callbacks Node's callback identities
Node passes a stream's one onwrite function to every _write and _writev
call, and a new function to every _transform call. A write or writev
option callback now receives the same closure on every call
(scr_stream_write_closure), kept or not, so a Set, WeakSet or WeakMap
finds it again. A reused transform, flush, final, construct or destroy
callback is first forgotten by weak collections, as at its free, so a
WeakSet or WeakMap that recorded the previous call's callback does not
find it on the next call.
2026-10-26 05:52:57 -05:00
Chris Tate a684543b58 Merge perf/shape-overlay-core 2026-10-26 05:42:45 -05:00
Chris Tate b8aaa5985a Merge main 2026-10-26 05:23:00 -05:00
Chris Tate fade126bb5 Merge ni/i10-js-island-requires and fix live-handle tracing 2026-10-26 05:18:31 -05:00
Chris Tate c32adf6f85 Keep the layout of arrays and records passed to wider parameter types
An array or record converts by copying it when its layout differs from the
type it flows into (`{ id; name; owned?: true }[]` into a `{ id; name }[]`
parameter). JavaScript passes the same object, so a callee's `push`, index
stores and element-field writes reached the caller's array in Node but a
copy in the compiled program, and `===` against the original was false.

When an argument names an existing array or record whose layout has every
field of the parameter's type plus optional fields, a direct call of a
declared function now targets an instance of the function lowered with that
parameter bound to the argument's own type. The body reads and writes the
caller's value; a value it stores converts into the argument's layout by
completing the optional fields as absent. Instances are keyed by the
parameter layouts. An instance whose body does not lower is discarded with
everything it recorded, and the call converts as declared.

With the same rule, a non-exported function whose every return names such
a value returns its layout (including the parameter's element or field),
and a const keeps its initializer's layout when the initializer names an
existing value or is a call.
2026-10-26 05:07:05 -05:00
Chris Tate c3b265f68c Merge main 2026-10-26 04:39:20 -05:00
Chris Tate 4553941d84 Merge main 2026-10-26 04:25:15 -05:00
Chris Tate ddf5b1f8e0 Keep the integers of typed-array reads in locals for indices and loop guards
A local that only holds exact integers or NaN, such as one assigned from
an integer typed-array read, now keeps whether it is NaN beside its
integer view. Its reads, and sums, differences and products of them,
carry an i64 that holds the integer whenever the number is not NaN, so
an index check or a counted loop's guard tests that integer and the
ordered bit instead of converting the double back and checking that it
is an exact integer.
2026-10-26 04:08:25 -05:00
Chris Tate 3ed13f4c4b Fix CI on the island stack 2026-10-26 03:59:57 -05:00
Chris Tate c66ce24a73 Fix Array.prototype calls on native arrays, typeof on ambient names, and net connections to Unix sockets
Fixes #2116
Co-authored-by: 4ndual <44326858+4ndual@users.noreply.github.com>
Fixes #2134
Co-authored-by: dolphin278 <1130473+dolphin278@users.noreply.github.com>
Fixes #2142
2026-10-26 03:57:37 -05:00
Chris Tate 2ad699c98a Compile classes that extend Array (#2059) 2026-10-26 03:57:16 -05:00