From f98a98506feec9405177fd920b9cf74d2c87e36b Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Fri, 9 Jul 2021 17:17:10 +0300 Subject: [PATCH] LibJS: Add %TypedArray%.prototype.subarray --- .../LibJS/Runtime/CommonPropertyNames.h | 1 + .../LibJS/Runtime/TypedArrayPrototype.cpp | 56 +++++++++++++++++++ .../LibJS/Runtime/TypedArrayPrototype.h | 1 + .../TypedArray.prototype.subarray.js | 45 +++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.subarray.js diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 8b7a96a906..42dcea4bdf 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -303,6 +303,7 @@ namespace JS { P(strike) \ P(stringify) \ P(sub) \ + P(subarray) \ P(substr) \ P(substring) \ P(sup) \ diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 1332b3894b..049042e67d 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -46,6 +46,7 @@ void TypedArrayPrototype::initialize(GlobalObject& object) define_native_function(vm.names.entries, entries, 0, attr); define_native_function(vm.names.set, set, 1, attr); define_native_function(vm.names.slice, slice, 2, attr); + define_native_function(vm.names.subarray, subarray, 2, attr); define_native_function(vm.names.reverse, reverse, 0, attr); define_native_function(vm.names.copyWithin, copy_within, 2, attr); define_native_function(vm.names.filter, filter, 1, attr); @@ -907,6 +908,61 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::slice) return new_array; } +// 23.2.3.27 %TypedArray%.prototype.subarray ( begin, end ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray +JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::subarray) +{ + auto* typed_array = typed_array_from(global_object); + if (!typed_array) + return {}; + + auto length = typed_array->array_length(); + + auto relative_begin = vm.argument(0).to_integer_or_infinity(global_object); + if (vm.exception()) + return {}; + + i32 begin_index; + if (Value(relative_begin).is_negative_infinity()) + begin_index = 0; + else if (relative_begin < 0) + begin_index = max(length + relative_begin, 0); + else + begin_index = min(relative_begin, length); + + double relative_end; + if (vm.argument(1).is_undefined()) { + relative_end = length; + } else { + relative_end = vm.argument(1).to_integer_or_infinity(global_object); + if (vm.exception()) + return {}; + } + + i32 end_index; + if (Value(relative_end).is_negative_infinity()) + end_index = 0; + else if (relative_end < 0) + end_index = max(length + relative_end, 0); + else + end_index = min(relative_end, length); + + auto new_length = max(end_index - begin_index, 0); + + Checked begin_byte_offset = begin_index; + begin_byte_offset *= typed_array->element_size(); + begin_byte_offset += typed_array->byte_offset(); + if (begin_byte_offset.has_overflow()) { + dbgln("TypedArrayPrototype::begin_byte_offset: limit overflowed, returning as if succeeded."); + return typed_array; + } + + MarkedValueList arguments(vm.heap()); + arguments.empend(typed_array->viewed_array_buffer()); + arguments.empend(begin_byte_offset.value()); + arguments.empend(new_length); + return typed_array_species_create(global_object, *typed_array, move(arguments)); +} + // 23.2.3.22 %TypedArray%.prototype.reverse ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::reverse) { diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h index 9ccb095da7..39c2b51bdd 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h @@ -43,6 +43,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(entries); JS_DECLARE_NATIVE_FUNCTION(set); JS_DECLARE_NATIVE_FUNCTION(slice); + JS_DECLARE_NATIVE_FUNCTION(subarray); JS_DECLARE_NATIVE_FUNCTION(reverse); JS_DECLARE_NATIVE_FUNCTION(copy_within); JS_DECLARE_NATIVE_FUNCTION(filter); diff --git a/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.subarray.js b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.subarray.js new file mode 100644 index 0000000000..aa60b769d0 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.subarray.js @@ -0,0 +1,45 @@ +const TYPED_ARRAYS = [ + Uint8Array, + Uint8ClampedArray, + Uint16Array, + Uint32Array, + Int8Array, + Int16Array, + Int32Array, + Float32Array, + Float64Array, +]; + +const BIGINT_TYPED_ARRAYS = [BigUint64Array, BigInt64Array]; + +test("basic functionality", () => { + TYPED_ARRAYS.forEach(T => { + expect(T.prototype.subarray).toHaveLength(2); + + const typedArray = new T(3); + typedArray[0] = 1; + typedArray[1] = 2; + typedArray[2] = 3; + + const subarray = typedArray.subarray(1, 2); + expect(subarray).toHaveLength(1); + expect(subarray[0]).toBe(2); + subarray[0] = 4; + expect(typedArray[1]).toBe(4); + }); + + BIGINT_TYPED_ARRAYS.forEach(T => { + expect(T.prototype.subarray).toHaveLength(2); + + const typedArray = new T(3); + typedArray[0] = 1n; + typedArray[1] = 2n; + typedArray[2] = 3n; + + const subarray = typedArray.subarray(1, 2); + expect(subarray).toHaveLength(1); + expect(subarray[0]).toBe(2n); + subarray[0] = 4n; + expect(typedArray[1]).toBe(4n); + }); +});