Teach import_rust_crate() to track RustFFI.h as a real build output,
and teach the relevant Rust build scripts to rerun when their FFI
inputs change.
Also keep a copy of RustFFI.h in Cargo's own OUT_DIR and restore the
configured FFI output from that cached copy after cargo rustc runs.
This fixes the case where Ninja knows the header is missing, reruns
the custom command, and Cargo exits without rerunning build.rs
because the crate itself is already up to date.
When Cargo leaves multiple hashed build-script outputs behind, pick
the newest root-output before restoring RustFFI.h so we do not copy a
stale header after Rust-side API changes.
Finally, track the remaining Rust-side inputs that could leave build
artifacts stale: LibUnicode and LibJS now rerun build.rs when src/
changes, and the asmintgen rule now depends on Cargo.lock, the
BytecodeDef path dependency, and newly added Rust source files.
Now that LibRegex is safe to use (for parsing) off the main thread,
we can validate regex literals directly while parsing JavaScript.
This allows us to remove the deferred regex compilation pass that we
previously ran on the main thread after parsing JS in the background.
Noticed this pattern when reading some minified JS while debugging a
seemingly unrelated problem and immediately got suspicious because of my
earlier, similar fixes.
The check_undeclared_exports() function only looked at top-level
VariableDeclaration nodes when collecting declared names. This missed
var declarations nested inside for loops, if/else blocks, try/catch,
switch statements, etc. Since var declarations are hoisted to the
enclosing module scope, they are valid export targets.
This caused legitimate modules (like the claude.ai JS bundle) to fail
with "'name' in export is not declared" errors when a var was declared
inside a for loop and later exported.
Fix this by recursively walking nested statements to collect var
declarations, while correctly not crossing function boundaries (since
var does not hoist out of functions) and not collecting block-scoped
let/const declarations.
x >> 0 is a common JS idiom equivalent to ToInt32(x). We already had
this optimization for x | 0, now do it for right shift by zero as well.
This allows the asmint handler for ToInt32 to run instead of the more
expensive RightShift handler, which wastes time loading and checking the
rhs operand and performing a shift by zero.
Add a deduplication cache for double constants, matching the existing
approach for int32 and string constants. Multiple references to the
same floating-point value now share a single constant table entry.
Now that the C++ bytecode pipeline has been removed, we no longer
need to match its register allocation or block layout. This removes:
- All manual drop() calls that existed solely to match C++ register
lifetimes, replaced with scope blocks to naturally limit register
lifetimes without increasing register pressure.
- The unnecessary saved_property copy in update expressions. The
property register is now used directly since emit_update_op
doesn't evaluate user expressions that could mutate it. The copy
is retained in compound/logical assignments where the RHS can
mutate the property variable (e.g. a[i] |= a[++i]).
- All "matching C++", "Match C++", etc. comments throughout
codegen.rs and generator.rs that referenced the removed pipeline.
- Restrict catch parameter conflict check to only direct children
of the catch body block, not nested scopes
- Set new_target_is_valid for dynamic function compilation (new
Function)
- Move check_parameters_post_body before flag restoration in
parse_method_definition so generator methods inside static init
blocks correctly allow 'await' as a parameter name
- Reject duplicate bindings in catch parameter patterns
- Reject redeclaration of catch parameter with let/const/function
- Reject binding patterns with initializers in for-in heads (AnnexB
only permits simple BindingIdentifier with initializer)
- Reject 'await' as binding identifier in class static init blocks
and module code
Check identifier name validity for destructuring assignment pattern
bound names, and validate arrow function parameters after the arrow
is confirmed rather than during speculative parameter parsing.
This fixes arguments/eval as destructuring assignment targets and as
arrow function parameter names in strict mode.
Arrow functions don't have their own new.target binding -- they
inherit from the enclosing scope. At the global level, there is no
enclosing function, so new.target inside a global arrow is invalid.
Add a new_target_is_valid flag to ParserFlags that is set to true
when entering regular (non-arrow) function bodies, method
definitions, and class static init blocks. Arrow functions inherit
the flag from their enclosing scope rather than setting it.