Commit Graph

424 Commits

Author SHA1 Message Date
Andreas Kling
a124af2abb LibJS: Migrate walk_env_chain and the binding handlers
Convert the walk_env_chain macro to take its outputs (target_env,
bind_index) as explicit parameters, then migrate every handler that
walks the environment chain: GetBinding, GetInitializedBinding,
InitializeLexicalBinding, SetLexicalBinding, and
GetCalleeAndThisFromEnvironment.

The macro's internal scratch (the EnvironmentCoordinate address, the
hops counter, the invalid-coord sentinel, and the screwed-by-eval
flag) is now declared as macro-local temps that the allocator places
without touching whatever the caller has live. Each handler picks
its own names for env / idx / binding / value, instead of remembering
that the macro happens to leave them in t3 and t2.
2026-04-26 13:29:56 +02:00
Andreas Kling
bb23e784dc LibJS: Migrate bitwise/UnaryPlus path and coerce_to_int32s macro
Convert coerce_to_int32s and bitwise_op to take operand temps as
explicit parameters, then migrate UnaryPlus.

The bitwise_op macro is the actual body of BitwiseAnd, BitwiseOr, and
BitwiseXor (which just call into it), so a single macro migration
covers all three handlers. UnaryPlus is migrated alongside since it
shares the same coerce-to-int32 conceptual path.
2026-04-26 13:29:56 +02:00
Andreas Kling
3a9661aa22 LibJS: Migrate equality handlers and their core macros
Convert the equality dispatch chain to take operand temps as explicit
parameters: equality_same_tag, double_equality_compare,
strict_equality_core, and loose_equality_core. Then migrate the
StrictlyEquals, StrictlyInequals, LooselyEquals, LooselyInequals,
JumpStrictlyEquals, JumpStrictlyInequals, JumpLooselyEquals, and
JumpLooselyInequals handlers.

These macros are tightly coupled -- strict_equality_core and
loose_equality_core both invoke equality_same_tag and reach
double_equality_compare via .double_compare, a label that crosses
macro boundaries. The existing label-uniquification rule (only
self-contained labels are renamed) keeps that contract working
without further plumbing.
2026-04-26 13:29:56 +02:00
Andreas Kling
86476e80e0 LibJS: Migrate Add/Sub/Mul, comparisons, and their core macros
Convert the heavy comparison and arithmetic macros to take their
operand temps as explicit parameters, then migrate every handler that
uses them: coerce_to_doubles, numeric_compare, numeric_compare_coerce,
boolean_result_epilogue, jump_binary_epilogue, plus the Add, Sub, Mul,
LessThan, LessThanEquals, GreaterThan, GreaterThanEquals,
JumpLessThan, JumpGreaterThan, JumpLessThanEquals, and
JumpGreaterThanEquals handlers.
2026-04-26 13:29:56 +02:00
Andreas Kling
123616d8ef LibJS: Migrate scratch-using helper macros to macro-local temps
Convert check_is_double, check_both_double, and box_double_or_int32 to
declare their internal scratch as macro-local `temp` decls instead of
hardcoding t3/t4. Each invocation now gets a freshly uniquified temp
that the allocator places independently of any other live values in
the caller, so adding a `temp` declaration around a sequence that
calls into one of these macros no longer needs to know which
positional slot the macro happened to be using.

box_double_or_int32 in particular is on the hot arithmetic path
(Add/Sub/Mul/PostfixIncrement/etc.), so this opens the door to
migrating those handlers without conflicting with the macro's
internal scratch use.
2026-04-26 13:29:56 +02:00
Andreas Kling
a19ae44977 LibJS: Migrate PostfixIncrement/PostfixDecrement/UnaryMinus/ToInt32
Convert these handlers to named DSL temporaries.
2026-04-26 13:29:56 +02:00
Andreas Kling
7fcaace5e8 LibJS: Migrate ThrowIf*/BitwiseNot/Shift* to named DSL temporaries
Convert another batch of macro-free handlers to named DSL temporaries.
The shift handlers in particular are nice exercises of the allocator's
fixed-operand support: x86's `shl`/`shr`/`sar` need the count register
to be rcx, and the allocator pins the named `count` temp accordingly
without the user having to remember it.
2026-04-26 13:29:56 +02:00
Andreas Kling
ddc5b995e5 LibJS: Migrate Increment/Decrement/Not/Return/End and friends
Convert another batch of straightforward handlers to named DSL
temporaries: Increment, Decrement, Not, GetLexicalEnvironment, Return,
and End. The migration uncovers a pleasing property of the new
pipeline: when a migrated handler invokes an un-migrated macro
(pop_inline_frame_and_resume here, which still uses positional t2/t3
/t4 internally), the macro body's positional uses appear as physical-
register defs in the flat instruction list and the allocator's
liveness analysis avoids placing live named temps in those registers.
2026-04-26 13:29:56 +02:00
Andreas Kling
9790948279 LibJS: Migrate JumpIf/JumpTrue/JumpFalse to named DSL temporaries
Convert the three boolean-conditional jump handlers to named temps,
exercising the 3-operand call_helper form so the input value and
truthy result no longer have to be pinned to t1/t0 by hand. The
allocator places `condition` in rcx (matching call_helper's input
convention) and `truthy` in rax (matching its output) automatically.
2026-04-26 13:29:56 +02:00
Andreas Kling
3d5b5602b4 LibJS: Migrate simple jump handlers to named DSL temporaries
Convert Jump, JumpNullish, and JumpUndefined to declare named
temporaries instead of pinning values to t0..t2 directly. These three
handlers are macro-free and call-free, so the migration is mechanical
and the allocator picks register assignments equivalent in cost to
the hand-written positional code.

The other Jump* handlers (JumpIf/JumpTrue/JumpFalse) drive
call_helper, which still needs the value to be in t1 (rcx) on x86 by
the existing register convention. Migrating those needs DSL syntax to
attach call_helper's input/output to named temps; until that lands
they stay on the positional form.
2026-04-26 13:29:56 +02:00
Andreas Kling
f1f7039d10 LibJS: Migrate Mov/Mov2/Mov3 handlers to named DSL temporaries
These three trivial data-movement handlers are a useful first
migration target -- they exercise the new `temp` declaration syntax
and the register allocator end-to-end without interacting with macros
or fixed-operand constraints. The allocator picks t1-equivalent
registers for the first temp (which is the smallest live range that
must survive load_operand's rax/x9 scratch use) and reuses the slot
across non-overlapping live ranges where possible.
2026-04-26 13:29:56 +02:00
Andreas Kling
eb9432fcb8 LibJS: Preserve source positions in bytecode source maps
Carry full source positions through the Rust bytecode source map so
stack traces and other bytecode-backed source lookups can use them
directly.

This keeps exception-heavy paths from reconstructing line and column
information through SourceCode::range_from_offsets(), which can spend a
lot of time building SourceCode's position cache on first use.

We're trading some space for time here, but I believe it's worth it at
this tag, as this saves ~250ms of main thread time while loading
https://x.com/ on my Linux machine. :^)

Reading the stored Position out of the source map directly also exposed
two things masked by the old range_from_offsets() path: a latent
off-by-one in Lexer::new_at_offset() (its consume() bumped line_column
past the character at offset; only synthesize_binding_pattern() hit it),
and a (1,1) fallback in range_from_offsets() that fired whenever the
queried range reached EOF. Fix the lexer, then rebaseline both the
bytecode dump tests (no more spurious "1:1") and the destructuring AST
tests (binding-pattern identifiers now report their real columns).
2026-04-22 22:34:54 +02:00
Andreas Kling
e5d4c5cce8 LibJS: Check TDZ state in asm environment calls
GetCalleeAndThisFromEnvironment treated a binding as initialized when
its value slot was not <empty>. Declarative bindings do not encode TDZ
in that slot, though: uninitialized bindings keep a separate initialized
flag and their value starts as undefined.

That let the first slow-path TDZ failure populate the environment cache,
then a second call at the same site reused the cached coordinate and
turned the required ReferenceError into a TypeError from calling
undefined.

Check Binding.initialized in the asm fast path instead and cover the
cached second-hit case with a regression test.
2026-04-20 11:23:34 +02:00
Andreas Kling
583fa475fb LibJS: Call RawNativeFunction directly from asm Call
The asm interpreter already inlines ECMAScript calls, but builtin calls
still went through the generic C++ Call slow path even when the callee
was a plain native function pointer. That added an avoidable boundary
around hot builtin calls and kept asm from taking full advantage of the
new RawNativeFunction representation.

Teach the asm Call handler to recognize RawNativeFunction, allocate the
callee frame on the interpreter stack, copy the call-site arguments,
and jump straight to the stored C++ entry point.
NativeJavaScriptBackedFunction and other non-raw callees keep falling
through to the existing C++ slow path unchanged.
2026-04-15 15:57:48 +02:00
Andreas Kling
23fea4208c LibJS: Pair-load asm global Realm metadata
Place Realm's cached declarative environment next to its global object
so the asm global access fast paths can fetch the two pointers with a
paired load. These handlers never use the intervening GlobalEnvironment
pointer directly.
2026-04-14 12:37:12 +02:00
Andreas Kling
b6c7f6c0c4 LibJS: Cache Executable constants for asm Call
Mirror Executable's constants size and data pointer in adjacent fields
so the asm Call fast path can pair-load them together. The underlying
Vector layout keeps size and data apart, so a small cached raw span
lets the hot constant-copy loop fetch both pieces of metadata at once.
2026-04-14 12:37:12 +02:00
Andreas Kling
5761f6bc54 LibJS: Pair-load PropertyNameIterator index counters
Load PropertyNameIterator's indexed-property count and next index
together when stepping the fast path. Keeping the paired count live
into the named-property case also avoids reloading it before computing
the flattened index.
2026-04-14 12:37:12 +02:00
Andreas Kling
3005945b38 LibJS: Pair-load PropertyNameIterator shape metadata
Load PropertyNameIterator's cached property cache and shape snapshot
together before validating the receiver shape. The two fields already
sit adjacent in the object layout, so the fast path can fetch both
without any extra reshuffling.
2026-04-14 12:37:12 +02:00
Andreas Kling
8dcb2b95ec LibJS: Pair-load asm environment coordinates
Load EnvironmentCoordinate::hops and ::index together in the asm
environment-walk helper. The pair-load keeps the DSL explicit about
which two fields travel together and removes another scalar metadata
fetch from the fast path.
2026-04-14 12:37:12 +02:00
Andreas Kling
acbbb2d726 LibJS: Pair-load property IC lookup metadata
Load the cached property offset and dictionary generation with paired
loads in the property inline-cache fast paths. AsmIntGen now verifies
these reads against the actual cache layout, so the DSL keeps both
fields named and self-documenting.
2026-04-14 12:37:12 +02:00
Andreas Kling
335c278b8f LibJS: Pair-load property IC shape metadata
Load the cached shape and prototype pointer together in the property
inline-cache fast paths that already read both. This keeps the
cache-entry metadata fetches aligned with the DSL's paired-load model
without changing the surrounding control flow.
2026-04-14 12:37:12 +02:00
Andreas Kling
75eb3a28ce LibJS: Pair-load asm Return resume metadata
Load the inline frame's return pc and destination register at once when
Return or End resumes an asm-managed caller. This keeps the unwind
metadata with the helper that consumes it and removes a separate scalar
load from both handlers.
2026-04-14 12:37:12 +02:00
Andreas Kling
58aa725afb LibJS: Reuse executable state in asm Call
The asm Call fast path was still reloading the executable pointer while
building the inline callee frame, even though it had already loaded the
same pointer while validating the call target.

Carry that executable pointer through frame setup and reload the passed
argument count from the call bytecode instead of the fresh frame header.
This trims a couple more loads from the hot path.
2026-04-14 12:37:12 +02:00
Andreas Kling
517812647a LibJS: Pack asm Call shared-data metadata
Pack the asm Call fast path metadata next to the executable pointer
so the interpreter can fetch both values with one paired load. This
removes several dependent shared-data loads from the hot path.

Keep the executable pointer and packed metadata in separate registers
through this binding so the fast path can still use the paired-load
layout after any non-strict this adjustment.

Lower the packed metadata flag checks correctly on x86_64 as well.
Those bits now live above bit 31, so the generator uses bt for single-
bit high masks and covers that path with a unit test.

Add a runtime test that exercises both object and global this binding
through the asm Call fast path.
2026-04-14 12:37:12 +02:00
Andreas Kling
50c497c59b LibJS: Use precomputed asm Call frame counts
Executable already caches the combined registers, locals, and constants
count that the asm Call fast path needs for inline frame allocation.

Use that precomputed total instead of rebuilding it from the registers
count and constants vector size in the hot path.
2026-04-14 12:37:12 +02:00
Andreas Kling
fffc16b2f6 LibJS: Trust inline-call bytecode in asm Call
The asm Call fast path already checks SharedFunctionInstanceData's
cached can_inline_call bit before touching the executable pointer.

That cache is only true for ordinary functions with compiled bytecode,
so the extra executable null check is redundant work in the hot path.
2026-04-14 12:37:12 +02:00
Andreas Kling
44deea24fe LibJS: Pair-load asm Call stack bounds
The asm Call fast path reads InterpreterStack::m_top and m_limit
back-to-back while checking whether the inline callee frame fits.

Those fields are adjacent, so we can load them together with one
paired load and keep the stack-size check otherwise unchanged.
2026-04-14 12:37:12 +02:00
Andreas Kling
fa931612e1 LibJS: Pair-store the asm Call frame setup
Teach the asm Call fast path to use paired stores for the fixed
ExecutionContext header writes and for the caller linkage fields.
This also initializes the five reserved Value slots directly instead
of looping over them as part of the general register clear path.

That keeps the hot frame setup work closer to the actual data layout:
reserved registers are seeded with a couple of fixed stores, while the
remaining register and local slots are cleared in wider chunks.

On x86_64, keep the new explicit-offset formatting on store_pair*
and load_pair* without changing ordinary [base, index, scale]
operands into base-plus-index-plus-offset addresses. Add unit
tests covering both the paired zero-offset form and the preserved
scaled-index lowering.
2026-04-14 12:37:12 +02:00
Andreas Kling
8ae173f4fd LibJS: Use paired loads in the asm Call fast path
Use the new paired-load DSL operations in the inline Call path for the
adjacent environment, ScriptOrModule, caller metadata, and callee-entry
loads. The flow stays the same, but the hot call setup now needs fewer
scalar memory operations on aarch64.
2026-04-14 12:37:12 +02:00
Andreas Kling
8c7c46f8ec LibJS: Inline asm interpreter JS Call fast path
Handle inline-eligible JS-to-JS Call directly in asmint.asm instead
of routing the whole operation through AsmInterpreter.cpp.

The asm handler now validates the callee, binds `this` for the
non-allocating cases, reserves the callee InterpreterStack frame,
populates the ExecutionContext header and Value tail, and enters the
callee bytecode at pc 0.

Keep the cases that need NewFunctionEnvironment() or sloppy `this`
boxing on a narrow helper that still builds an inline frame. This
preserves the existing inline-call semantics for promise-job ordering,
receiver binding, and sloppy global-this handling while keeping the
common path in assembly.

Add regression coverage for closure-capturing callees, sloppy
primitive receivers, and sloppy undefined receivers.
2026-04-14 08:14:43 +02:00
Andreas Kling
7a01a64087 LibJS: Expose asmint Call offset metadata
Emit the ExecutionContext, function-object, executable, and realm
offsets that the asm Call path needs to inspect and initialize
directly when building inline frames.
2026-04-14 08:14:43 +02:00
Andreas Kling
12a916d14a LibJS: Handle AsmInt returns without C++ helpers
Handle Return and End entirely in AsmInt when leaving an inline frame.
The handlers now restore the caller, update the interpreter stack
bookkeeping directly, and bump the execution generation without
bouncing through AsmInterpreter.cpp.

Add WeakRef tests that exercise both inline Return and inline End
so this path stays covered.
2026-04-14 08:14:43 +02:00
Andreas Kling
df0fdee2a0 LibJS: Cache JS-to-JS inline call eligibility
Store whether a function can participate in JS-to-JS inline calls on
SharedFunctionInstanceData instead of recomputing the function kind,
class-constructor bit, and bytecode availability at each fast-path
call site.
2026-04-14 08:14:43 +02:00
Andreas Kling
9af5508aef LibJS: Split inline frames from execution context stack
Keep JS-to-JS inline calls out of m_execution_context_stack and walk
the active stack from the running execution context instead. Base
pushes now record the previous running context so duplicate
TemporaryExecutionContext pushes and host re-entry still restore
correctly.

This keeps the fast JS-to-JS path off the vector without losing GC
root collection, stack traces, or helpers that need to inspect the
active execution context chain.
2026-04-13 18:29:43 +02:00
Andreas Kling
2ca7dfa649 LibJS: Move bytecode interpreter state to VM
The bytecode interpreter only needed the running execution context,
but still threaded a separate Interpreter object through both the C++
and asm entry points. Move that state and the bytecode execution
helpers onto VM instead, and teach the asm generator and slow paths to
use VM directly.
2026-04-13 18:29:43 +02:00
Andreas Kling
3e18136a8c LibJS: Add a String.fromCharCode builtin opcode
Specialize only the fixed unary case in the bytecode generator and let
all other argument counts keep using the generic Call instruction. This
keeps the builtin bytecode simple while still covering the common fast
path.

The asm interpreter handles int32 inputs directly, applies the ToUint16
mask in-place, and reuses the VM's cached ASCII single-character
strings when the result is 7-bit representable. Non-ASCII single code
unit results stay on the dedicated builtin path via a small helper, and
the dedicated slow path still handles the generic cases.
2026-04-12 19:15:50 +02:00
Andreas Kling
7bc40bd54a LibJS: Add a charAt builtin bytecode fast path
Tag String.prototype.charAt as a builtin and emit a dedicated
bytecode instruction for non-computed calls.

The asm interpreter can then stay on the fast path when the
receiver is a primitive string with resident UTF-16 data and the
selected code unit is ASCII. In that case we can return the VM's
cached empty or single-character ASCII string directly.
2026-04-12 19:15:50 +02:00
Andreas Kling
d31750a43c LibJS: Add a charCodeAt builtin bytecode fast path
Teach builtin call specialization to recognize non-computed
member calls to charCodeAt() and emit a dedicated builtin opcode.
Mark String.prototype.charCodeAt with that builtin tag, then add
an asm interpreter fast path for primitive-string receivers whose
UTF-16 data is already resident.

The asm path handles both ASCII-backed and UTF-16-backed resident
strings, returns NaN for out-of-bounds Int32 indices, and falls
back to the generic builtin call path for everything else. This
keeps the optimistic case in asm while preserving the ordinary
method call semantics when charCodeAt has been replaced or when
string resolution would be required.
2026-04-12 19:15:50 +02:00
Andreas Kling
7ffe01cee3 LibJS: Split builtin call bytecode opcodes
Replace the generic CallBuiltin instruction with one opcode per
supported builtin call and make those instructions fixed-size by
arity. This removes the builtin dispatch sled in the asm
interpreter, gives each builtin a dedicated slow-path entry point,
and lets bytecode generation encode the callee shape directly.

Keep the existing handwritten asm fast paths for the Math builtins
that already benefit from them, while routing the other builtin
opcodes through their own C++ execute implementations. Build the
new opcode directly in Rust codegen, and keep the generic call
fallback when the original builtin function has been replaced.
2026-04-12 19:15:50 +02:00
Andreas Kling
879ac36e45 LibJS: Cache stable for-in iteration at bytecode sites
Cache the flattened enumerable key snapshot for each `for..in` site and
reuse a `PropertyNameIterator` when the receiver shape, dictionary
generation, indexed storage kind and length, prototype chain
validity, and magical-length state still match.

Handle packed indexed receivers as well as plain named-property
objects. Teach `ObjectPropertyIteratorNext` in `asmint.asm` to return
cached property values directly and to fall back to the slow iterator
logic when any guard fails.

Treat arrays' hidden non-enumerable `length` property as a visited
name for for-in shadowing, and include the receiver's magical-length
state in the cache key so arrays and plain objects do not share
snapshots.

Add `test-js` and `test-js-bytecode` coverage for mixed numeric and
named keys, packed receiver transitions, re-entry, iterator reuse, GC
retention, array length shadowing, and same-site cache reuse.
2026-04-10 15:12:53 +02:00
Andreas Kling
4c1e2222df LibJS: Fast-path safe writes into holey array holes
Teach the asm PutByValue path to materialize in-bounds holey array
elements directly when the receiver is a normal extensible Array with
the default prototype chain and no indexed interference. This avoids
bouncing through generic property setting while preserving the lazy
holey length model.

Keep the fast path narrow so inherited setters, inherited non-writable
properties, and non-extensible arrays still fall back to the generic
semantics. Add regression coverage for those cases alongside the large
holey array stress tests.
2026-04-09 20:06:42 +02:00
Andreas Kling
da1c943161 LibJS: Make holey array lengths lazy
Treat setting a large array length as a logical length change instead of
forcing dictionary indexed storage or materializing every hole up front.
This keeps dense fills on Array(length) on the holey indexed path and
only falls back to sparse storage when later writes actually create a
large realized gap.

The asm indexed get/put fast paths assumed holey arrays always had a
materialized backing store. Guard those paths with a capacity check so
lazy holey arrays fall back safely until an index has been realized.

Add regression coverage for very large holey arrays and for densely
filling a large holey array after pre-sizing it with Array(length).
2026-04-09 20:06:42 +02:00
Tim Ledbetter
275e141823 LibJS: Rename Value::as_array() to Value::as_array_exotic_object()`
This better describes what the method returns and avoids the possible
confusion caused by the mismatch in behavior between
`Value::is_array()` and `Value::as_array()`.
2026-03-29 13:45:38 +02:00
InvalidUsernameException
cf6c9d69f4 LibJS: Initialize constants in execution context right away
In b2d9fd3352, the root cause of the crash
was somewhat misdiagnosed, particularly around what place in code an
allocation could occur while constants data was uninitialized.

But more importantly, we can do better than the solution in that commit.
Instead of initializing constants with default values and then
overwriting them afterwards, simply initialize them with their actual
values directly when constructing the execution context.

This effectivly reverts commit b2d9fd3352.
2026-03-29 13:44:06 +02:00
InvalidUsernameException
7002c47ce1 LibJS+LibWeb: Pass constants into execution context constructor
The additional data being passed will be used in an upcoming commit.
Allows splitting the churn of modified function signatures from the
logically meaningful code change.

No behavior change.
2026-03-29 13:44:06 +02:00
Andreas Kling
e243e146de LibJS+LibRegex: Switch RegExp over to the Rust engine
Switch LibJS `RegExp` over to the Rust-backed `ECMAScriptRegex` APIs.

Route `new RegExp()`, regex literals, and the RegExp builtins through
the new compile and exec APIs, and stop re-validating patterns with the
deleted C++ parser on the way in. Preserve the observable error
behavior by carrying structured compile errors and backtracking-limit
failures across the FFI boundary. Cache compiled regex state and named
capture metadata on `RegExpObject` in the new representation.

Use the new API surface to simplify and speed up the builtin paths too:
share `exec_internal`, cache compiled regex pointers, keep the legacy
RegExp statics lazy, run global replace through batch `find_all`, and
optimize replace, test, split, and String helper paths. Add regression
tests for those JavaScript-visible paths.
2026-03-27 17:32:19 +01:00
Andreas Kling
34d954e2d7 LibRegex: Add ECMAScriptRegex and migrate callers
Add `ECMAScriptRegex`, LibRegex's C++ facade for ECMAScript regexes.

The facade owns compilation, execution, captures, named groups, and
error translation for the Rust backend, which lets callers stop
depending on the legacy parser and matcher types directly. Use it in the
remaining non-LibJS callers: URLPattern, HTML input pattern handling,
and the places in LibHTTP that only needed token validation.

Where a full regex engine was unnecessary, replace those call sites with
direct character checks. Also update focused LibURL, LibHTTP, and WPT
coverage for the migrated callers and corrected surrogate handling.
2026-03-27 17:32:19 +01:00
Andreas Kling
72fdf10248 LibJS: Don't cache dictionary shapes in NewObject premade shape cache
Dictionary shapes are mutable (properties added/removed in-place via
add_property_without_transition), so sharing them between objects via
the NewObject premade shape cache is unsafe.

When a large object literal (>64 properties) is created repeatedly in
a loop, the first execution transitions to a dictionary shape, which
CacheObjectShape then caches. Subsequent iterations create new objects
all pointing to the same dictionary shape. If any of these objects adds
a new property, it mutates the shared shape in-place, increasing its
property_count, but only grows its own named property storage. Other
objects sharing the shape are left with undersized storage, leading to
a heap-buffer-overflow when the GC visits their edges.

Fix this by not caching dictionary shapes. This means object literals
with >64 properties won't get the premade-shape fast path, but such
literals are uncommon.
2026-03-22 11:10:01 -05:00
Ollie Hensman-Crook
df8ead1f12 LibJS: Treat concise methods as non-constructors 2026-03-20 15:58:05 -05:00
Johan Dahlin
1179e40d3f LibJS: Eliminate GeneratorResult GC cell allocation on yield/await
Store yield_continuation and yield_is_await directly in
ExecutionContext instead of allocating a GeneratorResult GC cell.
This removes a heap allocation per yield/await and fixes a latent
bug where continuation addresses stored as doubles could lose
precision.
2026-03-20 15:57:23 -05:00