mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-05 06:32:30 +02:00
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.
This commit is contained in:
committed by
Andreas Kling
parent
036819da22
commit
4c1e2222df
Notes:
github-actions[bot]
2026-04-09 18:07:43 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/4c1e2222dfd Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8847
@@ -9,6 +9,7 @@
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <LibJS/Bytecode/PropertyAccess.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/DeclarativeEnvironment.h>
|
||||
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
||||
#include <LibJS/Runtime/ModuleEnvironment.h>
|
||||
@@ -256,6 +257,7 @@ i64 asm_slow_path_unary_minus(Interpreter*, u32 pc);
|
||||
i64 asm_slow_path_postfix_decrement(Interpreter*, u32 pc);
|
||||
i64 asm_slow_path_to_int32(Interpreter*, u32 pc);
|
||||
i64 asm_slow_path_put_by_value(Interpreter*, u32 pc);
|
||||
i64 asm_try_put_by_value_holey_array(Interpreter*, u32 pc);
|
||||
u64 asm_helper_to_boolean(u64 encoded_value);
|
||||
u64 asm_helper_math_exp(u64 encoded_value);
|
||||
i64 asm_try_inline_call(Interpreter*, u32 pc);
|
||||
@@ -794,6 +796,39 @@ i64 asm_slow_path_put_by_value(Interpreter* interp, u32 pc)
|
||||
return slow_path_throwing<Op::PutByValue>(*interp, pc);
|
||||
}
|
||||
|
||||
i64 asm_try_put_by_value_holey_array(Interpreter* interp, u32 pc)
|
||||
{
|
||||
auto* bytecode = interp->current_executable().bytecode.data();
|
||||
auto& insn = *reinterpret_cast<Op::PutByValue const*>(&bytecode[pc]);
|
||||
|
||||
auto base = interp->get(insn.base());
|
||||
if (!base.is_object()) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
auto property = interp->get(insn.property());
|
||||
if (!property.is_non_negative_int32()) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
auto& object = base.as_object();
|
||||
if (!is<JS::Array>(object)) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
auto& array = static_cast<JS::Array&>(object);
|
||||
if (array.is_proxy_target()
|
||||
|| !array.default_prototype_chain_intact()
|
||||
|| !array.extensible()
|
||||
|| array.may_interfere_with_indexed_property_access()
|
||||
|| array.indexed_storage_kind() != IndexedStorageKind::Holey) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
auto index = static_cast<u32>(property.as_i32());
|
||||
if (index >= array.indexed_array_like_size()) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
array.indexed_put(index, interp->get(insn.src()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to inline a JS-to-JS call. Returns 0 on success (callee frame pushed),
|
||||
// 1 on failure (caller should fall through to slow path).
|
||||
i64 asm_try_inline_call(Interpreter* interp, u32 pc)
|
||||
|
||||
@@ -1380,17 +1380,21 @@ handler PutByValue
|
||||
load32 t5, [t3, OBJECT_INDEXED_ARRAY_LIKE_SIZE]
|
||||
branch_ge_unsigned t4, t5, .slow
|
||||
load64 t5, [t3, OBJECT_INDEXED_ELEMENTS]
|
||||
branch_zero t5, .slow
|
||||
branch_zero t5, .try_holey_array_slow
|
||||
mov t0, t5
|
||||
sub t0, 8
|
||||
load32 t0, [t0, 0]
|
||||
branch_ge_unsigned t4, t0, .slow
|
||||
branch_ge_unsigned t4, t0, .try_holey_array_slow
|
||||
load64 t1, [t5, t4, 8]
|
||||
mov t0, EMPTY_TAG_SHIFTED
|
||||
branch_eq t1, t0, .slow
|
||||
branch_eq t1, t0, .try_holey_array_slow
|
||||
load_operand t1, m_src
|
||||
store64 [t5, t4, 8], t1
|
||||
dispatch_next
|
||||
.try_holey_array_slow:
|
||||
call_interp asm_try_put_by_value_holey_array
|
||||
branch_nonzero t0, .slow
|
||||
dispatch_next
|
||||
.try_typed_array:
|
||||
# t3 = Object*, t4 = index (u32, non-negative)
|
||||
# Load cached data pointer (pre-computed: buffer.data() + byte_offset)
|
||||
|
||||
Reference in New Issue
Block a user