Warm cache hits used to validate bytecode cache blobs on the main
thread. Route script and module sidecars through a worker step that
decodes and validates the cache blob, then returns the validated blob
for main-thread materialization.
Keep the source bytes mmap-backed and avoid decoding the full source on
cache hits. The main thread still computes the UTF-16 source length so
validation can reject stale blobs before materialization.
Remove the decoded source length getter now that sidecar validation uses
the explicit validation API instead.
Add an explicit validation entry point for decoded bytecode cache blobs.
This lets callers validate a blob before materialization while keeping
the existing validated-before-use invariant in place.
Make validation idempotent so a prevalidated blob is not walked again
when materialization reaches the same check. Keep the existing decoded
source length query for callers that still validate synchronously.
Route decoded cache blob owner destruction through the origin event
loop. This lets a worker decode or reject mapped bytecode without
releasing non-atomically refcounted ImmutableBytes off-thread, while
lazy cached function materialization can still retain mmap-backed
bytecode.
Cache materialization used to validate source ranges and bytecode in
separate passes. That made function and class tables decode the same
payloads repeatedly before materialization decoded them again.
Make the materialization validator check source ranges, index bounds,
and bytecode in the same recursive walk. Nested cached function
executables are now decoded once for validation instead of once for
ranges and once for bytecode.
Cache blobs already validate decoded bytecode before rebuilding C++
Bytecode::Executable objects. Keep that as the only cache validation
pass and mark the decoded cache state once it completes.
Materialization now asserts that cache blobs and lazy cached function
records passed through validation before they can be installed or
decoded. This keeps the invariant without re-running the same validator
from rust_create_executable().
Switch bytecode cache source identity from decoded UTF-16 source text to
the original encoded response bytes plus the effective source encoding.
Store the decoded source length in the cache blob header so warm loads
can build lazy SourceCode objects without decoding the source before
checking the sidecar.
This removes the main-thread decoded_source_text_info pass from valid
warm-cache script and module loads. The source is only decoded on cache
miss, or when a rejected sidecar falls back to source compilation.
Move Rust-side cached bytecode validation to the decoded blob
boundary. All script, module, and install paths now reject invalid
cached bytecode before attaching lazy function executables to shared
function data.
This avoids validating the same cached function payload when attaching
it, then again during lazy materialization, and then again as an
executable. The C++ executable validation still runs when
materialization constructs an executable from the already validated
cache payload.
By default, `rustfmt` persists the import granularity. In practice, most
Rust code has import granularity "Module" due to LSP's actions.
"Item" gets rid of import groupings and achieves cleaner diffs and
better conflict resolution. Better greppability is a positive side
effect.
Note: it's an unstable rustfmt feature. `cargo +nightly fmt` must be
used instead of `cargo fmt`.
Give scripts and modules an explicit list of their shared function data
records, and teach Rust materialization to populate that list directly.
This gives bytecode cache installation a stable set of functions to
update when replacing executable backing storage.
Treat labelled FunctionDeclaration nodes as declaration-bearing items
when collecting block lexical and top-level var scoped declarations.
This lets Annex B declaration instantiation initialize them before
execution and copy block functions back to the var binding.
Add LibJS coverage for function bodies, direct eval, blocks, switch
cases, and duplicate labelled declarations.
`import * as ns; export { ns }` was being recorded as a local
export, so two star exports of matching namespace objects resolved
through different fixture modules and became ambiguous.
Emit the same indirect namespace export metadata used by `export * as`
for both normal compilation and bytecode-cache materialization. Add a
module test that merges two matching namespace re-exports.
Use a runtime SetFunctionName bytecode operation when object literal
property keys are not known until evaluation. This lets anonymous
function and class expressions, methods, and accessors receive names
from numeric, computed, and Symbol property keys.
Store inferred ECMAScript function names on each function object instead
of mutating shared function data. That keeps repeated evaluations with
different computed keys from leaking names across closures, while still
using the per-instance name for stack metadata.
Add regression coverage for computed object property names, repeated
computed-key evaluations, and preserving unnamed functions that are only
referenced by a computed property value.
Dynamic environment binding opcodes lost the old coordinate warmup.
They were split away from the static coordinate opcodes. Hot closures
and eval-sensitive functions then resolved the same binding by name on
every execution, which regressed JS benchmark throughput badly.
Give each dynamic environment opcode a per-executable coordinate cache
slot. The cache keeps the bytecode stream immutable while letting both
interpreters take a direct declarative environment fast path after the
first lookup. Keep the existing eval invalidation behavior and only warm
caches for declarative-only chains so with environments continue to
observe object shadowing.
Reject cached bytecode that uses the no-cache sentinel for dynamic
environment coordinate cache operands, since execution indexes those
cache arrays unconditionally.
Rebaseline bytecode expectations for the instruction size changes. Add
coverage for with-object shadowing across repeated dynamic lookups and
for rejecting corrupt dynamic environment cache indices.
Validate cached constant buffers without decoding them into Rust
ConstantValue objects, then pass the bytes to the C++ executable
factory. Align string constants in the FFI encoding so fresh and cached
buffers use the same layout.
Pass decoded UTF-16 table entries to the C++ executable factory as
borrowed FFI slices during bytecode cache materialization. This avoids
copying cache-backed names into generator-owned Rust vectors before C++
materializes its own bytecode tables.
Thread the var environment binding count through the Rust and C++ SFD
metadata helpers wherever the function environment binding count already
travels. This lets CreateVariableEnvironment use the cached var
environment shape for functions with parameter expressions.
Teach Bytecode::Executable to store its instruction stream as either
an owned Vector or a retained Core::ImmutableBytes range. Cached
bytecode materialization now clones the immutable blob owner and lets
the executable point directly into the file-backed cache blob instead
of copying instruction bytes back onto the heap.
Keep a cached instruction data pointer inside the stream wrapper so the
asm interpreter still has a direct hot-path load. Align executable
bytecode payloads in the cache format so mmap-backed instruction
streams satisfy validator and interpreter alignment requirements.
Add separate bytecode instructions for environment lookups that must
stay dynamic, such as eval- and with-sensitive scopes. Keep the
coordinate variants for eagerly resolved declarative environments so
their operands can be treated as immutable at runtime.
This removes cached-coordinate mutation from the interpreter paths and
updates the bytecode expectations for the new dynamic lookup opcodes.
Store compact cache indexes in bytecode instructions instead of raw
pointers to the executable cache vectors. This keeps the instruction
stream independent from heap addresses and removes pointer fixups when
materializing cached bytecode.
Resolve the mutable cache pointers at execution time from the current
Executable. Bytecode test expectations are updated for the smaller cache
operands and resulting instruction offsets.
Store nested function executables in the bytecode cache as
length-prefixed payloads, and keep those payloads mapped instead of
decoding every function when materializing the outer script or module.
Decode and validate a cached function executable only when that
function is installed for lazy materialization.
Validate cached executable bytecode before storing it on shared data,
and recurse source range validation through the lazy executable
payload. This keeps corrupt cache entries on the recoverable
materialization path instead of crashing when a function is first used.
This avoids turning the warm disk cache into retained dirty heap for
all uncalled nested functions on large sites.
Reject counted bytecode cache table payloads whose count is larger than
the payload byte length. All currently encoded records and constants use
at least one payload byte, so these counts cannot be valid. Accepting
them would only risk oversized allocations during materialization.
Add Rust coverage for record sequence and constant table headers with
impossible counts.
Store executable-side tables as counted encoded payloads instead of
allocating decoded Rust vectors while reading the bytecode cache. This
keeps identifier, property key, string, exception handler, source map,
local variable, shared function, and class blueprint tables borrowed
from mapped cache blobs until validation or materialization walks them.
Bump the bytecode cache format because these table encodings now carry
raw payload lengths and preserve their own nested alignment.
Store executable constants as a counted encoded payload instead of a
sequence of decoded records. Decoding a mapped cache blob can now retain
that payload as a borrowed range and postpone inflating ConstantValue
objects until executable materialization actually needs them.
Bump the bytecode cache format and pad serialized UTF-16 strings to u16
alignment. This lets mapped cache blobs expose decoded UTF-16 payloads
as FFI slices directly instead of re-decoding them into temporary
aligned buffers during materialization.
Update the bytecode cache corruption helpers to skip the new string
padding when walking serialized blobs.
Keep decoded executable strings as ranges into the mapped bytecode cache
blob when the decoder has a foreign owner. Materialize aligned UTF-16
buffers only when passing the data to C++ or rebuilding generator-owned
structures for executable creation.
This covers executable string tables, string constants, local variable
names, nested function metadata, and cached class blueprint strings. Add
Rust coverage for borrowing decoded UTF-16 payloads from a foreign blob.
Keep executable bytecode payloads decoded from owner-backed bytecode
cache blobs as ranges into the original blob instead of copying them
into Rust Vec allocations. The mapped blob owner is held by decoded
executable records, including lazy nested function executables, so the
borrowed bytecode remains alive until materialization copies it into the
final C++ Executable.
Use the owner-backed decoder for HTTP bytecode cache hits and keep the
plain byte decoder for tests and in-memory callers. Add coverage for
materializing bytecode cache data from an ImmutableBytes mapped file.
Keep basic block offsets as construction-only metadata rather than
storing them on every Executable. The validator now receives the offsets
through a transient Rust FFI span, and the bytecode dump rebuilds block
starts by scanning labels, terminators, and exception handler metadata.
Drop the table from the bytecode cache format and bump the format
version so old caches are rebuilt. This removes a field that was only
used by validation and bytecode dump paths.
Store source map locations as bytecode offset, line, and column.
Runtime consumers only emit the start line and column, so source end
positions and source text offsets do not need to be carried through
Executable source maps, bytecode cache serialization, or the Rust FFI.
Keep SourceCode's internal position cache able to track source text
offsets so callers can still translate source offsets to line and
column pairs when needed. Hash dump-bytecode IDs from the name, first
source position, and bytecode size instead of source slices that need
end offsets.
Bump the bytecode cache format version for the slimmer serialized
source map entry shape.
Keep fully compiled function bytecode in its Rust-side form until the
function is called for the first time. This covers decoded disk cache
records and freshly precompiled bytecode, so startup avoids eagerly
allocating every nested function executable.
Validate cached function bytecode before accepting a cache entry. This
keeps the existing failure behavior for corrupt on-disk cache data. Add
coverage for bytecode-cache and freshly precompiled functions to assert
that nested executables stay absent after script materialization, then
appear after the function is called.
Store the original imported binding name when serializing a re-export of
an imported binding as an indirect export. The cache previously kept the
local alias, so materialized modules could fail to resolve valid exports
such as `export { renamed as default }`.
Bump the bytecode cache format version so existing blobs with the stale
metadata are ignored. Add coverage for both normal module loading and
materializing this pattern from bytecode cache.
Create parser-free script and module materializers for decoded cache
blobs. Cached functions create SFDs without Rust compile inputs and
attach their precompiled executable immediately, while declaration
metadata is populated from decoded records.
Treat cache blobs as external input from the HTTP disk cache. Run
bytecode validation unconditionally before fixing up cache pointers, and
reject decoded source ranges or metadata indices that would be
out-of-bounds during C++ materialization.
Report executable validation failures as parser errors so callers can
reject corrupt sidecars and fall back to source compilation. LibJS tests
cover corrupt top-level bytecode, declaration bytecode, and declaration
source spans.
Store a SHA-256 fingerprint of the decoded source text in each bytecode
cache blob, and require callers to provide the expected fingerprint when
validating or decoding a blob.
This rejects sidecars for stale HTTP cache entries whose URL and request
headers still match but whose source body has been replaced. Bytecode
cache tests cover the mismatched-source rejection path.
Expose an owned decoded bytecode cache handle through RustIntegration.
This lets C++ callers keep validated metadata and executable records in
Rust-owned cache structures without invoking the parser.
Extend the js bytecode cache validation mode to create and free the FFI
handle so blob generation exercises the ownership path.
Precompile top-level function declarations used during script and
module instantiation while producing a full bytecode cache entry. Keep
normal off-thread execution artifacts on the existing eager path, and
store declaration records separately from executable nested functions.
Place those records after declaration metadata in the cache blob, and
bump the blob version so older sidecars are rejected.
Make bytecode cache validation return a decoded blob containing the
validated program record, declaration metadata, and executable records.
This keeps a single Rust-owned object alive for consumers that need to
materialize cached bytecode after validation succeeds.
Decode bytecode cache executable records into owned Rust data instead
of only skipping over their serialized fields during validation.
Keep cached bytecode, constants, nested functions, and class blueprints
available for later materialization without rebuilding ASTs.
Store and decode script declaration-instantiation metadata and module
import, export, request, and declaration metadata in bytecode cache
blobs.
Return decoded metadata as owned Rust records so warm-cache script and
module construction can recover parser-derived facts from the sidecar.
Record whether each bytecode cache blob contains a classic script or a
module, and pass that type through the serializer call sites.
Require validation callers to provide the expected program type so
script and module sidecars cannot be reused for the wrong loader.
Add structural validation for bytecode cache blobs using the serialized
record layout. The decoder shares primitive helpers across cache
sections instead of duplicating flat parsing logic.
Reject bad magic values, unsupported versions, invalid enum tags, and
truncated sections before materialization. Bound sequence reads against
the remaining blob so malformed sidecars cannot force large allocations.
Add a versioned Rust bytecode cache writer for fully compiled programs.
The blob records executable bytecode, metadata tables, source maps,
exception handlers, nested function bytecode, and class blueprints
without materializing GC objects.
Expose the serialized blob through RustIntegration as an owned
ByteBuffer so Web-facing callers can store it as HTTP cache data.