Commit graph

36 commits

Author SHA1 Message Date
Andreas Kling
1f6ca58e55 LibJS: Remove C++ AST constructor from SharedFunctionInstanceData
Remove the constructor that took C++ AST nodes (FunctionParameters,
Statement), along with create_for_function_node() and the
m_formal_parameters / m_ecmascript_code fields. These were only used
by the now-removed C++ compilation pipeline.

Also remove the dead EvalDeclarationData::create(VM&, Program&, bool)
and ECMAScriptFunctionObject::ecmascript_code() accessor.
2026-03-19 21:55:10 -05:00
Andreas Kling
272562ddc5 LibJS: Remove dead C++ bytecode compilation functions
Remove Bytecode::compile() and the old create() overloads on
ECMAScriptFunctionObject that accepted C++ AST nodes. These
have no remaining callers now that all compilation goes through
the Rust pipeline.

Also remove the if-constexpr Parse Node branch from
async_block_start, since the Statement template instantiation
was already removed.

Fix transitive include dependencies on Generator.h by adding
explicit includes for headers that were previously pulled in
transitively.
2026-03-19 21:55:10 -05:00
Tim Ledbetter
36f74ba96c Revert "LibJS: Shrink ExecutionContext by replacing ScriptOrModule …"
… with Cell*.

This reverts commit d3495c62a7.
2026-03-11 23:13:18 +00:00
Andreas Kling
d3495c62a7 LibJS: Shrink ExecutionContext by replacing ScriptOrModule with Cell*
Replace the 16-byte Variant<Empty, GC::Ref<Script>, GC::Ref<Module>>
with a simple 8-byte GC::Ptr<Cell> that points to either a Script or
Module (or is null for Empty).

A helper function script_or_module_from_cell() converts back to the
full ScriptOrModule variant when needed (e.g. in
VM::get_active_script_or_module).
2026-03-11 13:33:47 +01:00
Andreas Kling
c5427e5f4e LibJS: Convert Object bitfields to a flags byte
Replace individual bool bitfields in Object (m_is_extensible,
m_has_parameter_map, m_has_magical_length_property, etc.) with a
single u8 m_flags field and Flag:: constants.

This consolidates 8 scattered bitfields into one byte with explicit
bit positions, making them easy to access from generated assembly
code at a known offset. It also converts the virtual is_function()
and is_ecmascript_function_object() methods to flag-based checks,
avoiding virtual dispatch for these hot queries.

ProxyObject now explicitly clears the IsFunction flag in its
constructor when wrapping a non-callable target, instead of relying
on a virtual is_function() override.
2026-03-07 13:09:59 +01:00
Andreas Kling
27fa0aac98 LibJS: Inline JS-to-JS calls in the bytecode interpreter dispatch loop
Instead of recursing through 5 native stack frames per JS function
call (execute_call -> internal_call -> ordinary_call_evaluate_body ->
run_executable -> run_bytecode), handle Call and CallConstruct for
normal ECMAScript functions directly in the dispatch loop.

The fast path allocates the callee's execution context on the
InterpreterStack, copies arguments, sets up the environment, and
jumps to the callee's bytecode entry point. Return and End unwind
inline frames by restoring the caller's state. Exception unwinding
walks through inline frames to find handlers.

The fast path code is kept in NEVER_INLINE helper functions
(try_inline_call, try_inline_call_construct, pop_inline_frame) to
minimize register pressure in the dispatch loop. handle_exception
takes program_counter by value to avoid forcing it onto the stack.
Reloading of bytecode/program_counter after frame switches is done
inline at each call site via RELOAD_AND_GOTO_START to preserve a
single dispatch entry point for optimal indirect branch prediction.
2026-03-04 18:53:12 +01:00
Andreas Kling
7281091fdb LibJS: Make bytecode generation infallible
Remove CodeGenerationError and make all bytecode generation functions
return their results directly instead of wrapping them in
CodeGenerationErrorOr.

For the few remaining sites where codegen encounters an unimplemented
or unexpected AST node, we now use a new emit_todo() helper that emits
a NewTypeError + Throw sequence at compile time (preserving the runtime
behavior) and then switches to a dead basic block so subsequent codegen
for the same function can continue without issue.

This allows us to remove error handling from all callers of the
bytecode compiler, simplifying the code significantly.
2026-02-12 11:37:43 +01:00
Andreas Kling
9ea5aa93f8 LibJS: Pre-store formal parameter runtime data
Replace the runtime uses of formal_parameters() with pre-computed data:
- m_formal_parameter_count stores the parameter count
- m_parameter_names_for_mapped_arguments stores ordered parameter names
  for simple parameter lists (used by create_mapped_arguments_object)

Change create_mapped_arguments_object to take Span<Utf16FlyString>
instead of NonnullRefPtr<FunctionParameters const>.

Remove virtual formal_parameters() from FunctionObject as it is no
longer needed.
2026-02-11 23:57:41 +01:00
Andreas Kling
658ba1d023 LibJS: Clear compile-only data from SharedFunctionInstanceData
After successful bytecode compilation, the m_functions_to_initialize
and m_var_names_to_initialize_binding vectors are no longer needed
as they are only consumed by emit_function_declaration_instantiation()
during code generation.

Add clear_compile_inputs() to release these vectors post-compile,
and call it from both ECMAScriptFunctionObject::get_stack_frame_size()
and NativeJavaScriptBackedFunction::bytecode_executable() after their
respective lazy compilation succeeds.

Also add a pre-compile assertion in Generator::generate_from_function()
to verify we never try to compile the same function data twice, and a
VERIFY in ECMAScriptFunctionObject::ecmascript_code() to guard against
null dereference.
2026-02-11 23:57:41 +01:00
Andreas Kling
4d92c4d71a LibJS: Skip initializing constant slots in ExecutionContext
Every function call allocates an ExecutionContext with a trailing array
of Values for registers, locals, constants, and arguments. Previously,
the constructor would initialize all slots to js_special_empty_value(),
but constant slots were then immediately overwritten by the interpreter
copying in values from the Executable before execution began.

To eliminate this redundant initialization, we rearrange the layout from
[registers | constants | locals] to [registers | locals | constants].
This groups registers and locals together at the front, allowing us to
initialize only those slots while leaving constant slots uninitialized
until they're populated with their actual values.

This reduces the per-call initialization cost from O(registers + locals
+ constants) to O(registers + locals).

Also tightens up the types involved (size_t -> u32) and adds VERIFYs to
guard against overflow when computing the combined slot counts, and to
ensure the total fits within the 29-bit operand index field.
2026-01-19 10:48:12 +01:00
Andreas Kling
63eccc5640 LibJS: Don't make extra copies of every JS function's source code
Instead, let functions have a view into the AST's SourceCode object's
underlying string data. The source string is kept alive by the AST, so
it's fine to have views into it as long as the AST exists.

Reduces memory footprint on my x.com home feed by 65 MiB.
2025-12-21 10:06:04 -06:00
Andreas Kling
cbe75f8251 LibJS: Lazily instantiate "prototype" field on ECMAScriptFunctionObject
This field is rarely accessed but we were creating it for every single
script function instantiated.

It's a little awkward but the same optimization can be found in other
engines, so it's nothing crazy.

This avoids creating roughly 80,000 objects on my x.com home feed.
2025-12-17 12:50:17 -06:00
Luke Wilde
2d15326f5d LibJS: Moved SharedFunctionInstanceData into separate files
This will allow it to be reused by NativeJavaScriptBackedFunction.
2025-11-30 11:54:54 +01:00
Andreas Kling
9dae1acc31 LibJS: Pass ExecutionContext to Interpreter::run_executable()
This avoids having to get it from the VM's context stack, since most
callers already have it on hand.
2025-10-29 21:20:10 +01:00
Andreas Kling
4c7ffc0552 LibJS: Remove ExecutionContext::function_name field
Instead of having ExecutionContext track function names separately,
we give FunctionObject a virtual function that returns an appropriate
name string for use in call stacks.
2025-10-29 21:20:10 +01:00
Andreas Kling
b712caf855 LibJS: Move bytecode executable cache to SharedFunctionInstanceData
This shrinks every Statement and ECMAScriptFunctionObject by one
pointer, and puts the bytecode cache in the only place that actually
makes use of it anyway: functions.
2025-10-27 21:14:33 +01:00
Andreas Kling
3a38040c82 LibJS: Make SharedFunctionInstanceData GC-allocated 2025-10-27 21:14:33 +01:00
Andreas Kling
e5b07858a2 LibJS: Allocate Call{Construct,DirectEval,Builtin) contexts up front
We already do this for normal Call contexts, so this is just continuing
to propagate the same pattern to other instructions.

Fixes #6026
2025-08-31 15:24:37 +02:00
Timothy Flynn
0efa98a57a LibJS+LibWeb+WebContent: Port JS::PropertyKey to UTF-16
This has quite a lot of fall out. But the majority of it is just type or
UDL substitution, where the changes just fall through to other function
calls.

By changing property key storage to UTF-16, the main affected areas are:
* NativeFunction names must now be UTF-16
* Bytecode identifiers must now be UTF-16
* Module/binding names must now be UTF-16
2025-08-05 07:07:15 -04:00
ayeteadoe
2e2484257d LibJS: Enable EXPLICIT_SYMBOL_EXPORT and annotate minimum symbol set 2025-07-22 11:51:29 -04:00
ayeteadoe
539a675802 LibJS: Revert Enable EXPLICIT_SYMBOL_EXPORT
This reverts commit c14173f651. We
should only annotate the minimum number of symbols that external
consumers actually use, so I am starting from scratch to do that
2025-07-22 11:51:29 -04:00
ayeteadoe
c14173f651 LibJS: Enable EXPLICIT_SYMBOL_EXPORT 2025-06-30 10:50:36 -06:00
Aliaksandr Kalenik
db480b1f0c LibJS: Preserve information about local variables declaration kind
This is required for upcoming change where we want to emit ThrowIfTDZ
for assignment expressions only for lexical declarations.
2025-05-06 12:06:23 +02:00
Andreas Kling
35275651e3 LibJS: Skip stack overflow check in ESFO::prepare_for_ordinary_call()
We already do a stack overflow check when entering run_bytecode(),
which is the first thing that happens when we actually invoke the ESFO
executable.
2025-04-29 02:09:35 +02:00
Andreas Kling
074ca5d5b4 LibJS: Make ESFO::ordinary_call_evaluate_body() return TCO<Value>
This matches what the caller wants to return and allows us to simplify
a bunch of logic around returning a value or throwing.
2025-04-28 12:44:49 +02:00
Andreas Kling
403ae86fd9 LibJS: Pass VM& to ECMAScriptFunctionObject [[Call]] helpers
This avoids fetching the VM from the Cell::private_data() repeatedly.
2025-04-28 12:44:49 +02:00
Andreas Kling
a05be67e4a LibJS: Let invokers (callers) of [[Call]] allocate ExecutionContext
Instead of letting every [[Call]] implementation allocate an
ExecutionContext, we now make that a responsibility of the caller.

The main point of this exercise is to allow the Call instruction
to write function arguments directly into the callee ExecutionContext
instead of copying them later.

This makes function calls significantly faster:
- 10-20% faster on micro-benchmarks (depending on argument count)
- 4% speedup on Kraken
- 2% speedup on Octane
- 5% speedup on JetStream
2025-04-28 01:23:56 +02:00
Andreas Kling
6db20a9453 LibJS: Simplify ECMAScriptFunctionObject.[[Realm]] slot handling
Our engine already keeps track of the home realm for all objects.
This is stored in Shape::realm(). We can use that instead of having
a dedicated member in ESFO for the same pointer.

Since there's always a home realm these days, we can also remove some
outdated fallback code from the days when having a realm was not
guaranteed due to LibWeb shenanigans.
2025-04-12 11:07:48 +02:00
Andreas Kling
4a5863bcdb LibJS: Remove unnecessary FunctionObject::name() virtual
This allows us to remove the BoundFunction::m_name field, which we
were initializing with a formatted FlyString on every function binding,
despite never using it for anything.
2025-04-10 04:01:00 +02:00
Andreas Kling
4593e19bcf LibJS: Make class-specific members of ESFO lazily allocated
We don't need the [[Fields]] and [[PrivateMethods]] slots for most ESFO
instances, so let's reduce their impact on class size!

This shrinks ESFO from 200 bytes to 160 bytes, allowing more allocations
before we have to collect garbage.
2025-04-08 18:52:35 +02:00
Andreas Kling
2a9b6f1d97 LibJS: Move computation out of the ECMAScriptFunctionObject constructor
We were doing way too much computation every time an ESFO was
instantiated. This was particularly sad, since the results of these
computations were identical every time!

This patch adds a new SharedFunctionInstanceData object that gets
shared between all instances of an ESFO instantiated from some kind of
AST FunctionNode.

~5% speedup on Speedometer 2.1 :^)
2025-04-08 18:52:35 +02:00
Andreas Kling
4209b18b88 LibJS: Add ECMAScriptFunctionObject::create_from_function_node() helper
This gives us a shared entry point for every situation where we
instantiate a function based on a FunctionNode from the AST.
2025-04-08 18:52:35 +02:00
Andreas Kling
7477002e46 LibJS: Keep parsed function parameters in a shared data structure
Instead of making a copy of the Vector<FunctionParameter> from the AST
every time we instantiate an ECMAScriptFunctionObject, we now keep the
parameters in a ref-counted FunctionParameters object.

This reduces memory usage, and also allows us to cache the bytecode
executables for default parameter expressions without recompiling them
for every instantiation. :^)
2025-03-27 15:00:43 +00:00
Andreas Kling
46a5710238 LibJS: Use FlyString in PropertyKey instead of DeprecatedFlyString
This required dealing with *substantial* fallout.
2025-03-24 22:27:17 +00:00
Shannon Booth
f87041bf3a LibGC+Everywhere: Factor out a LibGC from LibJS
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:

 * JS::NonnullGCPtr -> GC::Ref
 * JS::GCPtr -> GC::Ptr
 * JS::HeapFunction -> GC::Function
 * JS::CellImpl -> GC::Cell
 * JS::Handle -> GC::Root
2024-11-15 14:49:20 +01:00
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00
Renamed from Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h (Browse further)