LibJS: Add common fast path for PutByValue into TypedArray

When putting to a numeric indexed property, we can skip a lot of the
ceremony and go directly to IntegerIndexedElementSet. :^)
This commit is contained in:
Andreas Kling 2023-11-25 18:41:38 +01:00
parent 743a9e9ebf
commit 51ac0d8821
Notes: sideshowbarker 2024-07-16 23:59:28 +09:00
2 changed files with 29 additions and 1 deletions

View file

@ -15,6 +15,8 @@
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/ObjectEnvironment.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Bytecode {
@ -306,10 +308,13 @@ Value new_function(VM& vm, FunctionExpression const& function_node, Optional<Ide
ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Value property_key_value, Value value, Op::PropertyKind kind)
{
// OPTIMIZATION: Fast path for simple Int32 indexes in array-like objects.
if (base.is_object() && property_key_value.is_int32() && property_key_value.as_i32() >= 0) {
if ((kind == Op::PropertyKind::KeyValue || kind == Op::PropertyKind::DirectKeyValue)
&& base.is_object() && property_key_value.is_int32() && property_key_value.as_i32() >= 0) {
auto& object = base.as_object();
auto* storage = object.indexed_properties().storage();
auto index = static_cast<u32>(property_key_value.as_i32());
// For "non-typed arrays":
if (storage
&& storage->is_simple_storage()
&& !object.may_interfere_with_indexed_property_access()
@ -320,6 +325,20 @@ ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Value property_key_valu
return {};
}
}
// For typed arrays:
if (object.is_typed_array()) {
auto& typed_array = static_cast<TypedArrayBase&>(object);
auto canonical_index = CanonicalIndex { CanonicalIndex::Type::Index, index };
switch (typed_array.kind()) {
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
case TypedArrayBase::Kind::ClassName: \
return integer_indexed_element_set<Type>(typed_array, canonical_index, value);
JS_ENUMERATE_TYPED_ARRAYS
#undef __JS_ENUMERATE
}
return {};
}
}
auto property_key = kind != Op::PropertyKind::Spread ? TRY(property_key_value.to_property_key(vm)) : PropertyKey {};

View file

@ -32,6 +32,13 @@ public:
Number,
};
enum class Kind {
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
ClassName,
JS_ENUMERATE_TYPED_ARRAYS
#undef __JS_ENUMERATE
};
using IntrinsicConstructor = NonnullGCPtr<TypedArrayConstructor> (Intrinsics::*)();
u32 array_length() const { return m_array_length; }
@ -48,6 +55,7 @@ public:
virtual size_t element_size() const = 0;
virtual DeprecatedFlyString const& element_name() const = 0;
virtual Kind kind() const = 0;
// 25.1.2.6 IsUnclampedIntegerElementType ( type ), https://tc39.es/ecma262/#sec-isunclampedintegerelementtype
virtual bool is_unclamped_integer_element_type() const = 0;
@ -472,6 +480,7 @@ ThrowCompletionOr<double> compare_typed_array_elements(VM&, Value x, Value y, Fu
static ThrowCompletionOr<NonnullGCPtr<ClassName>> create(Realm&, u32 length); \
static NonnullGCPtr<ClassName> create(Realm&, u32 length, ArrayBuffer& buffer); \
virtual DeprecatedFlyString const& element_name() const override; \
virtual Kind kind() const override { return Kind::ClassName; } \
\
protected: \
ClassName(Object& prototype, u32 length, ArrayBuffer& array_buffer); \