Commit Graph
4679 Commits
Author SHA1 Message Date
Chris Tate f03b798ea5 Convert typed arrays to BigInt through their element text (#1934) 2026-10-22 23:31:39 -05:00
Malte UblandClaude Opus 5.5 37ea2c9ce7 Keep arrays stored through a typed global view native
A fresh array literal written to a checked-dynamic slot is built as a
dynamic array. On a member of a typed view of the global object
(`(globalThis as typeof globalThis & { cache?: number[] }).cache ??= []`)
the program reads it back through that declaration, and each typed read
extracted a new native copy. `cache().push(x)` was lost, and two reads
were never the same array. Node keeps one array.

When the literal is the right side of a write (`=`, `??=`, `||=`) to a
member of the global object, and the member is declared as a native
array, build the native array and store it boxed. Every typed read then
extracts that same array, and untyped reads see it through its live
capsule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:31:28 -07:00
Chris Tate d027786c80 Convert Buffers and DataViews to BigInt through their own text
BigInt of byte storage joined the elements with "," for every kind, so a
Buffer, whose text is its UTF-8 decoding, and a DataView, whose text is
"[object DataView]", converted as typed arrays. BigInt now parses the
value's ToString, which the runtime value decides, as String does. This also
covers a Buffer held in a Uint8Array slot.

Corpus 7403 adds Buffers, a DataView, and a Buffer in a typed array slot.

Refs #1647
2026-10-22 23:29:34 -05:00
Chris Tate 5159d2e966 Keep replaceable method results that have no dynamic form native (#1947) 2026-10-22 23:28:45 -05:00
Chris Tate 5e624865b5 Merge main 2026-10-22 23:27:30 -05:00
Chris Tate ebefb8d208 Merge main 2026-10-22 23:23:00 -05:00
Chris Tate 6134dc4c89 Run two-counter while loops as two-counter for loops 2026-10-22 23:20:40 -05:00
Chris Tate da289bb593 Support writev on Transform and PassThrough, and runtime stream option values 2026-10-22 23:13:49 -05:00
Chris Tate acb31f7144 Dispatch String-only method names on untyped receivers by runtime kind (#1926) 2026-10-22 23:06:28 -05:00
Luis Alvarez D 04583b419f Merge branch 'main' of https://github.com/vercel-labs/scriptc into spli-commonjs-require-bindings 2026-10-22 23:05:49 -05:00
Luis Alvarez D c009b582e2 Support split CommonJS require bindings 2026-10-22 23:05:28 -05:00
Chris Tate 608c6202d4 Spread untyped iterables into Math.min and Math.max (#1928) 2026-10-22 23:02:05 -05:00
Chris Tate ac3cb1c98f Merge main 2026-10-22 22:59:19 -05:00
Chris Tate 7d424368ce Dispatch splice on arrays of unknown elements (#1935) 2026-10-22 22:57:55 -05:00
Chris Tate fc31dd5060 Enumerate each record in the key order its object literal wrote 2026-10-22 22:56:12 -05:00
Chris Tate e3e955eda0 Register Math.min and Math.max spreads as generator steps
dyn.mathFold steps the iterator of an untyped iterable, so the generator
dispatch pass now counts it among the runtime entry points that step
iterators. A generator whose only consumer is Math.min or Math.max then has
its step hooks registered, and the spread folds its values instead of
throwing "Reading this native iterator result has no lowering".
2026-10-22 22:55:26 -05:00
Chris Tate 0624d34786 Merge main 2026-10-22 22:50:18 -05:00
Malte UblandClaude Opus 5.5 dd770477b0 Format the boundary harness test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:47:13 -07:00
Chris Tate b161d0be13 Authenticate empty AES-CCM messages in decipher
A CCM decipher skipped its one update() when the data was empty, and
final() accepted when an update had run without failing, so it never
compared the tag. setAuthTag() with any tag of the right length, then
update() with empty data, then final(), succeeded: anyone could forge an
empty message, or one with different AAD or a different declared
plaintextLength, without the key.

A decipher's update() now runs the authenticated decryption for empty
data too. As in OpenSSL, the tag covers the nonce, the AAD and the
length, so the right tag still opens an empty message and any other
tag, AAD or length fails in final() with "Unsupported state or unable to
authenticate data". final() succeeds only after a tag comparison has
succeeded. A cipher's empty update() is unchanged.
2026-10-22 22:46:00 -05:00
Malte UblandClaude Opus 5.5 0b969479c3 Build fresh literals a JavaScript callee may reshape as plain objects
A fresh TypeScript data literal passed to a checked-dynamic slot became a
typed view whose record layout requires every property, so a JavaScript
callee deleting one (zod 4's `normalizeParams` deletes `params.message`
from `.refine(fn, { message })`) threw "Cannot delete property". When
the callee is implemented in JavaScript (a call through an untyped value,
an untyped parameter of a JavaScript function, or a non-library `.d.ts`
signature whose parameter is untyped or makes one of the literal's
properties optional), the literal has no typed alias and is now built as
the plain object the callee receives. Standard-library and TypeScript
callees, and literals with methods or accessors, keep their native
storage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:40:40 -07:00
Malte Ubl bb28b57063 Merge commit '4f801f1b39285271a755fb6016926a3815f46cac' into HEAD
# Conflicts:
#	packages/runtime/src/scr_node_island_handle.c
2026-10-22 20:32:53 -07:00
Malte Ubl 4f801f1b39 Merge remote-tracking branch 'origin/ni/i9-recorded-deferral' into HEAD 2026-10-22 20:32:37 -07:00
Malte Ubl 5f0941fd5c Merge remote-tracking branch 'origin/ni/i8-exit' into HEAD 2026-10-22 20:32:21 -07:00
Chris Tate 7b9ac8d5bb Merge main 2026-10-22 22:26:04 -05:00
Malte Ubl 02e499f434 Merge remote-tracking branch 'origin/ni/i7-routing' into HEAD
# Conflicts:
#	packages/libnode-common/bridge/scr_node_bridge.cc
2026-10-22 20:26:01 -07:00
Malte Ubl 5695f91291 Merge remote-tracking branch 'origin/ni/i6-subclasses' into HEAD 2026-10-22 20:25:37 -07:00
Malte UblandClaude Opus 5.5 9a452b8129 Keep replaceable method results that have no dynamic form native
A method whose name an untyped write can replace is called through the
instance's property lookup: a ternary between the dynamic call of an
installed replacement and the native call, both boxed into a dynamic
value and converted back to the method's result type. A result with no
dynamic form, such as an Iterable<T> (its generator arm does not box),
stayed unboxed in the dynamic ternary, which failed IR validation with
"ternary else-branch: expected dyn, got union". Methods of generic class
instantiations always take this path once any write can replace their
name, because their prototype data is not modeled, so importing zod
(whose JavaScript has unknown-key writes) broke every such call.

Such a result now keeps its native type: the native call's value is used
as it is, and only a replacement's dynamic result takes the checked
conversion into the result type. Results that box are lowered as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:24:18 -07:00
Chris Tate 97921c2764 Read and write Error.stackTraceLimit through the Error constructor value (#1932) 2026-10-22 22:21:42 -05:00
Malte Ubl 267eb7444e Merge remote-tracking branch 'origin/ni/i5-shared-modules' into HEAD
# Conflicts:
#	packages/compiler/src/backend/llvm/lib-shared.ts
#	packages/compiler/src/ir/builtin-signatures.ts
2026-10-22 20:19:46 -07:00
Malte Ubl b66a1104fe Merge remote-tracking branch 'origin/ni/i4-deferred' into HEAD
# Conflicts:
#	packages/compiler/src/backend/llvm/lib-shared.ts
#	packages/compiler/src/ir/builtin-effects.ts
#	packages/compiler/src/ir/builtin-signatures.ts
#	packages/libnode-common/bridge/scr_node_bridge.cc
2026-10-22 20:19:15 -07:00
Malte Ubl 05f7696eed Merge remote-tracking branch 'origin/ni/i3-exports' into HEAD 2026-10-22 20:18:50 -07:00
Malte UblandClaude Opus 5.5 a8285c756b Clone native data in islands and copy island arrays of plain values
structuredClone in an island of a value holding native records, class
instances or objects (interceptor objects V8's serializer cannot clone)
clones a plain copy of that data, as Node clones the objects themselves.
An island array of primitives or strings (or arrays of those) returned
directly or through a promise crosses as a copy, which the checked cast
then meets, instead of failing the cast as an object handle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:18:17 -07:00
Chris Tate 143f2e11e9 Keep an own stackTraceLimit on the Error value ahead of the limit 2026-10-22 22:15:57 -05:00
Chris TateandQuino Terrasa 84eba88276 Convert typed arrays to BigInt through their element text
BigInt(typedArray) compiled in JavaScript but stopped at run time with
SC2020. Node converts the typed array through ToPrimitive to its elements
joined with "," and parses that text: one element reads as its value, an
empty array as 0n, and several elements, fractions, NaN, Infinity or an
exponent form throw the SyntaxError for the joined text.

- BigInt of a typed array lowers to bigint.parse of its "," join, the same
  conversion Node performs.
- A union whose arms are typed arrays and other BigInt sources dispatches
  each typed-array arm the same way.

Corpus 7403 covers every supported element kind, negative and clamped
values, float formatting (2 ** 60 reads through its shortest decimal
text), empty arrays and views, the SyntaxError cases and results in
arithmetic, and matches Node.

Refs #1647

Co-authored-by: Quino Terrasa <26749475+espetro@users.noreply.github.com>
2026-10-22 22:13:46 -05:00
Chris Tate 75cf8f0e52 Run zod 4's core constructor factory in the dynamic tier (#1918) 2026-10-22 22:08:46 -05:00
Malte UblandClaude Opus 5.5 56f70c47b1 Answer 'in' on native Node handles from their declared members
`"closeAllConnections" in server` (the feature test servers use before
calling it) was refused for an http.Server and the other native handles.
A member Node's declarations give the class is on its prototype, so the
test now answers true after evaluating the receiver. Undeclared names
keep the refusal, since internal fields can still be present.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:06:30 -07:00
Chris Tate 6a1e5103f0 Array keys and properties: non-index number keys, Object.keys, console.log (#1769) 2026-10-22 22:00:27 -05:00
Chris Tate 77c0636826 Include star re-exports in namespace objects, and read causes and instanceof Error like Node under a runtime Error parent
- A module namespace converted to an untyped object, and a computed
  namespace read, use the module's resolved exports, which include the
  members of `export *` declarations.
- `super(message, options)` through a runtime Error parent installs the
  cause as Error does: an inherited `cause` counts, the value is read
  through its getter, and the getter's exception propagates.
- `value instanceof Error` on an instance of a class whose heritage is
  evaluated at run time tests that class's prototype chain for
  Error.prototype. A program with such a class checks prototype chains
  for `instanceof Error` on untyped values.
- The cache of names written on the global object is a Lowerer field
  instead of a WeakMap keyed by the Lowerer.
- errors.test.ts: `"prototype" in Map` answers from the builtin
  constructor's keys now, so it leaves the refused reads and joins a
  check of `in` probes against Node's answers.
2026-10-22 22:00:01 -05:00
Malte UblandClaude Opus 5.5 ca2d5bd9c7 Support String.prototype.at on strings held in untyped values
Hono's mergePath reads base?.at(-1) on an untyped parameter. The
checked-dynamic method dispatch answered at() on strings with a
not-supported error. It now returns the UTF-16 code unit at the index,
counting from the end for a negative index, and undefined outside the
string, as String.prototype.at does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:58:24 -07:00
Chris Tate 12166956b8 Spread protocol iterables into Math.min and Math.max
Math.min(...src) and Math.max(...src) over an untyped source now take its
values the way a spread does: arrays, strings, bytes and collections pack,
a native iterator (a Map's keys()) drains, and other iterables (a generator,
an object with a Symbol.iterator method) step their iterator to the end.
Before, only the packing kinds were accepted and every other iterable threw
the spread TypeError.
2026-10-22 21:57:29 -05:00
Malte Ubl 2c0accca50 Merge ni/i10-js-island-requires into ni/i11-cross-heap-gc 2026-10-22 19:57:02 -07:00
Malte Ubl 8f603cde98 Merge ni/i9-recorded-deferral into ni/i10-js-island-requires 2026-10-22 19:56:57 -07:00
Malte Ubl ae0dd7f2d6 Merge ni/i8-exit into ni/i9-recorded-deferral 2026-10-22 19:56:53 -07:00
Malte Ubl 63269b8009 Merge ni/i7-routing into ni/i8-exit 2026-10-22 19:56:48 -07:00
Chris Tate 09c132fb2e Merge main 2026-10-22 21:55:35 -05:00
Chris Tate 9dbb16d7f8 Support new.target in class constructors (#1917) 2026-10-22 21:52:42 -05:00
Chris Tate ee79ce16e3 Give the zod3-infer npm case the long per-case timeout
A sanitized build of zod3-infer compiles zod 3's types module, as zod3's
does, and takes about as long as the default 120 s on a CI runner.
2026-10-22 21:49:03 -05:00
Chris Tate df9f83bbc1 Refuse new.target over function-local subclasses lowered later
Lowering collects a function-local class with the body declaring it, so
a local subclass whose function lowers after its base's constructor was
missing from new.target's dispatch, which then answered with the base for
its instances. The refusal no longer depends on that order: the program's
function-local classes are found once, and one that extends the
constructor's class, directly or through other classes its extends
clauses name, refuses new.target as a collected one does.
2026-10-22 21:47:37 -05:00
Chris Tate e0f6f094bf Keep int32 slots for long number arrays with checked integer stores (#1931) 2026-10-22 21:46:03 -05:00
Chris Tate bbc9a4e5f9 Read and write the "undefined" property for element indexes that are undefined (#1930) 2026-10-22 21:39:58 -05:00