Commit graph

32 commits

Author SHA1 Message Date
Andreas Kling
b81269e78b Libraries: Clean up UTF-16 source text paths
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.
2026-06-22 19:51:25 +02:00
Andreas Kling
b6bef6b688 Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including
numeric formatting, BigInt and BigFraction formatting, URI encoding,
console formatting, parser errors, regular expression errors, Intl and
Temporal records, LibUnicode locale boundaries, and LibWeb bindings.

Handle fractional radix formatting through the UTF-16 builder view.
2026-06-22 19:51:25 +02:00
Andreas Kling
7025dd1fa7 Libraries: Parse JS strings from UTF-16
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.
2026-06-22 19:51:25 +02:00
Andreas Kling
e5bcffc3d5 LibJS: Move bytecode block counting to Rust
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.
2026-06-15 02:41:57 +02:00
Andreas Kling
7a6af95db3 LibJS: Move bytecode instruction dumping to Rust
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.
2026-06-15 02:41:57 +02:00
Andreas Kling
6ecfcd3e68 LibWeb+LibJS: Cache decoded JS bytecode sidecars
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.
2026-06-06 09:15:09 +02:00
Andreas Kling
ec421d7fa4 LibWeb+LibJS: Validate bytecode cache blobs off-thread
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.
2026-06-05 21:55:55 +02:00
Andreas Kling
bb20f15965 LibJS: Prepare bytecode cache validation off-thread
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.
2026-06-05 21:55:55 +02:00
Andreas Kling
bf81464904 LibWeb+LibJS: Remove rust_pipeline_available
The Rust pipeline is always available now, so the getter only wrapped
code that always ran. Remove it and make the JavaScript fetch paths use
the off-thread Rust pipeline directly.

This also removes the unreachable synchronous fallback branches from the
classic script and module fetch paths.
2026-06-05 21:55:55 +02:00
Andreas Kling
afb0fa2413 LibJS: Hash encoded source identity in bytecode cache
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.
2026-06-03 14:11:23 +02:00
Andreas Kling
795a82d621 LibJS: Track shared function data ownership
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.
2026-05-22 10:54:44 +02:00
Andreas Kling
a646f9d0bf LibJS: Borrow mapped bytecode cache executable bytes
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.
2026-05-16 08:13:35 +02:00
Andreas Kling
e926e86f8d LibJS: Materialize compiled function bytecode lazily
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.
2026-05-14 08:15:01 +02:00
Andreas Kling
afa1f77252 LibJS: Materialize decoded bytecode cache blobs
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.
2026-05-06 08:20:06 +02:00
Andreas Kling
b265694f0d LibJS: Match bytecode cache blobs to their source
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.
2026-05-06 08:20:06 +02:00
Andreas Kling
de9f2b8343 LibJS: Decode bytecode cache blobs over FFI
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.
2026-05-06 08:20:06 +02:00
Andreas Kling
c5b6739c47 LibJS: Tag bytecode cache blobs with program type
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.
2026-05-06 08:20:06 +02:00
Andreas Kling
96a6782800 LibJS: Serialize compiled bytecode cache blobs
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.
2026-05-06 08:20:06 +02:00
Andreas Kling
f25f245b3c LibJS: Split full off-thread script compilation
Keep fetched script and module compilation on the latency-sensitive path
limited to top-level code and eager direct IIFE compilation before
returning bytecode to the main thread.

Add a separate full off-thread compile entry point for bytecode cache
generation. Cache jobs can use it to compile every nested function after
the execution path has already been unblocked.
2026-05-06 08:20:06 +02:00
Andreas Kling
3604259676 LibJS: Add off-thread function bytecode artifacts
Add Rust and C++ integration points for cloning lazy function compile
payloads, compiling them to GC-free bytecode off the main thread, and
materializing the result later on the main thread.

The cloned payload lets background compilation race with lazy
main-thread compilation without sharing AST ownership between threads.
Compiled function artifacts recursively include nested functions, so
materialization can discard the corresponding AST subtree.
2026-05-06 08:20:06 +02:00
Andreas Kling
4a7dc45b3f LibWeb+LibJS: Compile fetched top-level JS off-thread
Split Rust program compilation so code generation and assembly finish
before the main thread materializes GC-backed executable objects. The
new CompiledProgram handle owns the parsed program, generator state, and
bytecode until C++ consumes it on the main thread.

Wire WebContent script fetching through that handle for classic scripts
and modules. Syntax-error paths still return ParsedProgram, so existing
error reporting stays in place. Successful fetches now do top-level
codegen on the thread pool before deferred_invoke hands control back to
the main thread.

Executable creation, SharedFunctionInstanceData materialization, module
metadata extraction, and declaration data extraction still run on the
main thread where VM and GC access is valid.
2026-04-26 21:51:52 +02:00
Shannon Booth
f27bc38aa7 Everywhere: Remove ShadowRealm support
The proposal has not seemed to progress for a while, and there is
a open issue about module imports which breaks HTML integration.
While we could probably make an AD-HOC change to fix that issue,
it is deep enough in the JS engine that I am not particularly
keen on making that change.

Until other browsers begin to make positive signals about shipping
ShadowRealms, let's remove our implementation for now.

There is still some cleanup that can be done with regard to the
HTML integration, but there are a few more items that need to be
untangled there.
2026-04-05 13:57:58 +02:00
Andreas Kling
8ec7e7c07c LibJS: Remove C++ AST
Delete AST.cpp, AST.h, ASTDump.cpp, ScopeRecord.h, and the dead
get_builtin(MemberExpression const&) from Builtins.cpp.

Extract ImportEntry and ExportEntry into a new ModuleEntry.h,
since they are data types used by the module system, not AST
node types.

Inline ModuleRequest's sorting constructor and
SourceRange::filename().

Remove the dead annex_b_function_declarations field from
EvalDeclarationData, which was only populated by the C++ parser.
2026-03-19 21:55:10 -05:00
Andreas Kling
169452f41b LibJS: Remove C++ parser
Delete Parser.cpp/h and ScopeCollector.cpp/h, now that all parsing
goes through the Rust pipeline.

Port test262-runner to use RustIntegration::parse_program() for its
fast parse-only check instead of the C++ Parser.

Add parsed_program_has_errors() and free_parsed_program() to the
RustIntegration public API for parse-only use cases.
2026-03-19 21:55:10 -05:00
Andreas Kling
3518efd71c LibJS+LibWeb: Port remaining callers to Rust pipeline
Port all remaining users of the C++ Parser/Lexer/Generator to
use the Rust pipeline instead:

- Intrinsics: Remove C++ fallback in parse_builtin_file()
- ECMAScriptFunctionObject: Remove C++ compile() fallback
- NativeJavaScriptBackedFunction: Remove C++ compile() fallback
- EventTarget: Port to compile_dynamic_function
- WebDriver/ExecuteScript: Port to compile_dynamic_function
- LibTest/JavaScriptTestRunner.h: Remove Parser/Lexer includes
- FuzzilliJs: Remove unused Parser/Lexer includes

Also remove the dead Statement-based template instantiation of
async_block_start/async_function_start.
2026-03-19 21:55:10 -05:00
Andreas Kling
2c45472a11 LibJS: Remove pipeline comparison infrastructure
Remove PipelineComparison.cpp/h and all LIBJS_COMPARE_PIPELINES
support from RustIntegration.cpp. This includes:

- The compare_pipelines_enabled() function
- All comparison blocks in compile_script/eval/module/function
- The pair_shared_function_data() helper
- The m_cpp_comparison_sfd field on SharedFunctionInstanceData

The Rust pipeline has been validated extensively through comparison
testing and no longer needs the side-by-side verification harness.
2026-03-19 21:55:10 -05:00
Andrew Kaster
92e4c20ad5 LibJS: Generate FFI header using cbindgen instead of hand-rolling
Replace the BytecodeFactory header with cbindgen.

This will help ensure that types and enums and constants are kept in
sync between the C++ and Rust code. It's also a step in exporting more
Rust enums directly rather than relying on magic constants for
switch statements.

The FFI functions are now all placed in the JS::FFI namespace, which
is the cause for all the churn in the scripting parts of LibJS and
LibWeb.
2026-03-17 20:49:50 -05:00
Andreas Kling
3f4d3d6108 LibJS+LibWeb: Add C++ compile_parsed_module wrapper
Add compile_parsed_module() to RustIntegration, which takes a
RustParsedProgram and a SourceCode (from parse_program with
ProgramType::Module) and compiles it on the main thread with GC
interaction.

Rewrite compile_module() to use the new split functions internally.

Add SourceTextModule::parse_from_pre_parsed() and
JavaScriptModuleScript::create_from_pre_parsed() to allow creating
module scripts from a pre-parsed RustParsedProgram.

This prepares the infrastructure for off-thread module parsing.
2026-03-06 13:06:05 +01:00
Andreas Kling
d8921646f5 LibJS+LibWeb: Parse classic scripts off the main thread
Create a SourceCode on the main thread (performing UTF-8 to UTF-16
conversion), then submit parse_program() to the ThreadPool for
Rust parsing on a worker thread. This unblocks the WebContent event
loop during external script loading.

Add Script::create_from_parsed() and
ClassicScript::create_from_pre_parsed() factory methods that take a
pre-parsed RustParsedProgram and a SourceCode, performing only the
GC-allocating compile step on the main thread.

Falls back to synchronous parsing when the Rust pipeline is
unavailable (LIBJS_CPP=1 or LIBJS_COMPARE_PIPELINES=1).
2026-03-06 13:06:05 +01:00
Andreas Kling
6983c6b1a5 LibJS: Add C++ parse_program/compile_parsed_script wrappers
Expose the Rust parse/compile split to C++ callers:

- parse_program(): takes raw UTF-16 data and a ProgramType
  parameter (Script or Module). No GC interaction, thread-safe.
- compile_parsed_script(): takes a pre-parsed RustParsedProgram
  and a SourceCode, checks for errors, and calls
  rust_compile_parsed_script(). Returns a ScriptResult.

Rewrite compile_script() to use the split path internally. The
pipeline comparison logic now gets the AST dump from the
ParsedProgram before compilation consumes it.
2026-03-06 13:06:05 +01:00
Ali Mohammad Pur
3a5a6b741d LibJS: Include AST.h in RustIntegration.h
This was breaking the no-rust build with gcc.
2026-02-24 15:18:57 +01:00
Andreas Kling
6cdfbd01a6 LibJS: Add alternative source-to-bytecode pipeline in Rust
Implement a complete Rust reimplementation of the LibJS frontend:
lexer, parser, AST, scope collector, and bytecode code generator.

The Rust pipeline is built via Corrosion (CMake-Cargo bridge) and
linked into LibJS as a static library. It is gated behind a build
flag (ENABLE_RUST, on by default except on Windows) and two runtime
environment variables:

- LIBJS_CPP: Use the C++ pipeline instead of Rust
- LIBJS_COMPARE_PIPELINES=1: Run both pipelines in lockstep,
  aborting on any difference in AST or bytecode generated.

The C++ side communicates with Rust through a C FFI layer
(RustIntegration.cpp/h) that passes source text to Rust and receives
a populated Executable back via a BytecodeFactory interface.
2026-02-24 09:39:42 +01:00