Errors that reach checked-dynamic code are objects carrying the reserved
"%error" marker, with name and message either own or on their prototype.
Several string conversions handled them differently from Node:
- `"" + error`, `error + ""` and `error == "TypeError: ..."` converted
through the plain-object path and answered "[object Object]".
- Template literals and Array join read name and message as own members
only, so a builtin error whose name is inherited printed its message
alone.
- String(error) used the native error, which did not see name and message
assigned through the dynamic view.
scr_dyn_error_string implements Error.prototype.toString over the
encoding, reading both members through the prototype, and the template
renderer, Array join, ToPrimitive, ToString and the numeric conversion use
it. Assigning a string name or message through the dynamic view now also
updates the native error, as assigning stack and cause already did.
markAsUncloneable(value) marks a plain object, a record, an error or a
class instance (scr_json.c); structuredClone and postMessage then throw
DataCloneError "Cannot clone object of unsupported type." for it, also
where it is nested. As in Node, the mark has no effect on primitives,
arrays, typed arrays and ArrayBuffers. Marked values are retained until
the thread exits; with nothing marked, the clone paths add one branch.
worker[Symbol.asyncDispose]() terminates the worker and resolves with
undefined after its 'exit' event, so `await using` disposes a Worker at
the end of its block. The Worker handle's symbol_get op answers the
well-known symbol: the symbol unit registers Symbol.asyncDispose with the
dyn core when the program names it, and scr_dyn_is_async_dispose_symbol
tells the worker unit, so worker programs that never name the symbol do
not link the symbol unit.
static-support.json adds rows for markAsUncloneable, isInternalThread
(already lowered as false and declared) and worker[Symbol.asyncDispose]().
Corpus 5990-5991 match Node v24.22.0; corpus-costs.json records their
costs.
Regex literals and new RegExp calls accept the v (unicode sets) flag, which
the vendored engine implements: class subtraction and intersection, nested
classes, \q{...} string literals and properties of strings. The flag uses
unicode mode for pattern decoding and string iteration, and flags read in
getter order (dgimsuvy). Regex literals now also report their flags in
getter order, as Node does for /x/yg, and the flag getters (global,
unicodeSets and the rest) compile on statically typed regexes.
In v mode the engine rejected `-` and doubled punctuation outside a
character class, and the `\-` escape inside \q{...}. It now applies the
class-only checks inside classes and \q{...} only, and parses \q{...}
contents with the class escapes, matching Node. The d flag is still
refused.
The Node oracle runs with the harness's environment, but its cached
verdict was keyed only on SCRIPTC_TEST_ENV among the variables. A
program whose output reads NODE_ENV or another variable reused a
verdict recorded under a different value. The key now covers every
inherited variable except the test runner's worker numbers, which
differ between workers of one run.
Closes#51
Co-authored-by: Patrick Wozniak <4481570+patlux@users.noreply.github.com>
The util.types brands answered isFloat16Array with false for every value.
Float16Array now answers it from the value's storage kind, ahead of that
probe, so this drops the unreachable entry and the declaration that
returns boolean.
querystring.parse and querystring.decode build their result with a null
prototype, as Node does: util.inspect prints the [Object: null prototype]
base, Object.getPrototypeOf answers null, ToPrimitive throws a TypeError,
and Object.prototype methods are not reachable through the result.
An inline JavaScript callback receives a matchAll row as a dynamic
array. The groups projection now reads its captures through dynamic
index reads, and throws Node's TypeError for null and undefined rows.
Rows kept by filter, slice, toReversed and toSorted, or picked by find,
findLast and at, trace to the drain's regex; a reassigned callback
parameter does not. { groups } patterns serve dynamic rows and pattern
parameters. The groups record has a null prototype.
maybeNarrow takes the receiver's declared shape from its non-nullable
type, so a JavaScript read of a nonparticipating group keeps its
undefined arm instead of narrowing to string.
`"method" in instance` on a class instance held as `any` answered false
for the class's methods, getters and setters when the program also uses
instanceof or Object.getPrototypeOf on the class. Those uses attach the
class's prototype data to the instance's snapshot, and that object holds
only the methods the program reads through the prototype; the literal-key
`in` then searched it instead of the class.
When a literal key names a method or accessor of a boxed class with
prototype data, the class dynamic-dispatch pass now evaluates `in`
through the computed-key form, which answers class members from the class
itself.
renderDiagnostics printed every frame line whole and rebuilt the
file's line index for each diagnostic. On minified sources with
thousands of diagnostics the joined report exceeded V8's string length
and `scriptc coverage` crashed with RangeError: Invalid string length.
Frame lines longer than 400 characters now show a 400-character window
around the diagnostic's column, with "…" where text is cut, and the line
index is built once per file. Every diagnostic is still rendered.
Closes#201
Co-authored-by: Max B <32987678+techfreaque@users.noreply.github.com>
On Linux, a worker thread that exits without having made any object it
allocated reachable from another thread gives back all of its memory: the
pages it carved, including ProgramLifetime instances and other objects it
never freed, and the system blocks it still holds.
A worker carves past each slice's frontier while the arena's free lists and
returned regions are set aside, takes from those free lists only once a
slice has no bump room left, and records the system blocks it allocates.
Messages and intern tables that share published graphs by pointer, and the
process-wide key arrays of typed records, mark the thread as sharing; so
does a remote free of one of its blocks. When a worker that did not share
parks, the trim helper returns its pages, frees its system blocks, and
restores the arena to its state at the claim, with the free blocks the
worker took free again. A worker that shared keeps its memory as before.
SCR_SA_DISCARD=0 keeps every worker's memory; SCR_SA_DISCARD=poison makes
the discarded pages inaccessible instead, for tests.
Inside a monomorphized generic body the checker keeps mapped types over
the function's own type parameters symbolic. The instance binds those
parameters, so { [K in keyof S]: T } now maps each property of the bound
type through the template evaluated at that key, covering indexed
templates (S[K], S[K]["_output"]) and conditional ones with infer
(S[K] extends Schema<infer T> ? T : never). Conditional types over bound
parameters evaluate the same way elsewhere in the body.
Closes#886
Co-authored-by: Malek Mohamed Noureldean Elkssas <87043730+malekelkssas@users.noreply.github.com>