mirror of
https://github.com/RGBCube/serenity
synced 2025-05-19 00:25:07 +00:00
LibJS: Add specialized fast paths for 8/16/32-bit integer TypedArrays
By checking a few conditions up front, we can do a very specialized direct access into the underlying byte storage for 8/16/32-bit typed arrays. This relies on the fact that typed arrays are guaranteed to be type-appropriately aligned within the underlying array buffer.
This commit is contained in:
parent
4cce181ece
commit
cb46a7fd65
1 changed files with 91 additions and 8 deletions
|
@ -20,6 +20,42 @@
|
|||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
// NOTE: This function assumes that the index is valid within the TypedArray,
|
||||
// and that the TypedArray is not detached.
|
||||
template<typename T>
|
||||
inline Value fast_integer_indexed_element_get(TypedArrayBase& typed_array, u32 index)
|
||||
{
|
||||
Checked<u32> offset_into_array_buffer = index;
|
||||
offset_into_array_buffer *= sizeof(T);
|
||||
offset_into_array_buffer += typed_array.byte_offset();
|
||||
|
||||
if (offset_into_array_buffer.has_overflow()) [[unlikely]] {
|
||||
return js_undefined();
|
||||
}
|
||||
|
||||
auto const& array_buffer = *typed_array.viewed_array_buffer();
|
||||
auto const* slot = reinterpret_cast<T const*>(array_buffer.buffer().offset_pointer(offset_into_array_buffer.value()));
|
||||
return Value { *slot };
|
||||
}
|
||||
|
||||
// NOTE: This function assumes that the index is valid within the TypedArray,
|
||||
// and that the TypedArray is not detached.
|
||||
template<typename T>
|
||||
inline void fast_integer_indexed_element_set(TypedArrayBase& typed_array, u32 index, T value)
|
||||
{
|
||||
Checked<u32> offset_into_array_buffer = index;
|
||||
offset_into_array_buffer *= sizeof(T);
|
||||
offset_into_array_buffer += typed_array.byte_offset();
|
||||
|
||||
if (offset_into_array_buffer.has_overflow()) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& array_buffer = *typed_array.viewed_array_buffer();
|
||||
auto* slot = reinterpret_cast<T*>(array_buffer.buffer().offset_pointer(offset_into_array_buffer.value()));
|
||||
*slot = value;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<Object>> base_object_for_get(VM& vm, Value base_value)
|
||||
{
|
||||
if (base_value.is_object())
|
||||
|
@ -68,23 +104,43 @@ ThrowCompletionOr<Value> get_by_id(VM& vm, DeprecatedFlyString const& property,
|
|||
|
||||
ThrowCompletionOr<Value> get_by_value(VM& vm, Value base_value, Value property_key_value)
|
||||
{
|
||||
auto object = TRY(base_object_for_get(vm, base_value));
|
||||
|
||||
// OPTIMIZATION: Fast path for simple Int32 indexes in array-like objects.
|
||||
if (property_key_value.is_int32() && property_key_value.as_i32() >= 0) {
|
||||
if (base_value.is_object() && property_key_value.is_int32() && property_key_value.as_i32() >= 0) {
|
||||
auto& object = base_value.as_object();
|
||||
auto index = static_cast<u32>(property_key_value.as_i32());
|
||||
|
||||
// For "non-typed arrays":
|
||||
if (!object->may_interfere_with_indexed_property_access()
|
||||
&& object->indexed_properties().has_index(index)) {
|
||||
auto value = object->indexed_properties().get(index)->value;
|
||||
if (!object.may_interfere_with_indexed_property_access()
|
||||
&& object.indexed_properties().has_index(index)) {
|
||||
auto value = object.indexed_properties().get(index)->value;
|
||||
if (!value.is_accessor())
|
||||
return value;
|
||||
}
|
||||
|
||||
// For typed arrays:
|
||||
if (object->is_typed_array()) {
|
||||
auto& typed_array = static_cast<TypedArrayBase&>(*object);
|
||||
if (object.is_typed_array()) {
|
||||
auto& typed_array = static_cast<TypedArrayBase&>(object);
|
||||
|
||||
if (!typed_array.viewed_array_buffer()->is_detached() && index < typed_array.array_length()) {
|
||||
switch (typed_array.kind()) {
|
||||
case TypedArrayBase::Kind::Uint8Array:
|
||||
return fast_integer_indexed_element_get<u8>(typed_array, index);
|
||||
case TypedArrayBase::Kind::Uint16Array:
|
||||
return fast_integer_indexed_element_get<u16>(typed_array, index);
|
||||
case TypedArrayBase::Kind::Uint32Array:
|
||||
return fast_integer_indexed_element_get<u32>(typed_array, index);
|
||||
case TypedArrayBase::Kind::Int8Array:
|
||||
return fast_integer_indexed_element_get<i8>(typed_array, index);
|
||||
case TypedArrayBase::Kind::Int16Array:
|
||||
return fast_integer_indexed_element_get<i16>(typed_array, index);
|
||||
case TypedArrayBase::Kind::Int32Array:
|
||||
return fast_integer_indexed_element_get<i32>(typed_array, index);
|
||||
default:
|
||||
// FIXME: Support more TypedArray kinds.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto canonical_index = CanonicalIndex { CanonicalIndex::Type::Index, index };
|
||||
switch (typed_array.kind()) {
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
|
||||
|
@ -96,6 +152,8 @@ ThrowCompletionOr<Value> get_by_value(VM& vm, Value base_value, Value property_k
|
|||
}
|
||||
}
|
||||
|
||||
auto object = TRY(base_object_for_get(vm, base_value));
|
||||
|
||||
auto property_key = TRY(property_key_value.to_property_key(vm));
|
||||
|
||||
if (base_value.is_string()) {
|
||||
|
@ -345,6 +403,31 @@ ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Value property_key_valu
|
|||
// For typed arrays:
|
||||
if (object.is_typed_array()) {
|
||||
auto& typed_array = static_cast<TypedArrayBase&>(object);
|
||||
if (!typed_array.viewed_array_buffer()->is_detached() && index < typed_array.array_length() && value.is_int32()) {
|
||||
switch (typed_array.kind()) {
|
||||
case TypedArrayBase::Kind::Uint8Array:
|
||||
fast_integer_indexed_element_set<u8>(typed_array, index, static_cast<u8>(value.as_i32()));
|
||||
return {};
|
||||
case TypedArrayBase::Kind::Uint16Array:
|
||||
fast_integer_indexed_element_set<u16>(typed_array, index, static_cast<u16>(value.as_i32()));
|
||||
return {};
|
||||
case TypedArrayBase::Kind::Uint32Array:
|
||||
fast_integer_indexed_element_set<u32>(typed_array, index, static_cast<u32>(value.as_i32()));
|
||||
return {};
|
||||
case TypedArrayBase::Kind::Int8Array:
|
||||
fast_integer_indexed_element_set<i8>(typed_array, index, static_cast<i8>(value.as_i32()));
|
||||
return {};
|
||||
case TypedArrayBase::Kind::Int16Array:
|
||||
fast_integer_indexed_element_set<i16>(typed_array, index, static_cast<i16>(value.as_i32()));
|
||||
return {};
|
||||
case TypedArrayBase::Kind::Int32Array:
|
||||
fast_integer_indexed_element_set<i32>(typed_array, index, value.as_i32());
|
||||
return {};
|
||||
default:
|
||||
// FIXME: Support more TypedArray kinds.
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto canonical_index = CanonicalIndex { CanonicalIndex::Type::Index, index };
|
||||
switch (typed_array.kind()) {
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue