The tsc-ts 0.0.9 that scriptc includes rejects --listen, so with it every
build that sets SCRIPTC_CHECKER_SERVER=1 checks with its own tsc-ts
process. The variable's description now says so.
With SCRIPTC_CHECKER_SERVER=1 on Linux and macOS, the native compiler's
checker connections go to a shared `tsc-ts --api --listen` server, which
keeps the files it parsed for the next build. When the variable is unset,
nothing changes.
checkerServerName names the server by a digest of the tsc-ts executable's
identity, the working directory, the file system callbacks, the timing
flag and the TSC_TS_* environment. scriptc_ts7_attach takes the server's
lock file with a non-blocking flock, connects to its socket in this
user's private server directory ($XDG_RUNTIME_DIR/scriptc or
/tmp/scriptc-<uid>), and starts the server when none answers: in its own
process group, with its standard streams on /dev/null and no other
descriptor of the build, with --idle-exit 300 and TSC_TS_LISTEN_MEMORY=2048
unless the environment sets it. A build that finds the server in use,
cannot start or reach it, or gets no answer to a ping checks with its own
tsc-ts process, as without the variable; so does a tsc-ts without
--listen, which exits as it starts. The syntax-only source parser, which
reads no libraries, always uses its own process and leaves the server to
the program's checker.
Preflight admits a createRequire loader's require.resolve call with a
computed request inside a try block, but lowering refused the call, so
in JavaScript source the whole statement became a runtime fence. The
fence threw before the request expression ran, and before anything else
in the statement: `try { where = load.resolve(candidate(name)); }`
skipped candidate()'s side effects, so the catch clause saw a different
state than in Node.
Such calls (a computed request, another argument shape, or
runtime-computed options, on require.resolve and require.resolve.paths)
now evaluate their arguments in order and then throw the fence, as a
computed require call does. The addon-probe fixture checks that a
computed candidate path runs before each failed lookup.
A pipeline whose first stage is a checked-dynamic value now checks it at
run time, as Node's stage ladder does: a stream is piped as before, and a
string or a value with a Symbol.asyncIterator or Symbol.iterator method is
pumped into the next stage through an async generator over its iterator.
A typed Set, Map, generator or async generator object as the first stage
takes the same path. This covers the callback and stream/promises forms,
with or without function stages and pipeline options.
A write whose callback fails synchronously no longer sets needDrain, so no
'drain' follows the error and a pumped source stops at the failed write,
as in Node.
RUNTIME_ABI_VERSION goes from 37 to 42 for scr_stream_dyn_iterable_source.
tls.connect, https.request and http2.connect verified the server against
the default CAs when ca was an empty Buffer, because the runtime read a
zero-length ca as none. The compiled calls now pass a null ca for none
(an omitted ca, or an empty string, which Node reads as no ca) and a
non-null one for any Buffer, and runtime option records read ca the same
way, so an empty Buffer or array trusts no certificate, as in Node. The
connection pool keys tell an empty ca from none. An empty array, which
threw, is an empty trust store too. A runtime-valued empty string ca in
http2.connect is refused instead of being read as an empty store.
Partitions were filled by a hash of each function's name, so most calls
crossed partitions and the thin link imported their small callees into
nearly every partition. The emitter now writes a "; scriptc-group" line
before the functions of each source file, and the text partitioner places
a group's functions together: a group larger than the mean partition, or
than 1 MiB, is divided into a power of two of chunks by name, and chunks
go, largest first, to the lighter of two partitions chosen by hash. The
1 MiB bound keeps the code a partition optimizes together, and the
inlining within it, from growing when a program has fewer partitions.
Modules with fewer than 32 partitions, and functions without a group,
keep their name-hash placement: with few partitions per core, the balance
of the largest partitions decides the build time more than the imports.
The placement still depends only on the module text and the partition
count.
The checker resolves an overloaded call whose argument is `any` to the
first overload that argument satisfies, but in JavaScript the value can
select another one: generateKeyPairSync("ec", options) returns KeyObjects
or PEM strings by the options, and digest(encoding) returns a Buffer when
the encoding is undefined. The result was converted to the first
overload's return type, so such calls threw a TypeError where Node
returns the other overload's value.
When a checked-dynamic argument could take another overload whose return
type differs (trailing untyped or undefined arguments may also be
absent), the call's result in a JavaScript source is checked-dynamic. So
are the unannotated bindings it initializes, destructured or not, and
the unannotated functions that return it. fs.globSync keeps choosing its
result form from the resolved overload, since the runtime checks that
withFileTypes agrees with it.
Object.freeze, Object.seal and Object.preventExtensions of a class
instance held in an untyped value threw SC2020 at run time. Node changes
the instance itself: writes through its typed references then throw the
read-only TypeError in strict mode code, adding properties through any
reference fails, and Object.isFrozen, isSealed and isExtensible report
the state through either reference.
- In a program that freezes, seals or prevents extensions of an untyped
value that is not a fresh literal, every class hierarchy that can be held
there gets the integrity word that static Object.freeze already uses, and
with it the existing write checks.
- The runtime applies the operation to the instance's checked view and
commits the view. The commit of such a hierarchy stores the view's
integrity state in the word (scr_dyn_class_view_integrity) and makes the
instance's property bag not extensible with it. A hierarchy without the
word still throws SC2020.
- These commits replace and remove the bag's field entries whatever their
attributes, so a sealed or frozen view does not leave stale field values
in the bag.
- The analysis behind records and arrays now starts from these calls only,
rather than from every untyped freeze the lowering emits, such as the
frozen strings array of a tagged template.
- Programs without such calls compile as before. The runtime ABI moves to
v38.
Corpus 7407 covers freeze, seal and preventExtensions through unknown of
classes and subclasses, writes through typed and untyped references and
through methods, properties added before and after the operation, and the
integrity queries, and matches Node.
Refs #1374
Co-authored-by: blurname <50226652+blurname@users.noreply.github.com>