TypedArrayPrototype.cpp 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191
  1. /*
  2. * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  4. * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/TypeCasts.h>
  9. #include <LibJS/Runtime/AbstractOperations.h>
  10. #include <LibJS/Runtime/Array.h>
  11. #include <LibJS/Runtime/ArrayIterator.h>
  12. #include <LibJS/Runtime/GlobalObject.h>
  13. #include <LibJS/Runtime/TypedArray.h>
  14. #include <LibJS/Runtime/TypedArrayPrototype.h>
  15. #include <LibJS/Runtime/ValueInlines.h>
  16. namespace JS {
  17. GC_DEFINE_ALLOCATOR(TypedArrayPrototype);
  18. TypedArrayPrototype::TypedArrayPrototype(Realm& realm)
  19. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  20. {
  21. }
  22. void TypedArrayPrototype::initialize(Realm& realm)
  23. {
  24. auto& vm = this->vm();
  25. Base::initialize(realm);
  26. u8 attr = Attribute::Writable | Attribute::Configurable;
  27. define_native_accessor(realm, vm.names.buffer, buffer_getter, nullptr, Attribute::Configurable);
  28. define_native_accessor(realm, vm.names.byteLength, byte_length_getter, nullptr, Attribute::Configurable);
  29. define_native_accessor(realm, vm.names.byteOffset, byte_offset_getter, nullptr, Attribute::Configurable);
  30. define_native_accessor(realm, vm.names.length, length_getter, nullptr, Attribute::Configurable);
  31. define_native_function(realm, vm.names.at, at, 1, attr);
  32. define_native_function(realm, vm.names.copyWithin, copy_within, 2, attr);
  33. define_native_function(realm, vm.names.entries, entries, 0, attr);
  34. define_native_function(realm, vm.names.every, every, 1, attr);
  35. define_native_function(realm, vm.names.fill, fill, 1, attr);
  36. define_native_function(realm, vm.names.filter, filter, 1, attr);
  37. define_native_function(realm, vm.names.find, find, 1, attr);
  38. define_native_function(realm, vm.names.findIndex, find_index, 1, attr);
  39. define_native_function(realm, vm.names.findLast, find_last, 1, attr);
  40. define_native_function(realm, vm.names.findLastIndex, find_last_index, 1, attr);
  41. define_native_function(realm, vm.names.forEach, for_each, 1, attr);
  42. define_native_function(realm, vm.names.includes, includes, 1, attr);
  43. define_native_function(realm, vm.names.indexOf, index_of, 1, attr);
  44. define_native_function(realm, vm.names.join, join, 1, attr);
  45. define_native_function(realm, vm.names.keys, keys, 0, attr);
  46. define_native_function(realm, vm.names.lastIndexOf, last_index_of, 1, attr);
  47. define_native_function(realm, vm.names.map, map, 1, attr);
  48. define_native_function(realm, vm.names.reduce, reduce, 1, attr);
  49. define_native_function(realm, vm.names.reduceRight, reduce_right, 1, attr);
  50. define_native_function(realm, vm.names.reverse, reverse, 0, attr);
  51. define_native_function(realm, vm.names.set, set, 1, attr);
  52. define_native_function(realm, vm.names.slice, slice, 2, attr);
  53. define_native_function(realm, vm.names.some, some, 1, attr);
  54. define_native_function(realm, vm.names.sort, sort, 1, attr);
  55. define_native_function(realm, vm.names.subarray, subarray, 2, attr);
  56. define_native_function(realm, vm.names.toLocaleString, to_locale_string, 0, attr);
  57. define_native_function(realm, vm.names.toReversed, to_reversed, 0, attr);
  58. define_native_function(realm, vm.names.toSorted, to_sorted, 1, attr);
  59. define_native_function(realm, vm.names.with, with, 2, attr);
  60. define_native_function(realm, vm.names.values, values, 0, attr);
  61. define_native_accessor(realm, vm.well_known_symbol_to_string_tag(), to_string_tag_getter, nullptr, Attribute::Configurable);
  62. // 23.2.3.34 %TypedArray%.prototype.toString ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring
  63. define_direct_property(vm.names.toString, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.toString), attr);
  64. // 23.2.3.37 %TypedArray%.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator
  65. define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), attr);
  66. }
  67. static ThrowCompletionOr<TypedArrayBase*> typed_array_from_this(VM& vm)
  68. {
  69. auto this_value = vm.this_value();
  70. return typed_array_from(vm, this_value);
  71. }
  72. static ThrowCompletionOr<GC::Ref<FunctionObject>> callback_from_args(VM& vm, StringView prototype_name)
  73. {
  74. if (vm.argument_count() < 1)
  75. return vm.throw_completion<TypeError>(ErrorType::TypedArrayPrototypeOneArg, prototype_name);
  76. auto callback = vm.argument(0);
  77. if (!callback.is_function())
  78. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, callback);
  79. return callback.as_function();
  80. }
  81. // 23.2.4.1 TypedArraySpeciesCreate ( exemplar, argumentList ), https://tc39.es/ecma262/#typedarray-species-create
  82. static ThrowCompletionOr<TypedArrayBase*> typed_array_species_create(VM& vm, TypedArrayBase const& exemplar, GC::RootVector<Value> arguments)
  83. {
  84. auto& realm = *vm.current_realm();
  85. // 1. Let defaultConstructor be the intrinsic object listed in column one of Table 72 for exemplar.[[TypedArrayName]].
  86. auto default_constructor = (realm.intrinsics().*exemplar.intrinsic_constructor())();
  87. // 2. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
  88. auto* constructor = TRY(species_constructor(vm, exemplar, *default_constructor));
  89. // 3. Let result be ? TypedArrayCreate(constructor, argumentList).
  90. auto* result = TRY(typed_array_create(vm, *constructor, move(arguments)));
  91. // 4. Assert: result has [[TypedArrayName]] and [[ContentType]] internal slots.
  92. // 5. If result.[[ContentType]] ≠ exemplar.[[ContentType]], throw a TypeError exception.
  93. if (result->content_type() != exemplar.content_type())
  94. return vm.throw_completion<TypeError>(ErrorType::TypedArrayContentTypeMismatch, result->class_name(), exemplar.class_name());
  95. // 6. Return result.
  96. return result;
  97. }
  98. // 23.2.3.1 %TypedArray%.prototype.at ( index ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.at
  99. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::at)
  100. {
  101. auto index = vm.argument(0);
  102. // 1. Let O be the this value.
  103. auto* typed_array = TRY(typed_array_from_this(vm));
  104. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  105. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  106. // 3. Let len be TypedArrayLength(taRecord).
  107. auto length = typed_array_length(typed_array_record);
  108. // 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
  109. auto relative_index = TRY(index.to_integer_or_infinity(vm));
  110. if (Value { relative_index }.is_infinity())
  111. return js_undefined();
  112. Checked<size_t> k_checked { 0 };
  113. // 5. If relativeIndex ≥ 0, then
  114. if (relative_index >= 0) {
  115. // a. Let k be relativeIndex.
  116. k_checked += relative_index;
  117. }
  118. // 6. Else,
  119. else {
  120. // a. Let k be len + relativeIndex.
  121. k_checked += length;
  122. k_checked -= -relative_index;
  123. }
  124. // 7. If k < 0 or k ≥ len, return undefined.
  125. if (k_checked.has_overflow() || k_checked.value() >= length)
  126. return js_undefined();
  127. // 8. Return ! Get(O, ! ToString(𝔽(k))).
  128. return MUST(typed_array->get(k_checked.value()));
  129. }
  130. // 23.2.3.2 get %TypedArray%.prototype.buffer, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.buffer
  131. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::buffer_getter)
  132. {
  133. // 1. Let O be the this value.
  134. // 2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  135. // 3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  136. auto* typed_array = TRY(typed_array_from_this(vm));
  137. // 4. Let buffer be O.[[ViewedArrayBuffer]].
  138. auto* buffer = typed_array->viewed_array_buffer();
  139. VERIFY(buffer);
  140. // 5. Return buffer.
  141. return Value(buffer);
  142. }
  143. // 23.2.3.3 get %TypedArray%.prototype.byteLength, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.bytelength
  144. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::byte_length_getter)
  145. {
  146. // 1. Let O be the this value.
  147. // 2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  148. // 3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  149. auto* typed_array = TRY(typed_array_from_this(vm));
  150. // 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  151. auto typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  152. // 5. Let size be TypedArrayByteLength(taRecord).
  153. auto size = typed_array_byte_length(typed_array_record);
  154. // 6. Return 𝔽(size).
  155. return Value { size };
  156. }
  157. // 23.2.3.4 get %TypedArray%.prototype.byteOffset, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.byteoffset
  158. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::byte_offset_getter)
  159. {
  160. // 1. Let O be the this value.
  161. // 2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  162. // 3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  163. auto* typed_array = TRY(typed_array_from_this(vm));
  164. // 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  165. auto typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  166. // 5. If IsTypedArrayOutOfBounds(taRecord) is true, return +0𝔽.
  167. if (is_typed_array_out_of_bounds(typed_array_record))
  168. return Value { 0 };
  169. // 6. Let offset be O.[[ByteOffset]].
  170. auto offset = typed_array->byte_offset();
  171. // 7. Return 𝔽(offset).
  172. return Value { offset };
  173. }
  174. // 23.2.3.6 %TypedArray%.prototype.copyWithin ( target, start [ , end ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
  175. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::copy_within)
  176. {
  177. auto target = vm.argument(0);
  178. auto start = vm.argument(1);
  179. auto end = vm.argument(2);
  180. // 1. Let O be the this value.
  181. auto* typed_array = TRY(typed_array_from_this(vm));
  182. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  183. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  184. // 3. Let len be TypedArrayLength(taRecord).
  185. auto length = typed_array_length(typed_array_record);
  186. // 4. Let relativeTarget be ? ToIntegerOrInfinity(target).
  187. auto relative_target = TRY(target.to_integer_or_infinity(vm));
  188. double to;
  189. // 5. If relativeTarget = -∞, let to be 0.
  190. if (Value { relative_target }.is_negative_infinity()) {
  191. to = 0.0;
  192. }
  193. // 6. Else if relativeTarget < 0, let to be max(len + relativeTarget, 0).
  194. else if (relative_target < 0) {
  195. to = max(length + relative_target, 0.0);
  196. }
  197. // 7. Else, let to be min(relativeTarget, len).
  198. else {
  199. to = min(relative_target, (double)length);
  200. }
  201. // 8. Let relativeStart be ? ToIntegerOrInfinity(start).
  202. auto relative_start = TRY(start.to_integer_or_infinity(vm));
  203. double from;
  204. // 9. If relativeStart = -∞, let from be 0.
  205. if (Value { relative_start }.is_negative_infinity()) {
  206. from = 0.0;
  207. }
  208. // 10. Else if relativeStart < 0, let from be max(len + relativeStart, 0).
  209. else if (relative_start < 0) {
  210. from = max(length + relative_start, 0.0);
  211. }
  212. // 11. Else, let from be min(relativeStart, len).
  213. else {
  214. from = min(relative_start, (double)length);
  215. }
  216. double relative_end;
  217. // 12. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  218. if (end.is_undefined())
  219. relative_end = length;
  220. else
  221. relative_end = TRY(end.to_integer_or_infinity(vm));
  222. double final;
  223. // 13. If relativeEnd = -∞, let final be 0.
  224. if (Value { relative_end }.is_negative_infinity()) {
  225. final = 0.0;
  226. }
  227. // 14. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  228. else if (relative_end < 0) {
  229. final = max(length + relative_end, 0.0);
  230. }
  231. // 15. Else, let final be min(relativeEnd, len).
  232. else {
  233. final = min(relative_end, (double)length);
  234. }
  235. // 16. Let count be min(final - from, len - to).
  236. double count = min(final - from, length - to);
  237. // 17. If count > 0, then
  238. if (count > 0.0) {
  239. // a. NOTE: The copying must be performed in a manner that preserves the bit-level encoding of the source data.
  240. // b. Let buffer be O.[[ViewedArrayBuffer]].
  241. auto* buffer = typed_array->viewed_array_buffer();
  242. // c. Set taRecord to MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  243. typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  244. // d. If IsTypedArrayOutOfBounds(taRecord) is true, throw a TypeError exception.
  245. if (is_typed_array_out_of_bounds(typed_array_record))
  246. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  247. // e. Set len to TypedArrayLength(taRecord).
  248. length = typed_array_length(typed_array_record);
  249. // f. Let elementSize be TypedArrayElementSize(O).
  250. auto element_size = typed_array->element_size();
  251. // g. Let byteOffset be O.[[ByteOffset]].
  252. auto byte_offset = typed_array->byte_offset();
  253. // FIXME: Not exactly sure what we should do when overflow occurs. Just return as if succeeded for now.
  254. // h. Let bufferByteLimit be len × elementSize + byteOffset.
  255. Checked<size_t> buffer_byte_limit_checked = static_cast<size_t>(length);
  256. buffer_byte_limit_checked *= element_size;
  257. buffer_byte_limit_checked += byte_offset;
  258. if (buffer_byte_limit_checked.has_overflow()) {
  259. dbgln("TypedArrayPrototype::copy_within: buffer_byte_limit overflowed, returning as if succeeded.");
  260. return typed_array;
  261. }
  262. // i. Let toByteIndex be to × elementSize + byteOffset.
  263. Checked<size_t> to_byte_index_checked = static_cast<size_t>(to);
  264. to_byte_index_checked *= element_size;
  265. to_byte_index_checked += byte_offset;
  266. if (to_byte_index_checked.has_overflow()) {
  267. dbgln("TypedArrayPrototype::copy_within: to_byte_index overflowed, returning as if succeeded.");
  268. return typed_array;
  269. }
  270. // j. Let fromByteIndex be from × elementSize + byteOffset.
  271. Checked<size_t> from_byte_index_checked = static_cast<size_t>(from);
  272. from_byte_index_checked *= element_size;
  273. from_byte_index_checked += byte_offset;
  274. if (from_byte_index_checked.has_overflow()) {
  275. dbgln("TypedArrayPrototype::copy_within: from_byte_index overflowed, returning as if succeeded.");
  276. return typed_array;
  277. }
  278. // k. Let countBytes be count × elementSize.
  279. Checked<size_t> count_bytes_checked = static_cast<size_t>(count);
  280. count_bytes_checked *= element_size;
  281. if (count_bytes_checked.has_overflow()) {
  282. dbgln("TypedArrayPrototype::copy_within: count_bytes overflowed, returning as if succeeded.");
  283. return typed_array;
  284. }
  285. auto buffer_byte_limit = buffer_byte_limit_checked.value();
  286. auto to_byte_index = to_byte_index_checked.value();
  287. auto from_byte_index = from_byte_index_checked.value();
  288. auto count_bytes = count_bytes_checked.value();
  289. Checked<size_t> from_plus_count = from_byte_index;
  290. from_plus_count += count_bytes;
  291. if (from_plus_count.has_overflow()) {
  292. dbgln("TypedArrayPrototype::copy_within: from_plus_count overflowed, returning as if succeeded.");
  293. return typed_array;
  294. }
  295. i8 direction;
  296. // l. If fromByteIndex < toByteIndex and toByteIndex < fromByteIndex + countBytes, then
  297. if (from_byte_index < to_byte_index && to_byte_index < from_plus_count.value()) {
  298. // i. Let direction be -1.
  299. direction = -1;
  300. // ii. Set fromByteIndex to fromByteIndex + countBytes - 1.
  301. from_byte_index = from_plus_count.value() - 1;
  302. Checked<size_t> to_plus_count = to_byte_index;
  303. to_plus_count += count_bytes;
  304. if (to_plus_count.has_overflow()) {
  305. dbgln("TypedArrayPrototype::copy_within: to_plus_count overflowed, returning as if succeeded.");
  306. return typed_array;
  307. }
  308. // iii. Set toByteIndex to toByteIndex + countBytes - 1.
  309. to_byte_index = to_plus_count.value() - 1;
  310. }
  311. // m. Else,
  312. else {
  313. // i. Let direction be 1.
  314. direction = 1;
  315. }
  316. // n. Repeat, while countBytes > 0,
  317. while (count_bytes > 0) {
  318. // i. If fromByteIndex < bufferByteLimit and toByteIndex < bufferByteLimit, then
  319. if (from_byte_index < buffer_byte_limit && to_byte_index < buffer_byte_limit) {
  320. // 1. Let value be GetValueFromBuffer(buffer, fromByteIndex, uint8, true, unordered).
  321. auto value = buffer->get_value<u8>(from_byte_index, true, ArrayBuffer::Order::Unordered);
  322. // 2. Perform SetValueInBuffer(buffer, toByteIndex, uint8, value, true, unordered).
  323. buffer->set_value<u8>(to_byte_index, value, true, ArrayBuffer::Order::Unordered);
  324. // 3. Set fromByteIndex to fromByteIndex + direction.
  325. from_byte_index += direction;
  326. // 4. Set toByteIndex to toByteIndex + direction.
  327. to_byte_index += direction;
  328. // 5. Set countBytes to countBytes - 1.
  329. --count_bytes;
  330. }
  331. // ii. Else,
  332. else {
  333. // 1. Set countBytes to 0.
  334. count_bytes = 0;
  335. }
  336. }
  337. }
  338. // 18. Return O.
  339. return typed_array;
  340. }
  341. // 23.2.3.7 %TypedArray%.prototype.entries ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
  342. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::entries)
  343. {
  344. auto& realm = *vm.current_realm();
  345. // 1. Let O be the this value.
  346. auto* typed_array = TRY(typed_array_from_this(vm));
  347. // 2. Perform ? ValidateTypedArray(O, seq-cst).
  348. (void)TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  349. // 3. Return CreateArrayIterator(O, key+value).
  350. return ArrayIterator::create(realm, typed_array, Object::PropertyKind::KeyAndValue);
  351. }
  352. // 23.2.3.8 %TypedArray%.prototype.every ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
  353. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::every)
  354. {
  355. auto this_arg = vm.argument(1);
  356. // 1. Let O be the this value.
  357. auto* typed_array = TRY(typed_array_from_this(vm));
  358. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  359. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  360. // 3. Let len be TypedArrayLength(taRecord).
  361. auto length = typed_array_length(typed_array_record);
  362. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  363. auto callback_function = TRY(callback_from_args(vm, "every"sv));
  364. // 5. Let k be 0.
  365. // 6. Repeat, while k < len,
  366. for (size_t k = 0; k < length; ++k) {
  367. // a. Let Pk be ! ToString(𝔽(k)).
  368. PropertyKey property_key { k };
  369. // b. Let kValue be ! Get(O, Pk).
  370. auto value = MUST(typed_array->get(property_key));
  371. // c. Let testResult be ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
  372. auto test_result = TRY(call(vm, *callback_function, this_arg, value, Value { k }, typed_array)).to_boolean();
  373. // d. If testResult is false, return false.
  374. if (!test_result)
  375. return false;
  376. // e. Set k to k + 1.
  377. }
  378. // 7. Return true.
  379. return true;
  380. }
  381. // NOTE: This function assumes that the index is valid within the TypedArray,
  382. // and that the TypedArray is not detached.
  383. template<typename T>
  384. inline void fast_typed_array_fill(TypedArrayBase& typed_array, u32 begin, u32 end, T value)
  385. {
  386. Checked<size_t> computed_begin = begin;
  387. computed_begin *= sizeof(T);
  388. computed_begin += typed_array.byte_offset();
  389. Checked<size_t> computed_end = end;
  390. computed_end *= sizeof(T);
  391. computed_end += typed_array.byte_offset();
  392. if (computed_begin.has_overflow() || computed_end.has_overflow()) [[unlikely]] {
  393. return;
  394. }
  395. if (computed_begin.value() >= typed_array.viewed_array_buffer()->byte_length()
  396. || computed_end.value() > typed_array.viewed_array_buffer()->byte_length()) [[unlikely]] {
  397. return;
  398. }
  399. auto& array_buffer = *typed_array.viewed_array_buffer();
  400. auto* slot = reinterpret_cast<T*>(array_buffer.buffer().offset_pointer(computed_begin.value()));
  401. for (auto i = begin; i < end; ++i)
  402. *(slot++) = value;
  403. }
  404. // 23.2.3.9 %TypedArray%.prototype.fill ( value [ , start [ , end ] ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
  405. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::fill)
  406. {
  407. auto value = vm.argument(0);
  408. auto start = vm.argument(1);
  409. auto end = vm.argument(2);
  410. // 1. Let O be the this value.
  411. auto* typed_array = TRY(typed_array_from_this(vm));
  412. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  413. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  414. // 3. Let len be TypedArrayLength(taRecord).
  415. auto length = typed_array_length(typed_array_record);
  416. // 4. If O.[[ContentType]] is BigInt, set value to ? ToBigInt(value).
  417. if (typed_array->content_type() == TypedArrayBase::ContentType::BigInt)
  418. value = TRY(value.to_bigint(vm));
  419. // 5. Otherwise, set value to ? ToNumber(value).
  420. else
  421. value = TRY(value.to_number(vm));
  422. // 6. Let relativeStart be ? ToIntegerOrInfinity(start).
  423. auto relative_start = TRY(start.to_integer_or_infinity(vm));
  424. u32 k;
  425. // 7. If relativeStart = -∞, let k be 0.
  426. if (Value { relative_start }.is_negative_infinity())
  427. k = 0;
  428. // 8. Else if relativeStart < 0, let k be max(len + relativeStart, 0).
  429. else if (relative_start < 0)
  430. k = max(length + relative_start, 0);
  431. // 9. Else, let k be min(relativeStart, len).
  432. else
  433. k = min(relative_start, length);
  434. double relative_end;
  435. // 10. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  436. if (end.is_undefined())
  437. relative_end = length;
  438. else
  439. relative_end = TRY(end.to_integer_or_infinity(vm));
  440. u32 final;
  441. // 11. If relativeEnd = -∞, let final be 0.
  442. if (Value { relative_end }.is_negative_infinity())
  443. final = 0;
  444. // 12. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  445. else if (relative_end < 0)
  446. final = max(length + relative_end, 0);
  447. // 13. Else, let final be min(relativeEnd, len).
  448. else
  449. final = min(relative_end, length);
  450. // 14. Set taRecord to MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  451. typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  452. // 15. If IsTypedArrayOutOfBounds(taRecord) is true, throw a TypeError exception.
  453. if (is_typed_array_out_of_bounds(typed_array_record))
  454. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  455. // 16. Set len to TypedArrayLength(taRecord).
  456. length = typed_array_length(typed_array_record);
  457. // 17. Set final to min(final, len).
  458. final = min(final, length);
  459. if (value.is_int32()) {
  460. switch (typed_array->kind()) {
  461. case TypedArrayBase::Kind::Uint8Array:
  462. fast_typed_array_fill<u8>(*typed_array, k, final, static_cast<u8>(value.as_i32()));
  463. return typed_array;
  464. case TypedArrayBase::Kind::Uint16Array:
  465. fast_typed_array_fill<u16>(*typed_array, k, final, static_cast<u16>(value.as_i32()));
  466. return typed_array;
  467. case TypedArrayBase::Kind::Uint32Array:
  468. fast_typed_array_fill<u32>(*typed_array, k, final, static_cast<u32>(value.as_i32()));
  469. return typed_array;
  470. case TypedArrayBase::Kind::Int8Array:
  471. fast_typed_array_fill<i8>(*typed_array, k, final, static_cast<i8>(value.as_i32()));
  472. return typed_array;
  473. case TypedArrayBase::Kind::Int16Array:
  474. fast_typed_array_fill<i16>(*typed_array, k, final, static_cast<i16>(value.as_i32()));
  475. return typed_array;
  476. case TypedArrayBase::Kind::Int32Array:
  477. fast_typed_array_fill<i32>(*typed_array, k, final, value.as_i32());
  478. return typed_array;
  479. case TypedArrayBase::Kind::Uint8ClampedArray:
  480. fast_typed_array_fill<u8>(*typed_array, k, final, clamp(value.as_i32(), 0, 255));
  481. return typed_array;
  482. default:
  483. // FIXME: Support more TypedArray kinds.
  484. break;
  485. }
  486. }
  487. // 18. Repeat, while k < final,
  488. while (k < final) {
  489. // a. Let Pk be ! ToString(𝔽(k)).
  490. // b. Perform ! Set(O, Pk, value, true).
  491. CanonicalIndex canonical_index { CanonicalIndex::Type::Index, k };
  492. switch (typed_array->kind()) {
  493. #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
  494. case TypedArrayBase::Kind::ClassName: \
  495. (void)typed_array_set_element<Type>(*typed_array, canonical_index, value); \
  496. break;
  497. JS_ENUMERATE_TYPED_ARRAYS
  498. #undef __JS_ENUMERATE
  499. }
  500. // c. Set k to k + 1.
  501. ++k;
  502. }
  503. // 19. Return O.
  504. return typed_array;
  505. }
  506. // 23.2.3.10 %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
  507. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::filter)
  508. {
  509. auto this_arg = vm.argument(1);
  510. // 1. Let O be the this value.
  511. auto* typed_array = TRY(typed_array_from_this(vm));
  512. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  513. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  514. // 3. Let len be TypedArrayLength(taRecord).
  515. auto length = typed_array_length(typed_array_record);
  516. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  517. auto callback_function = TRY(callback_from_args(vm, "filter"sv));
  518. // 5. Let kept be a new empty List.
  519. GC::RootVector<Value> kept { vm.heap() };
  520. // 6. Let captured be 0.
  521. size_t captured = 0;
  522. // 7. Let k be 0.
  523. // 8. Repeat, while k < len,
  524. for (size_t k = 0; k < length; ++k) {
  525. // a. Let Pk be ! ToString(𝔽(k)).
  526. PropertyKey property_key { k };
  527. // b. Let kValue be ! Get(O, Pk).
  528. auto value = MUST(typed_array->get(property_key));
  529. // c. Let selected be ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
  530. auto selected = TRY(call(vm, *callback_function, this_arg, value, Value { k }, typed_array)).to_boolean();
  531. // d. If selected is true, then
  532. if (selected) {
  533. // i. Append kValue to kept.
  534. kept.append(value);
  535. // ii. Set captured to captured + 1.
  536. ++captured;
  537. }
  538. // e. Set k to k + 1.
  539. }
  540. // 9. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(captured) »).
  541. GC::RootVector<Value> arguments(vm.heap());
  542. arguments.empend(captured);
  543. auto* filter_array = TRY(typed_array_species_create(vm, *typed_array, move(arguments)));
  544. // 10. Let n be 0.
  545. size_t index = 0;
  546. // 11. For each element e of kept, do
  547. for (auto& value : kept) {
  548. // a. Perform ! Set(A, ! ToString(𝔽(n)), e, true).
  549. MUST(filter_array->set(index, value, Object::ShouldThrowExceptions::Yes));
  550. // b. Set n to n + 1.
  551. ++index;
  552. }
  553. // 12. Return A.
  554. return filter_array;
  555. }
  556. enum class Direction {
  557. Ascending,
  558. Descending,
  559. };
  560. struct FoundValue {
  561. Value index_to_value() const
  562. {
  563. if (!index.has_value())
  564. return Value { -1 };
  565. return Value { *index };
  566. }
  567. Optional<u32> index; // [[Index]]
  568. Value value; // [[Value]]
  569. };
  570. // 23.1.3.12.1 FindViaPredicate ( O, len, direction, predicate, thisArg ), https://tc39.es/ecma262/#sec-findviapredicate
  571. static ThrowCompletionOr<FoundValue> find_via_predicate(VM& vm, TypedArrayBase const& typed_array, u32 length, Direction direction, Value this_arg, StringView prototype_name)
  572. {
  573. // 1. If IsCallable(predicate) is false, throw a TypeError exception.
  574. auto predicate = TRY(callback_from_args(vm, prototype_name));
  575. Vector<u32> indices;
  576. indices.ensure_capacity(length);
  577. // 2. If direction is ascending, then
  578. if (direction == Direction::Ascending) {
  579. // a. Let indices be a List of the integers in the interval from 0 (inclusive) to len (exclusive), in ascending order.
  580. for (u32 i = 0; i < length; ++i)
  581. indices.unchecked_append(i);
  582. }
  583. // 3. Else,
  584. else {
  585. // a. Let indices be a List of the integers in the interval from 0 (inclusive) to len (exclusive), in descending order.
  586. for (u32 i = length; i > 0; --i)
  587. indices.unchecked_append(i - 1);
  588. }
  589. // 4. For each integer k of indices, do
  590. for (auto k : indices) {
  591. // a. Let Pk be ! ToString(𝔽(k)).
  592. PropertyKey property_key { k };
  593. // b. NOTE: If O is a TypedArray, the following invocation of Get will return a normal completion.
  594. // c. Let kValue be ? Get(O, Pk).
  595. auto value = TRY(typed_array.get(property_key));
  596. // d. Let testResult be ? Call(predicate, thisArg, « kValue, 𝔽(k), O »).
  597. auto test_result = TRY(call(vm, *predicate, this_arg, value, Value { k }, &typed_array));
  598. // e. If ToBoolean(testResult) is true, return the Record { [[Index]]: 𝔽(k), [[Value]]: kValue }.
  599. if (test_result.to_boolean())
  600. return FoundValue { k, value };
  601. }
  602. // 5. Return the Record { [[Index]]: -1𝔽, [[Value]]: undefined }.
  603. return FoundValue { {}, js_undefined() };
  604. }
  605. // 23.2.3.11 %TypedArray%.prototype.find ( predicate [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
  606. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::find)
  607. {
  608. auto this_arg = vm.argument(1);
  609. // 1. Let O be the this value.
  610. auto* typed_array = TRY(typed_array_from_this(vm));
  611. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  612. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  613. // 3. Let len be TypedArrayLength(taRecord).
  614. auto length = typed_array_length(typed_array_record);
  615. // 4. Let findRec be ? FindViaPredicate(O, len, ascending, predicate, thisArg).
  616. auto find_record = TRY(find_via_predicate(vm, *typed_array, length, Direction::Ascending, this_arg, "find"sv));
  617. // 5. Return findRec.[[Value]].
  618. return find_record.value;
  619. }
  620. // 23.2.3.12 %TypedArray%.prototype.findIndex ( predicate [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
  621. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::find_index)
  622. {
  623. auto this_arg = vm.argument(1);
  624. // 1. Let O be the this value.
  625. auto* typed_array = TRY(typed_array_from_this(vm));
  626. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  627. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  628. // 3. Let len be TypedArrayLength(taRecord).
  629. auto length = typed_array_length(typed_array_record);
  630. // 4. Let findRec be ? FindViaPredicate(O, len, ascending, predicate, thisArg).
  631. auto find_record = TRY(find_via_predicate(vm, *typed_array, length, Direction::Ascending, this_arg, "findIndex"sv));
  632. // 5. Return findRec.[[Index]].
  633. return find_record.index_to_value();
  634. }
  635. // 23.2.3.13 %TypedArray%.prototype.findLast ( predicate [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.findlast
  636. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::find_last)
  637. {
  638. auto this_arg = vm.argument(1);
  639. // 1. Let O be the this value.
  640. auto* typed_array = TRY(typed_array_from_this(vm));
  641. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  642. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  643. // 3. Let len be TypedArrayLength(taRecord).
  644. auto length = typed_array_length(typed_array_record);
  645. // 4. Let findRec be ? FindViaPredicate(O, len, descending, predicate, thisArg).
  646. auto find_record = TRY(find_via_predicate(vm, *typed_array, length, Direction::Descending, this_arg, "findLast"sv));
  647. // 5. Return findRec.[[Value]].
  648. return find_record.value;
  649. }
  650. // 23.2.3.14 %TypedArray%.prototype.findLastIndex ( predicate [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.findlastindex
  651. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::find_last_index)
  652. {
  653. auto this_arg = vm.argument(1);
  654. // 1. Let O be the this value.
  655. auto* typed_array = TRY(typed_array_from_this(vm));
  656. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  657. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  658. // 3. Let len be TypedArrayLength(taRecord).
  659. auto length = typed_array_length(typed_array_record);
  660. // 4. Let findRec be ? FindViaPredicate(O, len, descending, predicate, thisArg).
  661. auto find_record = TRY(find_via_predicate(vm, *typed_array, length, Direction::Descending, this_arg, "findLastIndex"sv));
  662. // 5. Return findRec.[[Index]].
  663. return find_record.index_to_value();
  664. }
  665. // 23.2.3.15 %TypedArray%.prototype.forEach ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
  666. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::for_each)
  667. {
  668. auto this_arg = vm.argument(1);
  669. // 1. Let O be the this value.
  670. auto* typed_array = TRY(typed_array_from_this(vm));
  671. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  672. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  673. // 3. Let len be TypedArrayLength(taRecord).
  674. auto length = typed_array_length(typed_array_record);
  675. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  676. auto callback_function = TRY(callback_from_args(vm, "forEach"sv));
  677. // 5. Let k be 0.
  678. // 6. Repeat, while k < len,
  679. for (size_t k = 0; k < length; ++k) {
  680. // a. Let Pk be ! ToString(𝔽(k)).
  681. PropertyKey property_key { k };
  682. // b. Let kValue be ! Get(O, Pk).
  683. auto value = MUST(typed_array->get(property_key));
  684. // c. Perform ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
  685. TRY(call(vm, *callback_function, this_arg, value, Value { k }, typed_array));
  686. // d. Set k to k + 1.
  687. }
  688. // 7. Return undefined.
  689. return js_undefined();
  690. }
  691. // 23.2.3.16 %TypedArray%.prototype.includes ( searchElement [ , fromIndex ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
  692. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::includes)
  693. {
  694. auto search_element = vm.argument(0);
  695. auto from_index = vm.argument(1);
  696. // 1. Let O be the this value.
  697. auto* typed_array = TRY(typed_array_from_this(vm));
  698. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  699. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  700. // 3. Let len be TypedArrayLength(taRecord).
  701. auto length = typed_array_length(typed_array_record);
  702. // 4. If len = 0, return false.
  703. if (length == 0)
  704. return Value { false };
  705. // 5. Let n be ? ToIntegerOrInfinity(fromIndex).
  706. auto n = TRY(from_index.to_integer_or_infinity(vm));
  707. // 6. Assert: If fromIndex is undefined, then n is 0.
  708. if (from_index.is_undefined())
  709. VERIFY(n == 0);
  710. Value value_n { n };
  711. // 7. If n = +∞, return false.
  712. if (value_n.is_positive_infinity())
  713. return Value { false };
  714. // 8. Else if n = -∞, set n to 0.
  715. else if (value_n.is_negative_infinity())
  716. n = 0;
  717. u32 k;
  718. // 9. If n ≥ 0, then
  719. if (n >= 0) {
  720. // a. Let k be n.
  721. k = n;
  722. }
  723. // 10. Else,
  724. else {
  725. // a. Let k be len + n.
  726. auto relative_k = length + n; // Ensures we dont overflow `k`.
  727. // b. If k < 0, set k to 0.
  728. if (relative_k < 0)
  729. relative_k = 0;
  730. k = relative_k;
  731. }
  732. // 11. Repeat, while k < len,
  733. while (k < length) {
  734. // a. Let elementK be ! Get(O, ! ToString(𝔽(k))).
  735. auto element_k = MUST(typed_array->get(k));
  736. // b. If SameValueZero(searchElement, elementK) is true, return true.
  737. if (same_value_zero(search_element, element_k))
  738. return Value { true };
  739. // c. Set k to k + 1.
  740. ++k;
  741. }
  742. // 12. Return false.
  743. return Value { false };
  744. }
  745. // 23.2.3.17 %TypedArray%.prototype.indexOf ( searchElement [ , fromIndex ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
  746. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::index_of)
  747. {
  748. auto search_element = vm.argument(0);
  749. auto from_index = vm.argument(1);
  750. // 1. Let O be the this value.
  751. auto* typed_array = TRY(typed_array_from_this(vm));
  752. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  753. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  754. // 3. Let len be TypedArrayLength(taRecord).
  755. auto length = typed_array_length(typed_array_record);
  756. // 4. If len = 0, return -1𝔽.
  757. if (length == 0)
  758. return Value { -1 };
  759. // 5. Let n be ? ToIntegerOrInfinity(fromIndex).
  760. auto n = TRY(from_index.to_integer_or_infinity(vm));
  761. // 6. Assert: If fromIndex is undefined, then n is 0.
  762. if (from_index.is_undefined())
  763. VERIFY(n == 0);
  764. Value value_n { n };
  765. // 7. If n = +∞, return -1𝔽.
  766. if (value_n.is_positive_infinity())
  767. return Value { -1 };
  768. // 8. Else if n = -∞, set n to 0.
  769. else if (value_n.is_negative_infinity())
  770. n = 0;
  771. u32 k;
  772. // 9. If n ≥ 0, then
  773. if (n >= 0) {
  774. // a. Let k be n.
  775. k = n;
  776. }
  777. // 10. Else,
  778. else {
  779. // a. Let k be len + n.
  780. auto relative_k = length + n;
  781. // b. If k < 0, set k to 0.
  782. if (relative_k < 0)
  783. relative_k = 0;
  784. k = relative_k;
  785. }
  786. // 11. Repeat, while k < len,
  787. while (k < length) {
  788. // a. Let kPresent be ! HasProperty(O, ! ToString(𝔽(k))).
  789. auto k_present = MUST(typed_array->has_property(k));
  790. // b. If kPresent is true, then
  791. if (k_present) {
  792. // i. Let elementK be ! Get(O, ! ToString(𝔽(k))).
  793. auto element_k = MUST(typed_array->get(k));
  794. // ii. If IsStrictlyEqual(searchElement, elementK) is true, return 𝔽(k).
  795. if (is_strictly_equal(search_element, element_k))
  796. return Value { k };
  797. }
  798. // c. Set k to k + 1.
  799. ++k;
  800. }
  801. // 12. Return -1𝔽.
  802. return Value { -1 };
  803. }
  804. // 23.2.3.18 %TypedArray%.prototype.join ( separator ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
  805. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::join)
  806. {
  807. auto separator = vm.argument(0);
  808. // 1. Let O be the this value.
  809. auto* typed_array = TRY(typed_array_from_this(vm));
  810. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  811. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  812. // 3. Let len be TypedArrayLength(taRecord).
  813. auto length = typed_array_length(typed_array_record);
  814. String sep {};
  815. // 4. If separator is undefined, let sep be ",".
  816. if (separator.is_undefined())
  817. sep = String::from_code_point(',');
  818. // 5. Else, let sep be ? ToString(separator).
  819. else
  820. sep = TRY(separator.to_string(vm));
  821. // 6. Let R be the empty String.
  822. StringBuilder builder;
  823. // 7. Let k be 0.
  824. // 8. Repeat, while k < len,
  825. for (size_t k = 0; k < length; ++k) {
  826. // a. If k > 0, set R to the string-concatenation of R and sep.
  827. if (k > 0)
  828. builder.append(sep);
  829. // b. Let element be ! Get(O, ! ToString(𝔽(k))).
  830. auto element = MUST(typed_array->get(k));
  831. String next {};
  832. // c. If element is undefined, let next be the empty String; otherwise, let next be ! ToString(element).
  833. if (!element.is_undefined())
  834. next = MUST(element.to_string(vm));
  835. // d. Set R to the string-concatenation of R and next.
  836. builder.append(next);
  837. // e. Set k to k + 1.
  838. }
  839. // 9. Return R.
  840. return PrimitiveString::create(vm, MUST(builder.to_string()));
  841. }
  842. // 23.2.3.19 %TypedArray%.prototype.keys ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
  843. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::keys)
  844. {
  845. auto& realm = *vm.current_realm();
  846. // 1. Let O be the this value.
  847. auto* typed_array = TRY(typed_array_from_this(vm));
  848. // 2. Perform ? ValidateTypedArray(O, seq-cst).
  849. (void)TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  850. // 3. Return CreateArrayIterator(O, key).
  851. return ArrayIterator::create(realm, typed_array, Object::PropertyKind::Key);
  852. }
  853. // 23.2.3.20 %TypedArray%.prototype.lastIndexOf ( searchElement [ , fromIndex ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
  854. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::last_index_of)
  855. {
  856. auto search_element = vm.argument(0);
  857. auto from_index = vm.argument(1);
  858. // 1. Let O be the this value.
  859. auto* typed_array = TRY(typed_array_from_this(vm));
  860. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  861. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  862. // 3. Let len be TypedArrayLength(taRecord).
  863. auto length = typed_array_length(typed_array_record);
  864. // 4. If len = 0, return -1𝔽.
  865. if (length == 0)
  866. return Value { -1 };
  867. double n;
  868. // 5. If fromIndex is present, let n be ? ToIntegerOrInfinity(fromIndex); else let n be len - 1.
  869. if (vm.argument_count() > 1)
  870. n = TRY(from_index.to_integer_or_infinity(vm));
  871. else
  872. n = length - 1;
  873. // 6. If n = -∞, return -1𝔽.
  874. if (Value { n }.is_negative_infinity())
  875. return Value { -1 };
  876. i32 k;
  877. // 7. If n ≥ 0, then
  878. if (n >= 0) {
  879. // a. Let k be min(n, len - 1).
  880. k = min(n, (i32)length - 1);
  881. }
  882. // 8. Else,
  883. else {
  884. // a. Let k be len + n.
  885. auto relative_k = length + n; // Ensures we dont overflow `k`.
  886. if (relative_k < 0)
  887. relative_k = -1;
  888. k = relative_k;
  889. }
  890. // 9. Repeat, while k ≥ 0,
  891. while (k >= 0) {
  892. // a. Let kPresent be ! HasProperty(O, ! ToString(𝔽(k))).
  893. auto k_present = MUST(typed_array->has_property(k));
  894. // b. If kPresent is true, then
  895. if (k_present) {
  896. // i. Let elementK be ! Get(O, ! ToString(𝔽(k))).
  897. auto element_k = MUST(typed_array->get(k));
  898. // ii. If IsStrictlyEqual(searchElement, elementK) is true, return 𝔽(k).
  899. if (is_strictly_equal(search_element, element_k))
  900. return Value { k };
  901. }
  902. // c. Set k to k - 1.
  903. --k;
  904. }
  905. // 10. Return -1𝔽.
  906. return Value { -1 };
  907. }
  908. // 23.2.3.21 get %TypedArray%.prototype.length, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.length
  909. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::length_getter)
  910. {
  911. // 1. Let O be the this value.
  912. // 2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  913. // 3. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
  914. auto* typed_array = TRY(typed_array_from_this(vm));
  915. // 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  916. auto typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  917. // 5. If IsTypedArrayOutOfBounds(taRecord) is true, return +0𝔽.
  918. if (is_typed_array_out_of_bounds(typed_array_record))
  919. return Value { 0 };
  920. // 6. Let length be TypedArrayLength(taRecord).
  921. auto length = typed_array_length(typed_array_record);
  922. // 7. Return 𝔽(length).
  923. return Value { length };
  924. }
  925. // 23.2.3.22 %TypedArray%.prototype.map ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
  926. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::map)
  927. {
  928. auto this_arg = vm.argument(1);
  929. // 1. Let O be the this value.
  930. auto* typed_array = TRY(typed_array_from_this(vm));
  931. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  932. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  933. // 3. Let len be TypedArrayLength(taRecord).
  934. auto length = typed_array_length(typed_array_record);
  935. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  936. auto callback_function = TRY(callback_from_args(vm, "map"sv));
  937. // 5. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(len) »).
  938. GC::RootVector<Value> arguments(vm.heap());
  939. arguments.empend(length);
  940. auto* array = TRY(typed_array_species_create(vm, *typed_array, move(arguments)));
  941. // 6. Let k be 0.
  942. // 7. Repeat, while k < len,
  943. for (size_t k = 0; k < length; ++k) {
  944. // a. Let Pk be ! ToString(𝔽(k)).
  945. PropertyKey property_key { k };
  946. // b. Let kValue be ! Get(O, Pk).
  947. auto value = MUST(typed_array->get(property_key));
  948. // c. Let mappedValue be ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
  949. auto mapped_value = TRY(call(vm, *callback_function, this_arg, value, Value { k }, typed_array));
  950. // d. Perform ? Set(A, Pk, mappedValue, true).
  951. TRY(array->set(property_key, mapped_value, Object::ShouldThrowExceptions::Yes));
  952. // e. Set k to k + 1.
  953. }
  954. // 8. Return A.
  955. return array;
  956. }
  957. // 23.2.3.23 %TypedArray%.prototype.reduce ( callbackfn [ , initialValue ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
  958. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::reduce)
  959. {
  960. auto initial_value = vm.argument(1);
  961. // 1. Let O be the this value.
  962. auto* typed_array = TRY(typed_array_from_this(vm));
  963. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  964. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  965. // 3. Let len be TypedArrayLength(taRecord).
  966. auto length = typed_array_length(typed_array_record);
  967. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  968. auto callback_function = TRY(callback_from_args(vm, "reduce"sv));
  969. // 5. If len = 0 and initialValue is not present, throw a TypeError exception.
  970. if (length == 0 && vm.argument_count() <= 1)
  971. return vm.throw_completion<TypeError>(ErrorType::ReduceNoInitial);
  972. // 6. Let k be 0.
  973. u32 k = 0;
  974. // 7. Let accumulator be undefined.
  975. auto accumulator = js_undefined();
  976. // 8. If initialValue is present, then
  977. if (vm.argument_count() > 1) {
  978. // a. Set accumulator to initialValue.
  979. accumulator = initial_value;
  980. }
  981. // 9. Else,
  982. else {
  983. // a. Let Pk be ! ToString(𝔽(k)).
  984. PropertyKey property_key { k };
  985. // b. Set accumulator to ! Get(O, Pk).
  986. accumulator = MUST(typed_array->get(property_key));
  987. // c. Set k to k + 1.
  988. ++k;
  989. }
  990. // 10. Repeat, while k < len,
  991. while (k < length) {
  992. // a. Let Pk be ! ToString(𝔽(k)).
  993. PropertyKey property_key { k };
  994. // b. Let kValue be ! Get(O, Pk).
  995. auto value = MUST(typed_array->get(k));
  996. // c. Set accumulator to ? Call(callbackfn, undefined, « accumulator, kValue, 𝔽(k), O »).
  997. accumulator = TRY(call(vm, *callback_function, js_undefined(), accumulator, value, Value { k }, typed_array));
  998. // d. Set k to k + 1.
  999. ++k;
  1000. }
  1001. // 11. Return accumulator.
  1002. return accumulator;
  1003. }
  1004. // 23.2.3.24 %TypedArray%.prototype.reduceRight ( callbackfn [ , initialValue ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
  1005. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::reduce_right)
  1006. {
  1007. auto initial_value = vm.argument(1);
  1008. // 1. Let O be the this value.
  1009. auto* typed_array = TRY(typed_array_from_this(vm));
  1010. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1011. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1012. // 3. Let len be TypedArrayLength(taRecord).
  1013. auto length = typed_array_length(typed_array_record);
  1014. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  1015. auto callback_function = TRY(callback_from_args(vm, "reduceRight"sv));
  1016. // 5. If len = 0 and initialValue is not present, throw a TypeError exception.
  1017. if (length == 0 && vm.argument_count() <= 1)
  1018. return vm.throw_completion<TypeError>(ErrorType::ReduceNoInitial);
  1019. // 6. Let k be len - 1.
  1020. auto k = static_cast<i32>(length) - 1;
  1021. // 7. Let accumulator be undefined.
  1022. auto accumulator = js_undefined();
  1023. // 8. If initialValue is present, then
  1024. if (vm.argument_count() > 1) {
  1025. // a. Set accumulator to initialValue.
  1026. accumulator = initial_value;
  1027. }
  1028. // 9. Else,
  1029. else {
  1030. // a. Let Pk be ! ToString(𝔽(k)).
  1031. PropertyKey property_key { k };
  1032. // b. Set accumulator to ! Get(O, Pk).
  1033. accumulator = MUST(typed_array->get(property_key));
  1034. // c. Set k to k - 1.
  1035. --k;
  1036. }
  1037. // 10. Repeat, while k ≥ 0,
  1038. while (k >= 0) {
  1039. // a. Let Pk be ! ToString(𝔽(k)).
  1040. PropertyKey property_key { k };
  1041. // b. Let kValue be ! Get(O, Pk).
  1042. auto value = MUST(typed_array->get(k));
  1043. // c. Set accumulator to ? Call(callbackfn, undefined, « accumulator, kValue, 𝔽(k), O »).
  1044. accumulator = TRY(call(vm, *callback_function, js_undefined(), accumulator, value, Value { k }, typed_array));
  1045. // d. Set k to k - 1.
  1046. --k;
  1047. }
  1048. // 11. Return accumulator.
  1049. return accumulator;
  1050. }
  1051. // 23.2.3.25 %TypedArray%.prototype.reverse ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
  1052. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::reverse)
  1053. {
  1054. // 1. Let O be the this value.
  1055. auto* typed_array = TRY(typed_array_from_this(vm));
  1056. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1057. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1058. // 3. Let len be TypedArrayLength(taRecord).
  1059. auto length = typed_array_length(typed_array_record);
  1060. // 4. Let middle be floor(len / 2).
  1061. auto middle = length / 2;
  1062. // 5. Let lower be 0.
  1063. // 6. Repeat, while lower ≠ middle,
  1064. for (u32 lower = 0; lower != middle; ++lower) {
  1065. // a. Let upper be len - lower - 1.
  1066. auto upper = length - lower - 1;
  1067. // b. Let upperP be ! ToString(𝔽(upper)).
  1068. PropertyKey upper_property_key { upper };
  1069. // c. Let lowerP be ! ToString(𝔽(lower)).
  1070. PropertyKey lower_property_key { lower };
  1071. // d. Let lowerValue be ! Get(O, lowerP).
  1072. auto lower_value = MUST(typed_array->get(lower_property_key));
  1073. // e. Let upperValue be ! Get(O, upperP).
  1074. auto upper_value = MUST(typed_array->get(upper_property_key));
  1075. // f. Perform ! Set(O, lowerP, upperValue, true).
  1076. MUST(typed_array->set(lower_property_key, upper_value, Object::ShouldThrowExceptions::Yes));
  1077. // g. Perform ! Set(O, upperP, lowerValue, true).
  1078. MUST(typed_array->set(upper_property_key, lower_value, Object::ShouldThrowExceptions::Yes));
  1079. // h. Set lower to lower + 1.
  1080. }
  1081. // 7. Return O.
  1082. return typed_array;
  1083. }
  1084. // 23.2.3.26.1 SetTypedArrayFromTypedArray ( target, targetOffset, source ), https://tc39.es/ecma262/#sec-settypedarrayfromtypedarray
  1085. static ThrowCompletionOr<void> set_typed_array_from_typed_array(VM& vm, TypedArrayBase& target, double target_offset, TypedArrayBase const& source)
  1086. {
  1087. // 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
  1088. auto* target_buffer = target.viewed_array_buffer();
  1089. // 2. Let targetRecord be MakeTypedArrayWithBufferWitnessRecord(target, seq-cst)
  1090. auto target_record = make_typed_array_with_buffer_witness_record(target, ArrayBuffer::Order::SeqCst);
  1091. // 3. If IsTypedArrayOutOfBounds(targetRecord) is true, throw a TypeError exception.
  1092. if (is_typed_array_out_of_bounds(target_record))
  1093. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  1094. // 4. Let targetLength be TypedArrayLength(targetRecord).
  1095. auto target_length = typed_array_length(target_record);
  1096. // 5. Let srcBuffer be source.[[ViewedArrayBuffer]].
  1097. auto* source_buffer = source.viewed_array_buffer();
  1098. // 6. Let srcRecord be MakeTypedArrayWithBufferWitnessRecord(source, seq-cst).
  1099. auto source_record = make_typed_array_with_buffer_witness_record(source, ArrayBuffer::Order::SeqCst);
  1100. // 7. If IsTypedArrayOutOfBounds(srcRecord) is true, throw a TypeError exception.
  1101. if (is_typed_array_out_of_bounds(source_record))
  1102. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  1103. // 8. Let srcLength be TypedArrayLength(srcRecord).
  1104. auto source_length = typed_array_length(source_record);
  1105. // 9. Let targetType be TypedArrayElementType(target).
  1106. // 10. Let targetElementSize be TypedArrayElementSize(target).
  1107. auto target_element_size = target.element_size();
  1108. // 11. Let targetByteOffset be target.[[ByteOffset]].
  1109. auto target_byte_offset = target.byte_offset();
  1110. // 12. Let srcType be TypedArrayElementType(source).
  1111. // 13. Let srcElementSize be TypedArrayElementSize(source).
  1112. auto source_element_size = source.element_size();
  1113. // 14. Let srcByteOffset be source.[[ByteOffset]].
  1114. auto source_byte_offset = source.byte_offset();
  1115. // 15. If targetOffset = +∞, throw a RangeError exception.
  1116. if (Value { target_offset }.is_positive_infinity())
  1117. return vm.throw_completion<RangeError>(ErrorType::TypedArrayInvalidTargetOffset, "finite");
  1118. // 16. If srcLength + targetOffset > targetLength, throw a RangeError exception.
  1119. Checked<size_t> checked = source_length;
  1120. checked += static_cast<u32>(target_offset);
  1121. if (checked.has_overflow() || checked.value() > target_length)
  1122. return vm.throw_completion<RangeError>(ErrorType::TypedArrayOverflowOrOutOfBounds, "target length");
  1123. // 17. If target.[[ContentType]] is not source.[[ContentType]], throw a TypeError exception.
  1124. if (target.content_type() != source.content_type())
  1125. return vm.throw_completion<TypeError>(ErrorType::TypedArrayInvalidCopy, target.class_name(), source.class_name());
  1126. auto same_shared_array_buffer = false;
  1127. // 18. If IsSharedArrayBuffer(srcBuffer) is true, IsSharedArrayBuffer(targetBuffer) is true, and srcBuffer.[[ArrayBufferData]] is targetBuffer.[[ArrayBufferData]], let sameSharedArrayBuffer be true; otherwise, let sameSharedArrayBuffer be false.
  1128. if (source_buffer->is_shared_array_buffer() && target_buffer->is_shared_array_buffer() && (&source_buffer->buffer() == &target_buffer->buffer()))
  1129. same_shared_array_buffer = true;
  1130. size_t source_byte_index = 0;
  1131. // 19. If SameValue(srcBuffer, targetBuffer) is true or sameSharedArrayBuffer is true, then
  1132. if (same_shared_array_buffer || same_value(source_buffer, target_buffer)) {
  1133. // a. Let srcByteLength be TypedArrayByteLength(srcRecord).
  1134. auto source_byte_length = typed_array_byte_length(source_record);
  1135. // b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcByteLength).
  1136. source_buffer = TRY(clone_array_buffer(vm, *source_buffer, source_byte_offset, source_byte_length));
  1137. // c. Let srcByteIndex be 0.
  1138. source_byte_index = 0;
  1139. }
  1140. // 20. Else,
  1141. else {
  1142. // a. Let srcByteIndex be srcByteOffset.
  1143. source_byte_index = source_byte_offset;
  1144. }
  1145. // 21. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
  1146. Checked<size_t> checked_target_byte_index(static_cast<size_t>(target_offset));
  1147. checked_target_byte_index *= target_element_size;
  1148. checked_target_byte_index += target_byte_offset;
  1149. if (checked_target_byte_index.has_overflow())
  1150. return vm.throw_completion<RangeError>(ErrorType::TypedArrayOverflow, "target byte index");
  1151. auto target_byte_index = checked_target_byte_index.value();
  1152. // 22. Let limit be targetByteIndex + targetElementSize × srcLength.
  1153. Checked<size_t> checked_limit(source_length);
  1154. checked_limit *= target_element_size;
  1155. checked_limit += target_byte_index;
  1156. if (checked_limit.has_overflow())
  1157. return vm.throw_completion<RangeError>(ErrorType::TypedArrayOverflow, "target limit");
  1158. auto limit = checked_limit.value();
  1159. // 23. If srcType is targetType, then
  1160. if (source.element_name() == target.element_name()) {
  1161. // a. NOTE: The transfer must be performed in a manner that preserves the bit-level encoding of the source data.
  1162. // b. Repeat, while targetByteIndex < limit,
  1163. // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, true, Unordered).
  1164. // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, value, true, Unordered).
  1165. // iii. Set srcByteIndex to srcByteIndex + 1.
  1166. // iv. Set targetByteIndex to targetByteIndex + 1.
  1167. target_buffer->buffer().overwrite(target_byte_index, source_buffer->buffer().data() + source_byte_index, limit - target_byte_index);
  1168. }
  1169. // 24. Else,
  1170. else {
  1171. // a. Repeat, while targetByteIndex < limit,
  1172. while (target_byte_index < limit) {
  1173. // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType, true, Unordered).
  1174. auto value = source.get_value_from_buffer(source_byte_index, ArrayBuffer::Unordered);
  1175. // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered).
  1176. target.set_value_in_buffer(target_byte_index, value, ArrayBuffer::Unordered);
  1177. // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
  1178. source_byte_index += source_element_size;
  1179. // iv. Set targetByteIndex to targetByteIndex + targetElementSize.
  1180. target_byte_index += target_element_size;
  1181. }
  1182. }
  1183. // 25. Return unused.
  1184. return {};
  1185. }
  1186. // 23.2.3.26.2 SetTypedArrayFromArrayLike ( target, targetOffset, source ), https://tc39.es/ecma262/#sec-settypedarrayfromarraylike
  1187. static ThrowCompletionOr<void> set_typed_array_from_array_like(VM& vm, TypedArrayBase& target, double target_offset, Value source)
  1188. {
  1189. // 1. Let targetRecord be MakeTypedArrayWithBufferWitnessRecord(target, seq-cst)
  1190. auto target_record = make_typed_array_with_buffer_witness_record(target, ArrayBuffer::Order::SeqCst);
  1191. // 2. If IsTypedArrayOutOfBounds(targetRecord) is true, throw a TypeError exception.
  1192. if (is_typed_array_out_of_bounds(target_record))
  1193. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  1194. // 3. Let targetLength be TypedArrayLength(targetRecord).
  1195. auto target_length = typed_array_length(target_record);
  1196. // 4. Let src be ? ToObject(source).
  1197. auto source_object = TRY(source.to_object(vm));
  1198. // 5. Let srcLength be ? LengthOfArrayLike(src).
  1199. auto source_length = TRY(length_of_array_like(vm, source_object));
  1200. // 6. If targetOffset = +∞, throw a RangeError exception.
  1201. if (Value { target_offset }.is_positive_infinity())
  1202. return vm.throw_completion<RangeError>(ErrorType::TypedArrayInvalidTargetOffset, "finite");
  1203. // 7. If srcLength + targetOffset > targetLength, throw a RangeError exception.
  1204. Checked<size_t> checked = source_length;
  1205. checked += static_cast<u32>(target_offset);
  1206. if (checked.has_overflow() || checked.value() > target_length)
  1207. return vm.throw_completion<RangeError>(ErrorType::TypedArrayOverflowOrOutOfBounds, "target length");
  1208. // 8. Let k be 0.
  1209. size_t k = 0;
  1210. // 9. Repeat, while k < srcLength,
  1211. while (k < source_length) {
  1212. // a. Let Pk be ! ToString(𝔽(k)).
  1213. PropertyKey property_key { k };
  1214. // b. Let value be ? Get(src, Pk).
  1215. auto value = TRY(source_object->get(property_key));
  1216. // c. Let targetIndex be 𝔽(targetOffset + k).
  1217. // NOTE: We verify above that target_offset + source_length is valid, so this cannot fail.
  1218. auto target_index = MUST(CanonicalIndex::from_double(vm, CanonicalIndex::Type::Index, target_offset + k));
  1219. // d. Perform ? TypedArraySetElement(target, targetIndex, value).
  1220. // FIXME: This is very awkward.
  1221. #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
  1222. if (is<ClassName>(target)) \
  1223. TRY(typed_array_set_element<Type>(target, target_index, value));
  1224. JS_ENUMERATE_TYPED_ARRAYS
  1225. #undef __JS_ENUMERATE
  1226. // e. Set k to k + 1.
  1227. ++k;
  1228. }
  1229. // 10. Return unused.
  1230. return {};
  1231. }
  1232. // 23.2.3.26 %TypedArray%.prototype.set ( source [ , offset ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
  1233. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set)
  1234. {
  1235. auto source = vm.argument(0);
  1236. auto offset = vm.argument(1);
  1237. // 1. Let target be the this value.
  1238. // 2. Perform ? RequireInternalSlot(target, [[TypedArrayName]]).
  1239. // 3. Assert: target has a [[ViewedArrayBuffer]] internal slot.
  1240. auto* typed_array = TRY(typed_array_from_this(vm));
  1241. // 4. Let targetOffset be ? ToIntegerOrInfinity(offset).
  1242. auto target_offset = TRY(offset.to_integer_or_infinity(vm));
  1243. // 5. If targetOffset < 0, throw a RangeError exception.
  1244. if (target_offset < 0)
  1245. return vm.throw_completion<RangeError>(ErrorType::TypedArrayInvalidTargetOffset, "positive");
  1246. // 6. If source is an Object that has a [[TypedArrayName]] internal slot, then
  1247. if (source.is_object() && is<TypedArrayBase>(source.as_object())) {
  1248. auto& source_typed_array = static_cast<TypedArrayBase&>(source.as_object());
  1249. // a. Perform ? SetTypedArrayFromTypedArray(target, targetOffset, source).
  1250. TRY(set_typed_array_from_typed_array(vm, *typed_array, target_offset, source_typed_array));
  1251. }
  1252. // 7. Else,
  1253. else {
  1254. // a. Perform ? SetTypedArrayFromArrayLike(target, targetOffset, source).
  1255. TRY(set_typed_array_from_array_like(vm, *typed_array, target_offset, source));
  1256. }
  1257. // 8. Return undefined.
  1258. return js_undefined();
  1259. }
  1260. // 23.2.3.27 %TypedArray%.prototype.slice ( start, end ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
  1261. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::slice)
  1262. {
  1263. auto start = vm.argument(0);
  1264. auto end = vm.argument(1);
  1265. // 1. Let O be the this value.
  1266. auto* typed_array = TRY(typed_array_from_this(vm));
  1267. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1268. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1269. // 3. Let len be TypedArrayLength(taRecord).
  1270. auto length = typed_array_length(typed_array_record);
  1271. // 4. Let relativeStart be ? ToIntegerOrInfinity(start).
  1272. auto relative_start = TRY(start.to_integer_or_infinity(vm));
  1273. i32 k = 0;
  1274. // 5. If relativeStart = -∞, let k be 0.
  1275. if (Value { relative_start }.is_negative_infinity())
  1276. k = 0;
  1277. // 6. Else if relativeStart < 0, let k be max(len + relativeStart, 0).
  1278. else if (relative_start < 0)
  1279. k = max(length + relative_start, 0);
  1280. // 7. Else, let k be min(relativeStart, len).
  1281. else
  1282. k = min(relative_start, length);
  1283. double relative_end = 0;
  1284. // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  1285. if (end.is_undefined())
  1286. relative_end = length;
  1287. else
  1288. relative_end = TRY(end.to_integer_or_infinity(vm));
  1289. i32 final = 0;
  1290. // 9. If relativeEnd is -∞, let final be 0.
  1291. if (Value { relative_end }.is_negative_infinity())
  1292. final = 0;
  1293. // 10. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  1294. else if (relative_end < 0)
  1295. final = max(length + relative_end, 0);
  1296. // 11. Else, let final be min(relativeEnd, len).
  1297. else
  1298. final = min(relative_end, length);
  1299. // 12. Let count be max(final - k, 0).
  1300. auto count = max(final - k, 0);
  1301. // 13. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(count) »).
  1302. GC::RootVector<Value> arguments(vm.heap());
  1303. arguments.empend(count);
  1304. auto* array = TRY(typed_array_species_create(vm, *typed_array, move(arguments)));
  1305. // 14. If count > 0, then
  1306. if (count > 0) {
  1307. // a. Set taRecord to MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  1308. typed_array_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  1309. // b. If IsTypedArrayOutOfBounds(taRecord) is true, throw a TypeError exception.
  1310. if (is_typed_array_out_of_bounds(typed_array_record))
  1311. return vm.throw_completion<TypeError>(ErrorType::BufferOutOfBounds, "TypedArray"sv);
  1312. // c. Set len to TypedArrayLength(taRecord).
  1313. length = typed_array_length(typed_array_record);
  1314. // d. Set final to min(final, len).
  1315. final = min(final, length);
  1316. // e. Set count to max(final - k, 0).
  1317. count = max(final - k, 0);
  1318. // f. Let srcType be TypedArrayElementType(O).
  1319. // g. Let targetType be TypedArrayElementType(A).
  1320. // h. If srcType is targetType, then
  1321. if (typed_array->element_name() == array->element_name()) {
  1322. // i. NOTE: The transfer must be performed in a manner that preserves the bit-level encoding of the source data.
  1323. // ii. Let srcBuffer be O.[[ViewedArrayBuffer]].
  1324. auto& source_buffer = *typed_array->viewed_array_buffer();
  1325. // iii. Let targetBuffer be A.[[ViewedArrayBuffer]].
  1326. auto& target_buffer = *array->viewed_array_buffer();
  1327. // iv. Let elementSize be TypedArrayElementSize(O).
  1328. auto element_size = typed_array->element_size();
  1329. // v. Let srcByteOffset be O.[[ByteOffset]].
  1330. auto source_byte_offset = typed_array->byte_offset();
  1331. // vi. Let srcByteIndex be (k × elementSize) + srcByteOffset.
  1332. Checked<u32> source_byte_index = k;
  1333. source_byte_index *= element_size;
  1334. source_byte_index += source_byte_offset;
  1335. if (source_byte_index.has_overflow()) {
  1336. dbgln("TypedArrayPrototype::slice: source_byte_index overflowed, returning as if succeeded.");
  1337. return array;
  1338. }
  1339. // vii. Let targetByteIndex be A.[[ByteOffset]].
  1340. auto target_byte_index = array->byte_offset();
  1341. // viii. Let limit be targetByteIndex + (count × elementSize).
  1342. Checked<u32> limit = count;
  1343. limit *= element_size;
  1344. limit += target_byte_index;
  1345. if (limit.has_overflow()) {
  1346. dbgln("TypedArrayPrototype::slice: limit overflowed, returning as if succeeded.");
  1347. return array;
  1348. }
  1349. // ix. Repeat, while targetByteIndex < limit,
  1350. while (target_byte_index < limit) {
  1351. // 1. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, uint8, true, unordered).
  1352. auto value = source_buffer.get_value<u8>(source_byte_index.value(), true, ArrayBuffer::Unordered);
  1353. // 2. Perform SetValueInBuffer(targetBuffer, targetByteIndex, uint8, value, true, unordered).
  1354. target_buffer.set_value<u8>(target_byte_index, value, true, ArrayBuffer::Unordered);
  1355. // 3. Set srcByteIndex to srcByteIndex + 1.
  1356. ++source_byte_index;
  1357. // 4. Set targetByteIndex to targetByteIndex + 1.
  1358. ++target_byte_index;
  1359. }
  1360. }
  1361. // i. Else,
  1362. else {
  1363. // i. Let n be 0.
  1364. u32 n = 0;
  1365. // ii. Repeat, while k < final,
  1366. while (k < final) {
  1367. // 1. Let Pk be ! ToString(𝔽(k)).
  1368. PropertyKey property_key { k };
  1369. // 2. Let kValue be ! Get(O, Pk).
  1370. auto value = MUST(typed_array->get(property_key));
  1371. // 3. Perform ! Set(A, ! ToString(𝔽(n)), kValue, true).
  1372. MUST(array->set(n, value, Object::ShouldThrowExceptions::Yes));
  1373. // 4. Set k to k + 1.
  1374. ++k;
  1375. // 5. Set n to n + 1.
  1376. ++n;
  1377. }
  1378. }
  1379. }
  1380. // 15. Return A.
  1381. return array;
  1382. }
  1383. // 23.2.3.28 %TypedArray%.prototype.some ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
  1384. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::some)
  1385. {
  1386. auto this_arg = vm.argument(1);
  1387. // 1. Let O be the this value.
  1388. auto* typed_array = TRY(typed_array_from_this(vm));
  1389. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1390. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1391. // 3. Let len be TypedArrayLength(taRecord).
  1392. auto length = typed_array_length(typed_array_record);
  1393. // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  1394. auto callback_function = TRY(callback_from_args(vm, "some"sv));
  1395. // 5. Let k be 0.
  1396. // 6. Repeat, while k < len,
  1397. for (size_t k = 0; k < length; ++k) {
  1398. // a. Let Pk be ! ToString(𝔽(k)).
  1399. PropertyKey property_key { k };
  1400. // b. Let kValue be ! Get(O, Pk).
  1401. auto value = MUST(typed_array->get(property_key));
  1402. // c. Let testResult be ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
  1403. auto test_result = TRY(call(vm, *callback_function, this_arg, value, Value { k }, typed_array)).to_boolean();
  1404. // d. If testResult is true, return true.
  1405. if (test_result)
  1406. return true;
  1407. // e. Set k to k + 1.
  1408. }
  1409. // 7. Return false.
  1410. return false;
  1411. }
  1412. // 23.2.3.29 %TypedArray%.prototype.sort ( comparefn ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
  1413. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::sort)
  1414. {
  1415. auto compare_function = vm.argument(0);
  1416. // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
  1417. if (!compare_function.is_undefined() && !compare_function.is_function())
  1418. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, compare_function);
  1419. // 2. Let obj be the this value.
  1420. auto* typed_array = TRY(typed_array_from_this(vm));
  1421. // 3. Let taRecord be ? ValidateTypedArray(obj, seq-cst).
  1422. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1423. // 4. Let len be TypedArrayLength(taRecord).
  1424. auto length = typed_array_length(typed_array_record);
  1425. // 5. NOTE: The following closure performs a numeric comparison rather than the string comparison used in 23.1.3.30.
  1426. // 6. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs the following steps when called:
  1427. Function<ThrowCompletionOr<double>(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr<double> {
  1428. // a. Return ? CompareTypedArrayElements(x, y, comparefn).
  1429. return TRY(compare_typed_array_elements(vm, x, y, compare_function.is_undefined() ? nullptr : &compare_function.as_function()));
  1430. };
  1431. // 7. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, read-through-holes).
  1432. auto sorted_list = TRY(sort_indexed_properties(vm, *typed_array, length, sort_compare, Holes::ReadThroughHoles));
  1433. // 8. Let j be 0.
  1434. // 9. Repeat, while j < len,
  1435. for (size_t j = 0; j < length; j++) {
  1436. // a. Perform ! Set(obj, ! ToString(𝔽(j)), sortedList[j], true).
  1437. MUST(typed_array->set(j, sorted_list[j], Object::ShouldThrowExceptions::Yes));
  1438. // b. Set j to j + 1.
  1439. }
  1440. // 10. Return obj.
  1441. return typed_array;
  1442. }
  1443. // 23.2.3.30 %TypedArray%.prototype.subarray ( begin, end ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
  1444. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::subarray)
  1445. {
  1446. auto begin = vm.argument(0);
  1447. auto end = vm.argument(1);
  1448. // 1. Let O be the this value.
  1449. // 2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  1450. // 3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  1451. auto* typed_array = TRY(typed_array_from_this(vm));
  1452. // 4. Let buffer be O.[[ViewedArrayBuffer]].
  1453. auto* buffer = typed_array->viewed_array_buffer();
  1454. // 5. Let srcRecord be MakeTypedArrayWithBufferWitnessRecord(O, seq-cst).
  1455. auto source_record = make_typed_array_with_buffer_witness_record(*typed_array, ArrayBuffer::Order::SeqCst);
  1456. u32 source_length = 0;
  1457. // 6. If IsTypedArrayOutOfBounds(srcRecord) is true, then
  1458. if (is_typed_array_out_of_bounds(source_record)) {
  1459. // a. Let srcLength be 0.
  1460. source_length = 0;
  1461. }
  1462. // 7. Else,
  1463. else {
  1464. // a. Let srcLength be TypedArrayLength(srcRecord).
  1465. source_length = typed_array_length(source_record);
  1466. }
  1467. // 8. Let relativeBegin be ? ToIntegerOrInfinity(begin).
  1468. auto relative_begin = TRY(begin.to_integer_or_infinity(vm));
  1469. i32 begin_index = 0;
  1470. // 7. If relativeBegin = -∞, let beginIndex be 0.
  1471. if (Value(relative_begin).is_negative_infinity())
  1472. begin_index = 0;
  1473. // 8. Else if relativeBegin < 0, let beginIndex be max(srcLength + relativeBegin, 0).
  1474. else if (relative_begin < 0)
  1475. begin_index = max(source_length + relative_begin, 0);
  1476. // 9. Else, let beginIndex be min(relativeBegin, srcLength).
  1477. else
  1478. begin_index = min(relative_begin, source_length);
  1479. // 12. Let elementSize be TypedArrayElementSize(O).
  1480. auto element_size = typed_array->element_size();
  1481. // 13. Let srcByteOffset be O.[[ByteOffset]].
  1482. auto source_byte_offset = typed_array->byte_offset();
  1483. // 14. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
  1484. Checked<u32> begin_byte_offset = begin_index;
  1485. begin_byte_offset *= element_size;
  1486. begin_byte_offset += source_byte_offset;
  1487. if (begin_byte_offset.has_overflow()) {
  1488. dbgln("TypedArrayPrototype::begin_byte_offset: limit overflowed, returning as if succeeded.");
  1489. return typed_array;
  1490. }
  1491. GC::RootVector<Value> arguments(vm.heap());
  1492. // 15. If O.[[ArrayLength]] is auto and end is undefined, then
  1493. if (typed_array->array_length().is_auto() && end.is_undefined()) {
  1494. // a. Let argumentsList be « buffer, 𝔽(beginByteOffset) ».
  1495. arguments.empend(buffer);
  1496. arguments.empend(begin_byte_offset.value());
  1497. }
  1498. // 16. Else,
  1499. else {
  1500. double relative_end = 0;
  1501. // a. If end is undefined, let relativeEnd be srcLength; else let relativeEnd be ? ToIntegerOrInfinity(end).
  1502. if (end.is_undefined())
  1503. relative_end = source_length;
  1504. else
  1505. relative_end = TRY(end.to_integer_or_infinity(vm));
  1506. i32 end_index = 0;
  1507. // 11. If relativeEnd = -∞, let endIndex be 0.
  1508. if (Value(relative_end).is_negative_infinity())
  1509. end_index = 0;
  1510. // 12. Else if relativeEnd < 0, let endIndex be max(srcLength + relativeEnd, 0).
  1511. else if (relative_end < 0)
  1512. end_index = max(source_length + relative_end, 0);
  1513. // 13. Else, let endIndex be min(relativeEnd, srcLength).
  1514. else
  1515. end_index = min(relative_end, source_length);
  1516. // e. Let newLength be max(endIndex - beginIndex, 0).
  1517. auto new_length = max(end_index - begin_index, 0);
  1518. // f. Let argumentsList be « buffer, 𝔽(beginByteOffset), 𝔽(newLength) ».
  1519. arguments.empend(buffer);
  1520. arguments.empend(begin_byte_offset.value());
  1521. arguments.empend(new_length);
  1522. }
  1523. // 17. Return ? TypedArraySpeciesCreate(O, argumentsList).
  1524. return TRY(typed_array_species_create(vm, *typed_array, move(arguments)));
  1525. }
  1526. // 23.2.3.31 %TypedArray%.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
  1527. // 19.5.1 Array.prototype.toLocaleString ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sup-array.prototype.tolocalestring
  1528. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_locale_string)
  1529. {
  1530. auto locales = vm.argument(0);
  1531. auto options = vm.argument(1);
  1532. // This function is not generic. ValidateTypedArray is applied to the this value prior to evaluating the algorithm.
  1533. // If its result is an abrupt completion that exception is thrown instead of evaluating the algorithm.
  1534. // 1. Let array be ? ToObject(this value).
  1535. auto* typed_array = TRY(typed_array_from_this(vm));
  1536. // 2. Let len be ? ToLength(? Get(array, "length")).
  1537. // The implementation of the algorithm may be optimized with the knowledge that the this value is an object that
  1538. // has a fixed length and whose integer-indexed properties are not sparse.
  1539. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1540. auto length = typed_array_length(typed_array_record);
  1541. // 3. Let separator be the implementation-defined list-separator String value appropriate for the host environment's current locale (such as ", ").
  1542. constexpr auto separator = ',';
  1543. // 4. Let R be the empty String.
  1544. StringBuilder builder;
  1545. // 5. Let k be 0.
  1546. // 6. Repeat, while k < len,
  1547. for (size_t k = 0; k < length; ++k) {
  1548. // a. If k > 0, then
  1549. if (k > 0) {
  1550. // i. Set R to the string-concatenation of R and separator.
  1551. builder.append(separator);
  1552. }
  1553. // b. Let nextElement be ? Get(array, ! ToString(k)).
  1554. auto next_element = TRY(typed_array->get(k));
  1555. // c. If nextElement is not undefined or null, then
  1556. if (!next_element.is_nullish()) {
  1557. // i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)).
  1558. auto locale_string_value = TRY(next_element.invoke(vm, vm.names.toLocaleString, locales, options));
  1559. auto locale_string = TRY(locale_string_value.to_byte_string(vm));
  1560. // ii. Set R to the string-concatenation of R and S.
  1561. builder.append(locale_string);
  1562. }
  1563. // d. Set k to k + 1.
  1564. }
  1565. // 7. Return R.
  1566. return PrimitiveString::create(vm, builder.to_byte_string());
  1567. }
  1568. // 23.2.3.32 %TypedArray%.prototype.toReversed ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.toreversed
  1569. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_reversed)
  1570. {
  1571. // 1. Let O be the this value.
  1572. auto* typed_array = TRY(typed_array_from_this(vm));
  1573. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1574. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1575. // 3. Let length be TypedArrayLength(taRecord).
  1576. auto length = typed_array_length(typed_array_record);
  1577. // 4. Let A be ? TypedArrayCreateSameType(O, « 𝔽(length) »).
  1578. GC::RootVector<Value> arguments(vm.heap());
  1579. arguments.empend(length);
  1580. auto* array = TRY(typed_array_create_same_type(vm, *typed_array, move(arguments)));
  1581. // 5. Let k be 0.
  1582. // 6. Repeat, while k < length,
  1583. for (size_t k = 0; k < length; ++k) {
  1584. // a. Let from be ! ToString(𝔽(length - k - 1)).
  1585. PropertyKey from { length - k - 1 };
  1586. // b. Let Pk be ! ToString(𝔽(k)).
  1587. PropertyKey property_key { k };
  1588. // c. Let fromValue be ! Get(O, from).
  1589. auto from_value = MUST(typed_array->get(from));
  1590. // d. Perform ! Set(A, Pk, fromValue, true).
  1591. MUST(array->set(property_key, from_value, Object::ShouldThrowExceptions::Yes));
  1592. // e. Set k to k + 1.
  1593. }
  1594. // 7. Return A.
  1595. return array;
  1596. }
  1597. // 23.2.3.33 %TypedArray%.prototype.toSorted ( comparefn ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.tosorted
  1598. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_sorted)
  1599. {
  1600. auto compare_function = vm.argument(0);
  1601. // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
  1602. if (!compare_function.is_undefined() && !compare_function.is_function())
  1603. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, compare_function);
  1604. // 2. Let O be the this value.
  1605. auto* typed_array = TRY(typed_array_from_this(vm));
  1606. // 3. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1607. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1608. // 4. Let len be TypedArrayLength(taRecord).
  1609. auto length = typed_array_length(typed_array_record);
  1610. // 5. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »).
  1611. GC::RootVector<Value> arguments(vm.heap());
  1612. arguments.empend(length);
  1613. auto* array = TRY(typed_array_create_same_type(vm, *typed_array, move(arguments)));
  1614. // 6. NOTE: The following closure performs a numeric comparison rather than the string comparison used in 23.1.3.34.
  1615. Function<ThrowCompletionOr<double>(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr<double> {
  1616. // a. Return ? CompareTypedArrayElements(x, y, comparefn).
  1617. return TRY(compare_typed_array_elements(vm, x, y, compare_function.is_undefined() ? nullptr : &compare_function.as_function()));
  1618. };
  1619. // 8. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes).
  1620. auto sorted_list = TRY(sort_indexed_properties(vm, *typed_array, length, sort_compare, Holes::ReadThroughHoles));
  1621. // 9. Let j be 0.
  1622. // 10. Repeat, while j < len,
  1623. for (size_t j = 0; j < length; j++) {
  1624. // a. Perform ! Set(A, ! ToString(𝔽(j)), sortedList[j], true).
  1625. MUST(array->set(j, sorted_list[j], Object::ShouldThrowExceptions::Yes));
  1626. // b. Set j to j + 1.
  1627. }
  1628. // 11. Return A.
  1629. return array;
  1630. }
  1631. // 23.2.3.35 %TypedArray%.prototype.values ( ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
  1632. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::values)
  1633. {
  1634. auto& realm = *vm.current_realm();
  1635. // 1. Let O be the this value.
  1636. auto* typed_array = TRY(typed_array_from_this(vm));
  1637. // 2. Perform ? ValidateTypedArray(O, seq-cst).
  1638. (void)TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1639. // 3. Return CreateArrayIterator(O, value).
  1640. return ArrayIterator::create(realm, typed_array, Object::PropertyKind::Value);
  1641. }
  1642. // 23.2.3.36 %TypedArray%.prototype.with ( index, value ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.with
  1643. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::with)
  1644. {
  1645. auto index = vm.argument(0);
  1646. auto value = vm.argument(1);
  1647. // 1. Let O be the this value.
  1648. auto* typed_array = TRY(typed_array_from_this(vm));
  1649. // 2. Let taRecord be ? ValidateTypedArray(O, seq-cst).
  1650. auto typed_array_record = TRY(validate_typed_array(vm, *typed_array, ArrayBuffer::Order::SeqCst));
  1651. // 3. Let len be TypedArrayLength(taRecord).
  1652. auto length = typed_array_length(typed_array_record);
  1653. // 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
  1654. auto relative_index = TRY(index.to_integer_or_infinity(vm));
  1655. double actual_index = 0;
  1656. // 5. If relativeIndex ≥ 0, let actualIndex be relativeIndex.
  1657. if (relative_index >= 0)
  1658. actual_index = relative_index;
  1659. // 6. Else, let actualIndex be len + relativeIndex.
  1660. else
  1661. actual_index = length + relative_index;
  1662. Value numeric_value;
  1663. // 7. If O.[[ContentType]] is BigInt, let numericValue be ? ToBigInt(value).
  1664. if (typed_array->content_type() == TypedArrayBase::ContentType::BigInt)
  1665. numeric_value = TRY(value.to_bigint(vm));
  1666. // 8. Else, let numericValue be ? ToNumber(value).
  1667. else
  1668. numeric_value = TRY(value.to_number(vm));
  1669. // 9. If IsValidIntegerIndex(O, 𝔽(actualIndex)) is false, throw a RangeError exception.
  1670. if (!is_valid_integer_index(*typed_array, TRY(CanonicalIndex::from_double(vm, CanonicalIndex::Type::Index, actual_index))))
  1671. return vm.throw_completion<RangeError>(ErrorType::TypedArrayInvalidIntegerIndex, actual_index);
  1672. // 10. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »).
  1673. GC::RootVector<Value> arguments(vm.heap());
  1674. arguments.empend(length);
  1675. auto* array = TRY(typed_array_create_same_type(vm, *typed_array, move(arguments)));
  1676. // 11. Let k be 0.
  1677. // 12. Repeat, while k < len,
  1678. for (size_t k = 0; k < length; k++) {
  1679. // a. Let Pk be ! ToString(𝔽(k)).
  1680. PropertyKey property_key { k };
  1681. Value from_value;
  1682. // b. If k is actualIndex, let fromValue be numericValue.
  1683. if (k == actual_index)
  1684. from_value = numeric_value;
  1685. // c. Else, let fromValue be ! Get(O, Pk).
  1686. else
  1687. from_value = MUST(typed_array->get(property_key));
  1688. // d. Perform ! Set(A, Pk, fromValue, true).
  1689. MUST(array->set(property_key, from_value, Object::ShouldThrowExceptions::Yes));
  1690. // e. Set k to k + 1.
  1691. }
  1692. // 13. Return A.
  1693. return array;
  1694. }
  1695. // 23.2.3.38 get %TypedArray%.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
  1696. JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_string_tag_getter)
  1697. {
  1698. // 1. Let O be the this value.
  1699. auto this_value = vm.this_value();
  1700. // 2. If O is not an Object, return undefined.
  1701. if (!this_value.is_object())
  1702. return js_undefined();
  1703. auto& this_object = this_value.as_object();
  1704. // 3. If O does not have a [[TypedArrayName]] internal slot, return undefined.
  1705. if (!this_object.is_typed_array())
  1706. return js_undefined();
  1707. // 4. Let name be O.[[TypedArrayName]].
  1708. // 5. Assert: name is a String.
  1709. // 6. Return name.
  1710. return PrimitiveString::create(vm, static_cast<TypedArrayBase&>(this_object).element_name());
  1711. }
  1712. }