From 7aa4c22f6b0dde61457c4e4112428b777401213b Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Sun, 13 Feb 2022 02:32:37 +0000 Subject: [PATCH] LibJS: Add spec comments to ArrayBuffer.prototype.slice --- .../LibJS/Runtime/ArrayBufferPrototype.cpp | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp index 1ba8237ec8..1b52da708a 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Linus Groh + * Copyright (c) 2021-2022, Jamie Mansfield * Copyright (c) 2021, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause @@ -37,51 +38,89 @@ ArrayBufferPrototype::~ArrayBufferPrototype() // 25.1.5.3 ArrayBuffer.prototype.slice ( start, end ), https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice) { + // 1. Let O be the this value. + // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]). auto* array_buffer_object = TRY(typed_this_value(global_object)); + + // 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception. // FIXME: Check for shared buffer + + // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. if (array_buffer_object->is_detached()) return vm.throw_completion(global_object, ErrorType::DetachedArrayBuffer); + // 5. Let len be O.[[ArrayBufferByteLength]]. auto length = array_buffer_object->byte_length(); + // 6. Let relativeStart be ? ToIntegerOrInfinity(start). auto relative_start = TRY(vm.argument(0).to_integer_or_infinity(global_object)); double first; - if (relative_start < 0) + // 7. If relativeStart is -∞, let first be 0. + if (Value(relative_start).is_negative_infinity()) + first = 0; + // 8. Else if relativeStart < 0, let first be max(len + relativeStart, 0). + else if (relative_start < 0) first = max(length + relative_start, 0.0); + // 9. Else, let first be min(relativeStart, len). else first = min(relative_start, (double)length); + // 10. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end). auto relative_end = vm.argument(1).is_undefined() ? length : TRY(vm.argument(1).to_integer_or_infinity(global_object)); double final; - if (relative_end < 0) + // 11. If relativeEnd is -∞, let final be 0. + if (Value(relative_end).is_negative_infinity()) + final = 0; + // 12. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0). + else if (relative_end < 0) final = max(length + relative_end, 0.0); + // 13. Else, let final be min(relativeEnd, len). else final = min(relative_end, (double)length); + // 14. Let newLen be max(final - first, 0). auto new_length = max(final - first, 0.0); + // 15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%). auto* constructor = TRY(species_constructor(global_object, *array_buffer_object, *global_object.array_buffer_constructor())); + + // 16. Let new be ? Construct(ctor, « 𝔽(newLen) »). auto* new_array_buffer = TRY(construct(global_object, *constructor, Value(new_length))); + // 17. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]). if (!is(new_array_buffer)) return vm.throw_completion(global_object, ErrorType::SpeciesConstructorDidNotCreate, "an ArrayBuffer"); auto* new_array_buffer_object = static_cast(new_array_buffer); + // 18. If IsSharedArrayBuffer(new) is true, throw a TypeError exception. // FIXME: Check for shared buffer + + // 19. If IsDetachedBuffer(new) is true, throw a TypeError exception. if (new_array_buffer_object->is_detached()) return vm.throw_completion(global_object, ErrorType::SpeciesConstructorReturned, "a detached ArrayBuffer"); + + // 20. If SameValue(new, O) is true, throw a TypeError exception. if (same_value(new_array_buffer_object, array_buffer_object)) return vm.throw_completion(global_object, ErrorType::SpeciesConstructorReturned, "same ArrayBuffer instance"); + + // 21. If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception. if (new_array_buffer_object->byte_length() < new_length) return vm.throw_completion(global_object, ErrorType::SpeciesConstructorReturned, "an ArrayBuffer smaller than requested"); + // 22. NOTE: Side-effects of the above steps may have detached O. + // 23. If IsDetachedBuffer(O) is true, throw a TypeError exception. if (array_buffer_object->is_detached()) return vm.throw_completion(global_object, ErrorType::DetachedArrayBuffer); - // This is ugly, is there a better way to do this? + // 24. Let fromBuf be O.[[ArrayBufferData]]. + // 25. Let toBuf be new.[[ArrayBufferData]]. + // 26. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen). + // FIXME: Implement this to specification array_buffer_object->buffer().span().slice(first, new_length).copy_to(new_array_buffer_object->buffer().span()); + + // 27. Return new. return new_array_buffer_object; }