diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 7ce7354de0e..7ace8e57669 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -469,6 +469,34 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::every) return true; } +// NOTE: This function assumes that the index is valid within the TypedArray, +// and that the TypedArray is not detached. +template +inline void fast_typed_array_fill(TypedArrayBase& typed_array, u32 begin, u32 end, T value) +{ + Checked computed_begin = begin; + computed_begin *= sizeof(T); + computed_begin += typed_array.byte_offset(); + + Checked computed_end = end; + computed_end *= sizeof(T); + computed_end += typed_array.byte_offset(); + + if (computed_begin.has_overflow() || computed_end.has_overflow()) [[unlikely]] { + return; + } + + if (computed_begin.value() >= typed_array.viewed_array_buffer()->byte_length() + || computed_end.value() > typed_array.viewed_array_buffer()->byte_length()) [[unlikely]] { + return; + } + + auto& array_buffer = *typed_array.viewed_array_buffer(); + auto* slot = reinterpret_cast(array_buffer.buffer().offset_pointer(computed_begin.value())); + for (auto i = begin; i < end; ++i) + *(slot++) = value; +} + // 23.2.3.9 %TypedArray%.prototype.fill ( value [ , start [ , end ] ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::fill) { @@ -537,13 +565,48 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::fill) // 17. Set final to min(final, len). final = min(final, length); + if (value.is_int32()) { + switch (typed_array->kind()) { + case TypedArrayBase::Kind::Uint8Array: + fast_typed_array_fill(*typed_array, k, final, static_cast(value.as_i32())); + return typed_array; + case TypedArrayBase::Kind::Uint16Array: + fast_typed_array_fill(*typed_array, k, final, static_cast(value.as_i32())); + return typed_array; + case TypedArrayBase::Kind::Uint32Array: + fast_typed_array_fill(*typed_array, k, final, static_cast(value.as_i32())); + return typed_array; + case TypedArrayBase::Kind::Int8Array: + fast_typed_array_fill(*typed_array, k, final, static_cast(value.as_i32())); + return typed_array; + case TypedArrayBase::Kind::Int16Array: + fast_typed_array_fill(*typed_array, k, final, static_cast(value.as_i32())); + return typed_array; + case TypedArrayBase::Kind::Int32Array: + fast_typed_array_fill(*typed_array, k, final, value.as_i32()); + return typed_array; + case TypedArrayBase::Kind::Uint8ClampedArray: + fast_typed_array_fill(*typed_array, k, final, clamp(value.as_i32(), 0, 255)); + return typed_array; + default: + // FIXME: Support more TypedArray kinds. + break; + } + } + // 18. Repeat, while k < final, while (k < final) { // a. Let Pk be ! ToString(𝔽(k)). - PropertyKey property_key { k }; - // b. Perform ! Set(O, Pk, value, true). - MUST(typed_array->set(property_key, value, Object::ShouldThrowExceptions::Yes)); + CanonicalIndex canonical_index { CanonicalIndex::Type::Index, k }; + switch (typed_array->kind()) { +#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \ + case TypedArrayBase::Kind::ClassName: \ + (void)typed_array_set_element(*typed_array, canonical_index, value); \ + break; + JS_ENUMERATE_TYPED_ARRAYS +#undef __JS_ENUMERATE + } // c. Set k to k + 1. ++k;