1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 01:57:45 +00:00

LibJS: Define SetTypedArrayFrom{TypedArray,ArrayLike} AOs out of line

%TypedArray%.prototype.set was a bit hard to read / compare to the spec
with these AOs defined inside it.
This commit is contained in:
Timothy Flynn 2022-04-15 09:09:37 -04:00 committed by Linus Groh
parent 1c80b377b2
commit c076b363ce

View file

@ -604,44 +604,23 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_string_tag_getter)
return js_string(vm, static_cast<TypedArrayBase&>(this_object).element_name());
}
// 23.2.3.24 %TypedArray%.prototype.set ( source [ , offset ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
{
auto source = vm.argument(0);
// 1. Let target be the this value.
// 2. Perform ? RequireInternalSlot(target, [[TypedArrayName]]).
auto* typed_array = TRY(typed_array_from_this(global_object));
// 3. Assert: target has a [[ViewedArrayBuffer]] internal slot.
// 4. Let targetOffset be ? ToIntegerOrInfinity(offset).
auto target_offset = TRY(vm.argument(1).to_integer_or_infinity(global_object));
// 5. If targetOffset < 0, throw a RangeError exception.
if (target_offset < 0)
return vm.throw_completion<RangeError>(global_object, "Invalid target offset");
// 6. If source is an Object that has a [[TypedArrayName]] internal slot, then
if (source.is_object() && is<TypedArrayBase>(source.as_object())) {
// a. Perform ? SetTypedArrayFromTypedArray(target, targetOffset, source).
// 23.2.3.23.1 SetTypedArrayFromTypedArray ( target, targetOffset, source ), https://tc39.es/ecma262/#sec-settypedarrayfromtypedarray
auto& source_typed_array = static_cast<TypedArrayBase&>(source.as_object());
static ThrowCompletionOr<void> set_typed_array_from_typed_array(GlobalObject& global_object, TypedArrayBase& target, double target_offset, TypedArrayBase& source)
{
auto& vm = global_object.vm();
// 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
auto* target_buffer = typed_array->viewed_array_buffer();
auto* target_buffer = target.viewed_array_buffer();
// 2. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
if (target_buffer->is_detached())
return vm.throw_completion<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
// 3. Let targetLength be target.[[ArrayLength]].
auto target_length = typed_array->array_length();
auto target_length = target.array_length();
// 4. Let srcBuffer be source.[[ViewedArrayBuffer]].
auto* source_buffer = source_typed_array.viewed_array_buffer();
auto* source_buffer = source.viewed_array_buffer();
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
if (source_buffer->is_detached())
@ -650,21 +629,21 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
// 6. Let targetName be the String value of target.[[TypedArrayName]].
// 7. Let targetType be the Element Type value in Table 69 for targetName.
// 8. Let targetElementSize be the Element Size value specified in Table 69 for targetName.
auto target_element_size = typed_array->element_size();
auto target_element_size = target.element_size();
// 9. Let targetByteOffset be target.[[ByteOffset]].
auto target_byte_offset = typed_array->byte_offset();
auto target_byte_offset = target.byte_offset();
// 10. Let srcName be the String value of source.[[TypedArrayName]].
// 11. Let srcType be the Element Type value in Table 69 for srcName.
// 12. Let srcElementSize be the Element Size value specified in Table 69 for srcName.
auto source_element_size = source_typed_array.element_size();
auto source_element_size = source.element_size();
// 13. Let srcLength be source.[[ArrayLength]].
auto source_length = source_typed_array.array_length();
auto source_length = source.array_length();
// 14. Let srcByteOffset be source.[[ByteOffset]].
auto source_byte_offset = source_typed_array.byte_offset();
auto source_byte_offset = source.byte_offset();
// 15. If targetOffset is +∞, throw a RangeError exception.
if (isinf(target_offset))
@ -677,7 +656,7 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
return vm.throw_completion<RangeError>(global_object, "Overflow or out of bounds in target length");
// 17. If target.[[ContentType]] ≠ source.[[ContentType]], throw a TypeError exception.
if (typed_array->content_type() != source_typed_array.content_type())
if (target.content_type() != source.content_type())
return vm.throw_completion<TypeError>(global_object, "Copy between arrays of different content types is prohibited");
// FIXME: 18. If both IsSharedArrayBuffer(srcBuffer) and IsSharedArrayBuffer(targetBuffer) are true, then
@ -691,7 +670,7 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
// 20. If same is true, then
if (same) {
// a. Let srcByteLength be source.[[ByteLength]].
auto source_byte_length = source_typed_array.byte_length();
auto source_byte_length = source.byte_length();
// b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcByteLength, %ArrayBuffer%).
source_buffer = TRY(clone_array_buffer(global_object, *source_buffer, source_byte_offset, source_byte_length, *global_object.array_buffer_constructor()));
@ -721,7 +700,7 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
auto limit = checked_limit.value();
// 24. If srcType is the same as targetType, then
if (source_typed_array.element_name() == typed_array->element_name()) {
if (source.element_name() == target.element_name()) {
// a. NOTE: If srcType and targetType are the same, the transfer must be performed in a manner that preserves the bit-level encoding of the source data.
// b. Repeat, while targetByteIndex < limit,
// i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, true, Unordered).
@ -733,31 +712,33 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
// a. Repeat, while targetByteIndex < limit,
while (target_byte_index < limit) {
// i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType, true, Unordered).
auto value = source_typed_array.get_value_from_buffer(source_byte_index, ArrayBuffer::Unordered);
auto value = source.get_value_from_buffer(source_byte_index, ArrayBuffer::Unordered);
// ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered).
typed_array->set_value_in_buffer(target_byte_index, value, ArrayBuffer::Unordered);
target.set_value_in_buffer(target_byte_index, value, ArrayBuffer::Unordered);
// iii. Set srcByteIndex to srcByteIndex + srcElementSize.
source_byte_index += source_element_size;
// iv. Set targetByteIndex to targetByteIndex + targetElementSize.
target_byte_index += typed_array->element_size();
target_byte_index += target.element_size();
}
}
return {};
}
// 7. Else,
else {
// a. Perform ? SetTypedArrayFromArrayLike(target, targetOffset, source).
// 23.2.3.23.2 SetTypedArrayFromArrayLike ( target, targetOffset, source ), https://tc39.es/ecma262/#sec-settypedarrayfromarraylike
static ThrowCompletionOr<void> set_typed_array_from_array_like(GlobalObject& global_object, TypedArrayBase& target, double target_offset, Value source)
{
auto& vm = global_object.vm();
// 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
auto* target_buffer = typed_array->viewed_array_buffer();
auto* target_buffer = target.viewed_array_buffer();
// 2. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
if (target_buffer->is_detached())
return vm.throw_completion<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
// 3. Let targetLength be target.[[ArrayLength]].
auto target_length = typed_array->array_length();
auto target_length = target.array_length();
// 4. Let src be ? ToObject(source).
auto* src = TRY(source.to_object(global_object));
@ -790,8 +771,8 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
// d. Perform ? IntegerIndexedElementSet(target, targetIndex, value).
// FIXME: This is very awkward.
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
if (is<ClassName>(typed_array)) \
TRY(integer_indexed_element_set<Type>(*typed_array, target_index, value));
if (is<ClassName>(target)) \
TRY(integer_indexed_element_set<Type>(target, target_index, value));
JS_ENUMERATE_TYPED_ARRAYS
#undef __JS_ENUMERATE
@ -800,6 +781,38 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
}
// 10. Return unused.
return {};
}
// 23.2.3.24 %TypedArray%.prototype.set ( source [ , offset ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
{
auto source = vm.argument(0);
// 1. Let target be the this value.
// 2. Perform ? RequireInternalSlot(target, [[TypedArrayName]]).
auto* typed_array = TRY(typed_array_from_this(global_object));
// 3. Assert: target has a [[ViewedArrayBuffer]] internal slot.
// 4. Let targetOffset be ? ToIntegerOrInfinity(offset).
auto target_offset = TRY(vm.argument(1).to_integer_or_infinity(global_object));
// 5. If targetOffset < 0, throw a RangeError exception.
if (target_offset < 0)
return vm.throw_completion<RangeError>(global_object, "Invalid target offset");
// 6. If source is an Object that has a [[TypedArrayName]] internal slot, then
if (source.is_object() && is<TypedArrayBase>(source.as_object())) {
auto& source_typed_array = static_cast<TypedArrayBase&>(source.as_object());
// a. Perform ? SetTypedArrayFromTypedArray(target, targetOffset, source).
TRY(set_typed_array_from_typed_array(global_object, *typed_array, target_offset, source_typed_array));
}
// 7. Else,
else {
// a. Perform ? SetTypedArrayFromArrayLike(target, targetOffset, source).
TRY(set_typed_array_from_array_like(global_object, *typed_array, target_offset, source));
}
// 8. Return undefined.