Store parser errors, source range filenames, source code filenames,
module source, and Rust parser errors as UTF-16 where they flow back
into JavaScript-visible strings. Keep byte-oriented source buffers
byte-backed.
Remove temporary PrimitiveString, ByteString, and UTF-8 detours from
JSON, RegExp, module debug logging, print formatting, and tests.
Thread UTF-16 string input through JSON, script parsing, Date parsing,
Intl option parsing, Temporal parsing, and the helper library boundaries
that feed those parsers. Preserve ASCII fast paths where the source data
is known to be ASCII.
Use the Rust bytecode dumper's basic block collection logic for the
metadata block count. This removes the last C++ bytecode label walk and
lets us delete the generated C++ label and operand visitor helpers.
The Rust bytecode dumper now formats exception handler labels, raw
operands, builtins, labels, and registers. Remove the C++ dump-only
formatters and flatten Operand to expose only the runtime value-array
layout that C++ still observes.
Generate Rust bytecode dump helpers from Bytecode.def and route
Executable::dump() through them for instruction stream formatting.
Add a small Rust runtime::value helper for decoding encoded LibJS
Values so immediate Value operands are formatted on the Rust side. C++
callbacks remain only for local names and GC-backed Value payloads that
still need LibJS object access.
Remove the generated C++ to_byte_string_impl() methods and the old
Instruction::to_byte_string() dispatch. The bytecode dump tests cover
output compatibility.
Add a ref-counted decoded bytecode cache backing so bytecode cache
materialization can create fresh script or module records from a shared
decoded sidecar without passing around one-shot raw blob ownership.
Keep that backing in ExecutableBacking for records materialized from
bytecode cache sidecars, so the immutable decoded data stays alive for
as long as the installed record needs it.
Cover the shared backing path with a bytecode-cache test that
materializes and runs two scripts from one decoded backing.
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`.
Resolve strict global-looking assignment targets before evaluating their
right-hand side instead of lowering them directly to SetGlobal. Preserve
the original unresolvable reference for PutValue so a RHS-created global
cannot hide the ReferenceError.
Add a runtime test for that ordering and update the bytecode expectation
for a strict top-level assignment that now uses SetResolvedBinding.
Parenthesized import calls are valid callees for new expressions. The
unparenthesized form remains a syntax error, but the grouped expression
must parse and then fail at runtime if the produced Promise is not a
constructor.
Add syntax coverage for both forms.
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.
Only drain the standalone Promise job queue when unwinding the outermost
bytecode execution. Draining after every nested run_executable() return
let sibling Promise reactions run before current-job reactions.
Plain async function returns were relying on that extra drain because
return values were compiled as implicit awaits. Resolve completed async
functions through the Promise resolving function instead, while keeping
the async generator return-await path.
Add Promise ordering coverage and update the asm inline-call regression
to check the pre-drain state.
Resolve dynamic identifier assignment targets before evaluating the
right hand side, then store through that saved environment record. This
matches the ECMA-262 ordering for simple assignment and var initializers
when a with binding is deleted or direct eval creates a nearer var.
Add runtime coverage for with and direct-eval cases and refresh bytecode
expectations for dynamic assignments that now snapshot the binding
before storing.
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.
Run deferred parameter validation whenever the surrounding context is
already strict, not only when a function body contains a Use Strict
Directive. Destructured parameter names are collected while parsing the
parameter list, so eval and arguments bindings in patterns otherwise
escaped the strict-mode early error for functions and methods.
Add parser coverage for sloppy destructuring remaining accepted, strict
source being rejected, and class methods applying their strict context.
Match ECMA-262's SuperCall evaluation order by resolving the super
constructor before evaluating the argument list. This preserves the
constructor across argument-side prototype mutations and still lets
abrupt argument evaluation happen before the constructor check.
Add LibJS coverage and update bytecode baselines for the new saved
super-constructor operand. The test262 superCallOrder staging test now
passes.
Reject parenthesized object and array literals when a destructuring
assignment element is refined into a nested assignment pattern. These
grouped forms do not cover AssignmentPattern, while parenthesized simple
assignment targets such as identifiers and member expressions remain
valid.
Add local syntax coverage for the invalid nested patterns and the valid
simple target cases.
Apply the `async of` grammar exclusion only to ordinary for-of
statements. The for-await-of production excludes `let` at the start of
the left-hand side, but does not exclude `async of`, so `async` remains
a valid assignment target there.
Add local parser coverage for async functions and async generators.
Parse await through the unary-expression path so the existing
exponentiation early error also applies to AwaitExpression. This keeps
parenthesized await expressions valid while rejecting await on the
left-hand side of **.
Add parser coverage for the async-function constructor case.
Reject labels whose string value is an unconditional ReservedWord,
while keeping await and yield on their contextual identifier paths.
This makes super labels a syntax error, matching ECMA-262 and V8.
Add coverage for the rejected super label form.
NamedEvaluation for assignment only applies when the left hand side is
an IdentifierRef. Parenthesized identifiers are still assignment
targets, but are not IdentifierRefs, so `(fn) = function () {}` must
leave the function anonymous.
Carry the parser's parenthesized-LHS bit into assignment codegen. Use
it when setting pending_lhs_name for plain and logical assignment, and
cover parenthesized assignment targets in the function-name tests.
The delete operator needs the Reference produced by an optional chain
when the chain ends in a property access. We evaluated the chain for
side effects and returned true, so delete object?.property reported
success without removing the property.
Emit delete-specific optional-chain bytecode. It short-circuits to true
for nullish optional hops, but performs DeleteById or DeleteByValue
when the final property reference is reached. Add runtime coverage for
named, computed, and short-circuited optional deletes.
`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.
Sync yield* must suspend with the delegated IteratorResult object itself
on non-terminal steps. We were reading value and yielding that value,
causing Generator.prototype.next() to create a fresh result object.
Add a bytecode op for this path so ordinary yield keeps wrapping its
value, and teach generator resume to return the prebuilt result object.
This also avoids touching value before the delegated iterator is done.
Add regression coverage and update the yield* bytecode baseline.
Reset the legacy octal string marker at the start of each directive
prologue scan. Otherwise an octal string parsed later in an outer
function body can leak into a nested function and be treated as part of
that nested function's directive prologue.
Add coverage for a nested strict function following a non-directive
octal string in the outer function body.
Reject for-await loop heads that fall through to normal for-loop or
for-in parsing. ECMA-262 only defines for-await with for-of productions,
and V8 rejects these forms as syntax errors.
Add parser coverage for the valid for-await-of form and the invalid
C-style and for-in forms.
Mark binding-pattern identifiers with their declaration kind so local
destructuring assignments use the normal TDZ and const assignment path.
This makes local const destructuring match the environment-backed path.
Also teach GetById to expose primitive string virtual index properties
before boxing, matching StringGetOwnProperty and GetByValue. Together
these fix the SpiderMonkey for-in/of const declaration coverage and the
lexical destructuring TDZ test.
YieldExpression carries the surrounding In grammar parameter into its
operand. The parser was always parsing yield operands with In enabled,
accepting invalid generator for-loop heads containing `yield ... in`.
GeneratorExpression parses its optional binding identifier with the
Yield grammar parameter enabled, so `yield` is not a valid name for
a named generator expression. Reject it while still allowing sloppy
generator declarations named `yield`, and add syntax coverage for
both cases.
ArrowFunction carries the surrounding In grammar parameter into its
ConciseBody. The parser recognized arrows in for-loop init expressions,
but parsed expression bodies with In always enabled, so
`for (x => 0 in 1;;)` was accepted as a normal for loop.
Thread the existing forbidden-token state through arrow parsing so the
body leaves `in` for the for-head parser. That parser then rejects the
arrow as an invalid for-in left-hand side. Add coverage in the for-loop
no-In syntax test.
Annex B.3.2 suppresses the labelled FunctionDeclaration early error
in non-strict code when the host supports that compatibility feature.
Script and block statement lists already enabled that path, but function
bodies parsed their statement lists with it disabled.
Parse function-body statement lists with the same labelled-function
allowance while the existing strict and generator checks continue to
reject the invalid forms. Add coverage for all three cases.
Record the generator's strictness for each emitted bytecode
instruction, instead of applying the executable's final strictness to
every instruction during assembly. This lets class heritage and
computed element names run with strict assignment semantics inside
sloppy scripts.
Also create the class self-binding as a strict immutable binding,
matching ClassDefinitionEvaluation, and cover strict class heritage and
computed names in the runtime tests.
SingleNameBinding default initializers use NamedEvaluation when the
argument value is undefined and the initializer is an anonymous function
or class definition.
Set the pending inferred name while evaluating default initializers for
identifier parameters, and add coverage for function, generator, async,
arrow, and class expressions.
WithStatement evaluation updates empty statement completions to
undefined. The bytecode generator reused the surrounding completion
register while compiling the with body, so an empty break or continue
could leak the enclosing loop's previous completion value.
Give the with body its own completion register initialized to undefined
and add regression coverage for abrupt exits from the body.
Treat ordinary and generator function expressions inside class static
blocks as boundaries for await binding names, while still rejecting
await as an arrow parameter in the static block itself.
Parse field initializers without inheriting an enclosing async
function's await-expression context, so script field initializers can
resolve await as an identifier while computed field names still use the
enclosing expression context.
Cover static block function expressions, class field initializers, and
the AST shape for an await arrow inside a nested function.
Evaluate member targets in object destructuring before reading the
source property or copying rest properties. Convert computed source
property keys before evaluating the target reference so the generated
bytecode follows the spec ordering.
Cover plain, computed, defaulted, and rest object destructuring.
ClassHeritage parses an extends clause as a LeftHandSideExpression,
which excludes unparenthesized arrow functions. Reject arrows that start
at the heritage expression while still allowing parenthesized arrows and
arrows nested inside call arguments.
Add class inheritance coverage for declarations, expressions, and nested
arrow arguments.
Formal parameter early errors depend on the final parameter-list shape.
A duplicate in `function(a, a, ...rest)` was accepted because the
duplicate appeared before the rest parameter was seen.
Track the final simple-parameter-list result before checking duplicate
names, and enforce `UniqueFormalParameters` for method definitions. Add
coverage for sloppy functions with a later rest parameter and sloppy
object methods.
Track private identifiers that eval code references outside a local
class body and pass them through EvalDeclarationInstantiation data.
This lets direct eval validate those names against the caller private
environment before execution, while indirect eval and missing names
still throw SyntaxError.
Add coverage for direct eval access from methods, field initializers,
static methods, and the missing-private-name SyntaxError path.
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.
Route abrupt completions from array destructuring target, default, and
store evaluation through IteratorClose when the iterator is still open.
Keep abrupt completions from iterator stepping itself on the existing
propagation path, matching the spec distinction used by other engines.
Also write back bytecode iterator done state when iterator abstract
operations mark the iterator as completed, so later close decisions see
the updated Iterator Record state. Add regression coverage for target,
default, iterator-next, and generator-return paths.
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.
Duplicate sloppy block function declarations append duplicate runtime
bindings, and name lookup resolves to the newest slot. The bytecode
coordinate tracker was keeping the first slot instead, so a second
InitializeLexicalBinding could target an already initialized binding
when running through the C++ interpreter.
Record every emitted binding creation and let later duplicates replace
the coordinate map entry, matching the way DeclarativeEnvironment
appends bindings.
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.