mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 18:57:35 +00:00
LibJS: Optimize IsValidIntegerIndex for TAs with non-resizable buffers
If we know the TA does not have a resizable ArrayBuffer, we can avoid most of the heavy lifting that IsValidIntegerIndex performs. On https://cyxx.github.io/another_js, this reduces the runtime of IsValidIntegerIndex from 7.1% to 3.7%.
This commit is contained in:
parent
b821f7b283
commit
08ad2d774e
2 changed files with 31 additions and 12 deletions
|
@ -700,21 +700,12 @@ bool is_typed_array_out_of_bounds_for_known_attached_array(TypedArrayWithBufferW
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10.4.5.14 IsValidIntegerIndex ( O, index ), https://tc39.es/ecma262/#sec-isvalidintegerindex
|
// 10.4.5.14 IsValidIntegerIndex ( O, index ), https://tc39.es/ecma262/#sec-isvalidintegerindex
|
||||||
bool is_valid_integer_index(TypedArrayBase const& typed_array, CanonicalIndex property_index)
|
bool is_valid_integer_index_slow_case(TypedArrayBase const& typed_array, CanonicalIndex property_index)
|
||||||
{
|
{
|
||||||
// 1. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
|
|
||||||
if (typed_array.viewed_array_buffer()->is_detached())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// 2. If IsIntegralNumber(index) is false, return false.
|
|
||||||
// 3. If index is -0𝔽, return false.
|
|
||||||
if (!property_index.is_index())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, unordered).
|
// 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, unordered).
|
||||||
auto typed_array_record = make_typed_array_with_buffer_witness_record_for_known_attached_array(typed_array, ArrayBuffer::Unordered);
|
auto typed_array_record = make_typed_array_with_buffer_witness_record_for_known_attached_array(typed_array, ArrayBuffer::Unordered);
|
||||||
|
|
||||||
// NOTE: Bounds checking is not a synchronizing operation when O's backing buffer is a growable SharedArrayBuffer.
|
// 5. NOTE: Bounds checking is not a synchronizing operation when O's backing buffer is a growable SharedArrayBuffer.
|
||||||
|
|
||||||
// 6. If IsTypedArrayOutOfBounds(taRecord) is true, return false.
|
// 6. If IsTypedArrayOutOfBounds(taRecord) is true, return false.
|
||||||
if (is_typed_array_out_of_bounds_for_known_attached_array(typed_array_record))
|
if (is_typed_array_out_of_bounds_for_known_attached_array(typed_array_record))
|
||||||
|
|
|
@ -96,7 +96,6 @@ struct TypedArrayWithBufferWitness {
|
||||||
|
|
||||||
u32 typed_array_byte_length(TypedArrayWithBufferWitness const&);
|
u32 typed_array_byte_length(TypedArrayWithBufferWitness const&);
|
||||||
bool is_typed_array_out_of_bounds(TypedArrayWithBufferWitness const&);
|
bool is_typed_array_out_of_bounds(TypedArrayWithBufferWitness const&);
|
||||||
bool is_valid_integer_index(TypedArrayBase const&, CanonicalIndex);
|
|
||||||
|
|
||||||
// Fast-path version of MakeTypedArrayWithBufferWitnessRecord when you already know the TA is not detached.
|
// Fast-path version of MakeTypedArrayWithBufferWitnessRecord when you already know the TA is not detached.
|
||||||
TypedArrayWithBufferWitness make_typed_array_with_buffer_witness_record_for_known_attached_array(TypedArrayBase const&, ArrayBuffer::Order);
|
TypedArrayWithBufferWitness make_typed_array_with_buffer_witness_record_for_known_attached_array(TypedArrayBase const&, ArrayBuffer::Order);
|
||||||
|
@ -135,6 +134,35 @@ inline bool is_typed_array_out_of_bounds(TypedArrayWithBufferWitness const& type
|
||||||
return is_typed_array_out_of_bounds_for_known_attached_array(typed_array_record);
|
return is_typed_array_out_of_bounds_for_known_attached_array(typed_array_record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_valid_integer_index_slow_case(TypedArrayBase const&, CanonicalIndex property_index);
|
||||||
|
|
||||||
|
// 10.4.5.14 IsValidIntegerIndex ( O, index ), https://tc39.es/ecma262/#sec-isvalidintegerindex
|
||||||
|
inline bool is_valid_integer_index(TypedArrayBase const& typed_array, CanonicalIndex property_index)
|
||||||
|
{
|
||||||
|
// 1. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
|
||||||
|
if (typed_array.viewed_array_buffer()->is_detached())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 2. If IsIntegralNumber(index) is false, return false.
|
||||||
|
// 3. If index is -0𝔽, return false.
|
||||||
|
if (!property_index.is_index())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// OPTIMIZATION: For TypedArrays with non-resizable ArrayBuffers, we can avoid most of the work performed by
|
||||||
|
// IsValidIntegerIndex. We just need to check whether the array itself is out-of-bounds and if
|
||||||
|
// the provided index is within the array bounds.
|
||||||
|
if (auto const& array_length = typed_array.array_length(); !array_length.is_auto()) {
|
||||||
|
auto byte_length = array_buffer_byte_length(*typed_array.viewed_array_buffer(), ArrayBuffer::Unordered);
|
||||||
|
auto byte_offset_end = typed_array.byte_offset() + array_length.length() * typed_array.element_size();
|
||||||
|
|
||||||
|
return typed_array.byte_offset() <= byte_length
|
||||||
|
&& byte_offset_end <= byte_length
|
||||||
|
&& property_index.as_index() < array_length.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_valid_integer_index_slow_case(typed_array, property_index);
|
||||||
|
}
|
||||||
|
|
||||||
// 10.4.5.15 TypedArrayGetElement ( O, index ), https://tc39.es/ecma262/#sec-typedarraygetelement
|
// 10.4.5.15 TypedArrayGetElement ( O, index ), https://tc39.es/ecma262/#sec-typedarraygetelement
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline ThrowCompletionOr<Value> typed_array_get_element(TypedArrayBase const& typed_array, CanonicalIndex property_index)
|
inline ThrowCompletionOr<Value> typed_array_get_element(TypedArrayBase const& typed_array, CanonicalIndex property_index)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue