2026-02-23 07:50:46 -03:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2026, Andreas Kling <andreas@ladybird.org>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2026-05-03 13:53:38 -03:00
|
|
|
#include <AK/ByteBuffer.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <AK/HashTable.h>
|
2026-02-27 19:44:14 -03:00
|
|
|
#include <AK/NonnullRefPtr.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <AK/Optional.h>
|
|
|
|
|
#include <AK/Result.h>
|
2026-05-21 16:49:43 -03:00
|
|
|
#include <AK/Span.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <AK/Utf16FlyString.h>
|
2026-05-15 11:45:31 -03:00
|
|
|
#include <LibCore/ImmutableBytes.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <LibGC/Ptr.h>
|
|
|
|
|
#include <LibGC/Root.h>
|
2026-03-19 15:37:46 -03:00
|
|
|
#include <LibJS/ModuleEntry.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <LibJS/ParserError.h>
|
|
|
|
|
#include <LibJS/Runtime/AbstractOperations.h>
|
|
|
|
|
#include <LibJS/Runtime/FunctionKind.h>
|
|
|
|
|
#include <LibJS/Script.h>
|
2026-02-27 19:44:14 -03:00
|
|
|
#include <LibJS/SourceCode.h>
|
2026-02-23 07:50:46 -03:00
|
|
|
#include <LibJS/SourceTextModule.h>
|
|
|
|
|
|
2026-02-27 19:44:14 -03:00
|
|
|
// Opaque parsed program handle from the Rust pipeline.
|
2026-03-17 18:47:58 -03:00
|
|
|
namespace JS::FFI {
|
|
|
|
|
|
|
|
|
|
struct ParsedProgram;
|
2026-04-26 09:53:34 -03:00
|
|
|
struct CompiledProgram;
|
2026-05-05 09:24:11 -03:00
|
|
|
struct CompiledFunction;
|
2026-05-03 14:48:26 -03:00
|
|
|
struct DecodedBytecodeCacheBlob;
|
2026-03-17 18:47:58 -03:00
|
|
|
|
|
|
|
|
}
|
2026-02-27 19:44:14 -03:00
|
|
|
|
2026-02-23 07:50:46 -03:00
|
|
|
namespace JS::RustIntegration {
|
|
|
|
|
|
2026-02-27 19:44:14 -03:00
|
|
|
enum class ProgramType : u8 {
|
|
|
|
|
Script = 0,
|
|
|
|
|
Module = 1,
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-23 07:50:46 -03:00
|
|
|
// Result type for compile_script().
|
|
|
|
|
// NB: Uses GC::Root to prevent collection while the result is in transit
|
|
|
|
|
// between compile_script() and the Script constructor.
|
|
|
|
|
struct ScriptResult {
|
|
|
|
|
GC::Root<Bytecode::Executable> executable;
|
2026-05-21 16:49:43 -03:00
|
|
|
Vector<GC::Root<SharedFunctionInstanceData>> shared_function_data;
|
2026-02-23 07:50:46 -03:00
|
|
|
bool is_strict_mode { false };
|
|
|
|
|
Vector<Utf16FlyString> lexical_names;
|
|
|
|
|
Vector<Utf16FlyString> var_names;
|
|
|
|
|
struct FunctionToInitialize {
|
|
|
|
|
GC::Root<SharedFunctionInstanceData> shared_data;
|
|
|
|
|
Utf16FlyString name;
|
|
|
|
|
};
|
|
|
|
|
Vector<FunctionToInitialize> functions_to_initialize;
|
|
|
|
|
HashTable<Utf16FlyString> declared_function_names;
|
|
|
|
|
Vector<Utf16FlyString> var_scoped_names;
|
|
|
|
|
Vector<Utf16FlyString> annex_b_candidate_names;
|
|
|
|
|
Vector<Script::LexicalBinding> lexical_bindings;
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-03 09:34:03 -03:00
|
|
|
// Result type for compile_eval().
|
2026-02-23 07:50:46 -03:00
|
|
|
// NB: Uses GC::Root to prevent collection while the result is in transit.
|
|
|
|
|
struct EvalResult {
|
|
|
|
|
GC::Root<Bytecode::Executable> executable;
|
|
|
|
|
bool is_strict_mode { false };
|
|
|
|
|
EvalDeclarationData declaration_data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Result type for compile_module().
|
|
|
|
|
// NB: Uses GC::Root to prevent collection while the result is in transit.
|
|
|
|
|
struct ModuleResult {
|
|
|
|
|
bool has_top_level_await { false };
|
|
|
|
|
Vector<ModuleRequest> requested_modules;
|
|
|
|
|
Vector<ImportEntry> import_entries;
|
|
|
|
|
Vector<ExportEntry> local_export_entries;
|
|
|
|
|
Vector<ExportEntry> indirect_export_entries;
|
|
|
|
|
Vector<ExportEntry> star_export_entries;
|
|
|
|
|
Optional<Utf16FlyString> default_export_binding_name;
|
|
|
|
|
Vector<Utf16FlyString> var_declared_names;
|
|
|
|
|
Vector<SourceTextModule::LexicalBinding> lexical_bindings;
|
|
|
|
|
struct FunctionToInitialize {
|
|
|
|
|
GC::Root<SharedFunctionInstanceData> shared_data;
|
|
|
|
|
Utf16FlyString name;
|
|
|
|
|
};
|
|
|
|
|
Vector<FunctionToInitialize> functions_to_initialize;
|
|
|
|
|
GC::Root<Bytecode::Executable> executable;
|
2026-05-21 16:49:43 -03:00
|
|
|
Vector<GC::Root<SharedFunctionInstanceData>> shared_function_data;
|
2026-02-23 07:50:46 -03:00
|
|
|
GC::Root<SharedFunctionInstanceData> tla_shared_data;
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-27 19:44:29 -03:00
|
|
|
// Check if the Rust pipeline is available for off-thread parsing.
|
|
|
|
|
JS_API bool rust_pipeline_available();
|
|
|
|
|
|
2026-02-27 19:44:14 -03:00
|
|
|
// Parse a program (script or module) without GC interaction. Thread-safe.
|
2026-03-17 18:47:58 -03:00
|
|
|
JS_API FFI::ParsedProgram* parse_program(u16 const* utf16_data, size_t length_in_code_units, ProgramType type, size_t line_number_offset = 0);
|
2026-02-27 19:44:14 -03:00
|
|
|
|
2026-04-26 09:53:34 -03:00
|
|
|
// Compile a parsed program to bytecode without touching the VM or GC. Thread-safe.
|
|
|
|
|
JS_API FFI::CompiledProgram* compile_parsed_program_off_thread(FFI::ParsedProgram* parsed, size_t length_in_code_units);
|
|
|
|
|
|
2026-05-03 13:43:14 -03:00
|
|
|
// Fully compile a parsed program to bytecode without touching the VM or GC. Thread-safe.
|
|
|
|
|
JS_API FFI::CompiledProgram* compile_parsed_program_fully_off_thread(FFI::ParsedProgram* parsed, size_t length_in_code_units);
|
|
|
|
|
|
2026-03-19 15:20:30 -03:00
|
|
|
// Check if a parsed program has errors. Does not consume the program.
|
|
|
|
|
JS_API bool parsed_program_has_errors(FFI::ParsedProgram const*);
|
|
|
|
|
|
|
|
|
|
// Free a parsed program without compiling it.
|
|
|
|
|
JS_API void free_parsed_program(FFI::ParsedProgram*);
|
|
|
|
|
|
2026-04-26 09:53:34 -03:00
|
|
|
// Free a compiled program without materializing it.
|
|
|
|
|
JS_API void free_compiled_program(FFI::CompiledProgram*);
|
|
|
|
|
|
2026-05-03 13:53:38 -03:00
|
|
|
// Serialize a fully compiled program into a versioned bytecode cache blob.
|
2026-05-03 17:49:29 -03:00
|
|
|
JS_API ByteBuffer serialize_compiled_program_for_bytecode_cache(FFI::CompiledProgram const&, ProgramType, ReadonlyBytes source_hash);
|
2026-05-03 13:53:38 -03:00
|
|
|
|
2026-05-21 16:49:43 -03:00
|
|
|
// Decode an ImmutableBytes-backed bytecode cache blob into a parser-free cache handle.
|
2026-05-15 11:45:31 -03:00
|
|
|
JS_API FFI::DecodedBytecodeCacheBlob* decode_bytecode_cache_blob(Core::ImmutableBytes, ProgramType, ReadonlyBytes source_hash);
|
2026-05-03 14:48:26 -03:00
|
|
|
|
|
|
|
|
// Free a decoded bytecode cache blob.
|
|
|
|
|
JS_API void free_decoded_bytecode_cache_blob(FFI::DecodedBytecodeCacheBlob*);
|
|
|
|
|
|
2026-05-03 14:53:55 -03:00
|
|
|
// Materialize a decoded script bytecode cache blob. Must be called on the main thread.
|
|
|
|
|
// Consumes and frees the decoded blob.
|
|
|
|
|
JS_API Optional<Result<ScriptResult, Vector<ParserError>>> materialize_bytecode_cache_script(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&);
|
|
|
|
|
|
|
|
|
|
// Materialize a decoded module bytecode cache blob. Must be called on the main thread.
|
|
|
|
|
// Consumes and frees the decoded blob.
|
|
|
|
|
JS_API Optional<Result<ModuleResult, Vector<ParserError>>> materialize_bytecode_cache_module(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&);
|
|
|
|
|
|
2026-05-21 16:49:43 -03:00
|
|
|
struct ModuleBytecodeCacheInstallResult {
|
|
|
|
|
GC::Root<Bytecode::Executable> executable;
|
|
|
|
|
GC::Root<Bytecode::Executable> top_level_await_executable;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Try to install a decoded script bytecode cache blob into an existing script executable tree.
|
|
|
|
|
// Must be called on the main thread. Consumes and frees the decoded blob.
|
|
|
|
|
JS_API GC::Ptr<Bytecode::Executable> try_install_bytecode_cache_script(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&, Bytecode::Executable& existing_executable, ReadonlySpan<SharedFunctionInstanceData*> existing_shared_function_data);
|
|
|
|
|
|
|
|
|
|
// Install a decoded script bytecode cache blob produced by the current process.
|
|
|
|
|
// Must be called on the main thread. Consumes and frees the decoded blob.
|
|
|
|
|
JS_API GC::Ref<Bytecode::Executable> install_generated_bytecode_cache_script(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&, Bytecode::Executable& existing_executable, ReadonlySpan<SharedFunctionInstanceData*> existing_shared_function_data);
|
|
|
|
|
|
|
|
|
|
// Try to install a decoded module bytecode cache blob into an existing module executable tree.
|
|
|
|
|
// Must be called on the main thread. Consumes and frees the decoded blob.
|
|
|
|
|
JS_API Optional<ModuleBytecodeCacheInstallResult> try_install_bytecode_cache_module(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&, Bytecode::Executable* existing_executable, ReadonlySpan<SharedFunctionInstanceData*> existing_shared_function_data, SharedFunctionInstanceData* existing_top_level_await_shared_data);
|
|
|
|
|
|
|
|
|
|
// Install a decoded module bytecode cache blob produced by the current process.
|
|
|
|
|
// Must be called on the main thread. Consumes and frees the decoded blob.
|
|
|
|
|
JS_API ModuleBytecodeCacheInstallResult install_generated_bytecode_cache_module(FFI::DecodedBytecodeCacheBlob*, NonnullRefPtr<SourceCode const> source_code, Realm&, Bytecode::Executable* existing_executable, ReadonlySpan<SharedFunctionInstanceData*> existing_shared_function_data, SharedFunctionInstanceData* existing_top_level_await_shared_data);
|
|
|
|
|
|
2026-02-27 19:44:14 -03:00
|
|
|
// Compile a previously parsed script. Must be called on the main thread.
|
2026-03-17 18:47:58 -03:00
|
|
|
// Consumes and frees the Rust ParsedProgram.
|
2026-02-27 19:44:14 -03:00
|
|
|
// Returns nullopt if Rust is not available.
|
2026-03-17 18:47:58 -03:00
|
|
|
Optional<Result<ScriptResult, Vector<ParserError>>> compile_parsed_script(FFI::ParsedProgram* parsed, NonnullRefPtr<SourceCode const> source_code, Realm& realm);
|
2026-02-27 19:44:14 -03:00
|
|
|
|
2026-04-26 09:53:34 -03:00
|
|
|
// Materialize a previously compiled script. Must be called on the main thread.
|
|
|
|
|
// Consumes and frees the Rust CompiledProgram.
|
|
|
|
|
Optional<Result<ScriptResult, Vector<ParserError>>> materialize_compiled_script(FFI::CompiledProgram* compiled, NonnullRefPtr<SourceCode const> source_code, Realm& realm);
|
|
|
|
|
|
2026-02-23 07:50:46 -03:00
|
|
|
// Compile a script. Returns nullopt if Rust is not available.
|
2026-02-27 19:44:14 -03:00
|
|
|
Optional<Result<ScriptResult, Vector<ParserError>>> compile_script(StringView source_text, Realm& realm, StringView filename, size_t line_number_offset);
|
2026-02-23 07:50:46 -03:00
|
|
|
|
|
|
|
|
// Compile eval code. Returns nullopt if Rust is not available.
|
|
|
|
|
// On success, the executable's name is set to "eval".
|
|
|
|
|
Optional<Result<EvalResult, String>> compile_eval(
|
|
|
|
|
PrimitiveString& code_string, VM& vm,
|
|
|
|
|
CallerMode strict_caller, bool in_function, bool in_method,
|
|
|
|
|
bool in_derived_constructor, bool in_class_field_initializer);
|
|
|
|
|
|
2026-02-27 19:44:44 -03:00
|
|
|
// Compile a previously parsed module. Must be called on the main thread.
|
2026-03-17 18:47:58 -03:00
|
|
|
// Consumes and frees the Rust ParsedProgram.
|
2026-02-27 19:44:44 -03:00
|
|
|
// Returns nullopt if Rust is not available.
|
2026-03-17 18:47:58 -03:00
|
|
|
Optional<Result<ModuleResult, Vector<ParserError>>> compile_parsed_module(FFI::ParsedProgram* parsed, NonnullRefPtr<SourceCode const> source_code, Realm& realm);
|
2026-02-27 19:44:44 -03:00
|
|
|
|
2026-04-26 09:53:34 -03:00
|
|
|
// Materialize a previously compiled module. Must be called on the main thread.
|
|
|
|
|
// Consumes and frees the Rust CompiledProgram.
|
|
|
|
|
Optional<Result<ModuleResult, Vector<ParserError>>> materialize_compiled_module(FFI::CompiledProgram* compiled, NonnullRefPtr<SourceCode const> source_code, Realm& realm);
|
|
|
|
|
|
2026-02-23 07:50:46 -03:00
|
|
|
// Compile a module. Returns nullopt if Rust is not available.
|
2026-02-27 19:44:44 -03:00
|
|
|
Optional<Result<ModuleResult, Vector<ParserError>>> compile_module(StringView source_text, Realm& realm, StringView filename);
|
2026-02-23 07:50:46 -03:00
|
|
|
|
2026-03-19 14:41:49 -03:00
|
|
|
// Compile a dynamic function (new Function()).
|
2026-02-23 07:50:46 -03:00
|
|
|
// On success, returns a SharedFunctionInstanceData with source_text set.
|
2026-03-19 14:41:49 -03:00
|
|
|
JS_API Optional<Result<GC::Ref<SharedFunctionInstanceData>, String>> compile_dynamic_function(
|
2026-02-23 07:50:46 -03:00
|
|
|
VM& vm, StringView source_text, StringView parameters_string, StringView body_parse_string,
|
|
|
|
|
FunctionKind kind);
|
|
|
|
|
|
|
|
|
|
// Compile a builtin JS file. Returns nullopt if Rust is not available.
|
|
|
|
|
Optional<Vector<GC::Root<SharedFunctionInstanceData>>> compile_builtin_file(
|
|
|
|
|
unsigned char const* script_text, VM& vm);
|
|
|
|
|
|
|
|
|
|
// Compile a function body for lazy compilation.
|
|
|
|
|
// Returns nullptr if Rust is not available or the SFD doesn't use Rust compilation.
|
|
|
|
|
GC::Ptr<Bytecode::Executable> compile_function(VM& vm, SharedFunctionInstanceData& shared_data, bool builtin_abstract_operations_enabled);
|
|
|
|
|
|
2026-05-05 09:24:11 -03:00
|
|
|
JS_API void* clone_function_ast(void const*);
|
|
|
|
|
JS_API FFI::CompiledFunction* compile_function_off_thread(void* function_ast, size_t length_in_code_units, bool builtin_abstract_operations_enabled);
|
2026-05-13 18:35:55 -03:00
|
|
|
// Attach a previously compiled function for lazy materialization.
|
2026-05-05 09:24:11 -03:00
|
|
|
JS_API void materialize_compiled_function(FFI::CompiledFunction*, VM&, SourceCode const&, SharedFunctionInstanceData&);
|
|
|
|
|
JS_API void free_compiled_function(FFI::CompiledFunction*);
|
|
|
|
|
|
2026-05-13 18:35:55 -03:00
|
|
|
// Free a Rust decoded bytecode cache executable pointer. No-op if null.
|
|
|
|
|
void free_cached_bytecode_executable(void*);
|
|
|
|
|
|
|
|
|
|
// Free a Rust precompiled bytecode executable pointer. No-op if null.
|
|
|
|
|
void free_precompiled_bytecode_executable(void*);
|
|
|
|
|
|
2026-02-23 07:50:46 -03:00
|
|
|
// Free a Rust function AST pointer. No-op if Rust is not available.
|
|
|
|
|
void free_function_ast(void* ast);
|
|
|
|
|
|
|
|
|
|
}
|