IntrinsicTypedArrayPrototype.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Jint.Collections;
  5. using Jint.Native.Array;
  6. using Jint.Native.ArrayBuffer;
  7. using Jint.Native.Iterator;
  8. using Jint.Native.Number;
  9. using Jint.Native.Object;
  10. using Jint.Native.Symbol;
  11. using Jint.Pooling;
  12. using Jint.Runtime;
  13. using Jint.Runtime.Descriptors;
  14. using Jint.Runtime.Interop;
  15. using Jint.Runtime.Interpreter.Expressions;
  16. namespace Jint.Native.TypedArray
  17. {
  18. /// <summary>
  19. /// https://tc39.es/ecma262/#sec-properties-of-the-%typedarrayprototype%-object
  20. /// </summary>
  21. internal sealed class IntrinsicTypedArrayPrototype : ObjectInstance
  22. {
  23. private readonly Realm _realm;
  24. private readonly IntrinsicTypedArrayConstructor _constructor;
  25. private ClrFunctionInstance _originalIteratorFunction;
  26. internal IntrinsicTypedArrayPrototype(
  27. Engine engine,
  28. Realm realm,
  29. ObjectInstance objectPrototype,
  30. IntrinsicTypedArrayConstructor constructor) : base(engine)
  31. {
  32. _prototype = objectPrototype;
  33. _realm = realm;
  34. _constructor = constructor;
  35. }
  36. protected override void Initialize()
  37. {
  38. const PropertyFlag lengthFlags = PropertyFlag.Configurable;
  39. const PropertyFlag propertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
  40. var properties = new PropertyDictionary(31, false)
  41. {
  42. ["buffer"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get buffer", Buffer, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  43. ["byteLength"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get byteLength", ByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  44. ["byteOffset"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(Engine, "get byteOffset", ByteOffset, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  45. ["length"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(Engine, "get length", GetLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
  46. ["constructor"] = new(_constructor, PropertyFlag.NonEnumerable),
  47. ["copyWithin"] = new(new ClrFunctionInstance(Engine, "copyWithin", CopyWithin, 2, PropertyFlag.Configurable), propertyFlags),
  48. ["entries"] = new(new ClrFunctionInstance(Engine, "entries", Entries, 0, PropertyFlag.Configurable), propertyFlags),
  49. ["every"] = new(new ClrFunctionInstance(Engine, "every", Every, 1, PropertyFlag.Configurable), propertyFlags),
  50. ["fill"] = new(new ClrFunctionInstance(Engine, "fill", Fill, 1, PropertyFlag.Configurable), propertyFlags),
  51. ["filter"] = new(new ClrFunctionInstance(Engine, "filter", Filter, 1, PropertyFlag.Configurable), propertyFlags),
  52. ["find"] = new(new ClrFunctionInstance(Engine, "find", Find, 1, PropertyFlag.Configurable), propertyFlags),
  53. ["findIndex"] = new(new ClrFunctionInstance(Engine, "findIndex", FindIndex, 1, PropertyFlag.Configurable), propertyFlags),
  54. ["forEach"] = new(new ClrFunctionInstance(Engine, "forEach", ForEach, 1, PropertyFlag.Configurable), propertyFlags),
  55. ["includes"] = new(new ClrFunctionInstance(Engine, "includes", Includes, 1, PropertyFlag.Configurable), propertyFlags),
  56. ["indexOf"] = new(new ClrFunctionInstance(Engine, "indexOf", IndexOf, 1, PropertyFlag.Configurable), propertyFlags),
  57. ["join"] = new(new ClrFunctionInstance(Engine, "join", Join, 1, PropertyFlag.Configurable), propertyFlags),
  58. ["keys"] = new(new ClrFunctionInstance(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
  59. ["lastIndexOf"] = new(new ClrFunctionInstance(Engine, "lastIndexOf", LastIndexOf, 1, PropertyFlag.Configurable), propertyFlags),
  60. ["map"] = new(new ClrFunctionInstance(Engine, "map", Map, 1, PropertyFlag.Configurable), propertyFlags),
  61. ["reduce"] = new(new ClrFunctionInstance(Engine, "reduce", Reduce, 1, PropertyFlag.Configurable), propertyFlags),
  62. ["reduceRight"] = new(new ClrFunctionInstance(Engine, "reduceRight", ReduceRight, 1, PropertyFlag.Configurable), propertyFlags),
  63. ["reverse"] = new(new ClrFunctionInstance(Engine, "reverse", Reverse, 0, PropertyFlag.Configurable), propertyFlags),
  64. ["set"] = new(new ClrFunctionInstance(Engine, "set", Set, 1, PropertyFlag.Configurable), propertyFlags),
  65. ["slice"] = new(new ClrFunctionInstance(Engine, "slice", Slice, 2, PropertyFlag.Configurable), propertyFlags),
  66. ["some"] = new(new ClrFunctionInstance(Engine, "some", Some, 1, PropertyFlag.Configurable), propertyFlags),
  67. ["sort"] = new(new ClrFunctionInstance(Engine, "sort", Sort, 1, PropertyFlag.Configurable), propertyFlags),
  68. ["subarray"] = new(new ClrFunctionInstance(Engine, "subarray", Subarray, 2, PropertyFlag.Configurable), propertyFlags),
  69. ["toLocaleString"] = new(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0, PropertyFlag.Configurable), propertyFlags),
  70. ["toString"] = new(new ClrFunctionInstance(Engine, "toLocaleString", _realm.Intrinsics.Array.PrototypeObject.ToString, 0, PropertyFlag.Configurable), propertyFlags),
  71. ["values"] = new(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags)
  72. };
  73. SetProperties(properties);
  74. _originalIteratorFunction = new ClrFunctionInstance(Engine, "iterator", Values, 1);
  75. var symbols = new SymbolDictionary(2)
  76. {
  77. [GlobalSymbolRegistry.Iterator] = new(_originalIteratorFunction, propertyFlags),
  78. [GlobalSymbolRegistry.ToStringTag] = new GetSetPropertyDescriptor(
  79. new ClrFunctionInstance(Engine, "get [Symbol.toStringTag]", ToStringTag, 0, PropertyFlag.Configurable),
  80. Undefined,
  81. PropertyFlag.Configurable)
  82. };
  83. SetSymbols(symbols);
  84. }
  85. /// <summary>
  86. /// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.buffer
  87. /// </summary>
  88. private JsValue Buffer(JsValue thisObj, JsValue[] arguments)
  89. {
  90. var o = thisObj as TypedArrayInstance;
  91. if (o is null)
  92. {
  93. ExceptionHelper.ThrowTypeError(_realm);
  94. }
  95. return o._viewedArrayBuffer;
  96. }
  97. /// <summary>
  98. /// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.bytelength
  99. /// </summary>
  100. private JsValue ByteLength(JsValue thisObj, JsValue[] arguments)
  101. {
  102. var o = thisObj as TypedArrayInstance;
  103. if (o is null)
  104. {
  105. ExceptionHelper.ThrowTypeError(_realm);
  106. }
  107. if (o._viewedArrayBuffer.IsDetachedBuffer)
  108. {
  109. return JsNumber.PositiveZero;
  110. }
  111. return JsNumber.Create(o._byteLength);
  112. }
  113. /// <summary>
  114. /// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.byteoffset
  115. /// </summary>
  116. private JsValue ByteOffset(JsValue thisObj, JsValue[] arguments)
  117. {
  118. var o = thisObj as TypedArrayInstance;
  119. if (o is null)
  120. {
  121. ExceptionHelper.ThrowTypeError(_realm);
  122. }
  123. if (o._viewedArrayBuffer.IsDetachedBuffer)
  124. {
  125. return JsNumber.PositiveZero;
  126. }
  127. return JsNumber.Create(o._byteOffset);
  128. }
  129. /// <summary>
  130. /// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.length
  131. /// </summary>
  132. private JsValue GetLength(JsValue thisObj, JsValue[] arguments)
  133. {
  134. var o = thisObj as TypedArrayInstance;
  135. if (o is null)
  136. {
  137. ExceptionHelper.ThrowTypeError(_realm);
  138. }
  139. var buffer = o._viewedArrayBuffer;
  140. if (buffer.IsDetachedBuffer)
  141. {
  142. return JsNumber.PositiveZero;
  143. }
  144. return JsNumber.Create(o.Length);
  145. }
  146. /// <summary>
  147. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
  148. /// </summary>
  149. private JsValue CopyWithin(JsValue thisObj, JsValue[] arguments)
  150. {
  151. var o = thisObj.ValidateTypedArray(_realm);
  152. var target = arguments.At(0);
  153. var start = arguments.At(1);
  154. var end = arguments.At(2);
  155. long len = o.Length;
  156. var relativeTarget = TypeConverter.ToIntegerOrInfinity(target);
  157. long to;
  158. if (double.IsNegativeInfinity(relativeTarget))
  159. {
  160. to = 0;
  161. }
  162. else if (relativeTarget < 0)
  163. {
  164. to = (long) System.Math.Max(len + relativeTarget, 0);
  165. }
  166. else
  167. {
  168. to = (long) System.Math.Min(relativeTarget, len);
  169. }
  170. var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
  171. long from;
  172. if (double.IsNegativeInfinity(relativeStart))
  173. {
  174. from = 0;
  175. }
  176. else if (relativeStart < 0)
  177. {
  178. from = (long) System.Math.Max(len + relativeStart, 0);
  179. }
  180. else
  181. {
  182. from = (long) System.Math.Min(relativeStart, len);
  183. }
  184. var relativeEnd = end.IsUndefined()
  185. ? len
  186. : TypeConverter.ToIntegerOrInfinity(end);
  187. long final;
  188. if (double.IsNegativeInfinity(relativeEnd))
  189. {
  190. final = 0;
  191. }
  192. else if (relativeEnd < 0)
  193. {
  194. final = (long) System.Math.Max(len + relativeEnd, 0);
  195. }
  196. else
  197. {
  198. final = (long) System.Math.Min(relativeEnd, len);
  199. }
  200. var count = System.Math.Min(final - from, len - to);
  201. if (count > 0)
  202. {
  203. var buffer = o._viewedArrayBuffer;
  204. buffer.AssertNotDetached();
  205. var elementSize = o._arrayElementType.GetElementSize();
  206. var byteOffset = o._byteOffset;
  207. var toByteIndex = to * elementSize + byteOffset;
  208. var fromByteIndex = from * elementSize + byteOffset;
  209. var countBytes = count * elementSize;
  210. int direction;
  211. if (fromByteIndex < toByteIndex && toByteIndex < fromByteIndex + countBytes)
  212. {
  213. direction = -1;
  214. fromByteIndex = fromByteIndex + countBytes - 1;
  215. toByteIndex = toByteIndex + countBytes - 1;
  216. }
  217. else
  218. {
  219. direction = 1;
  220. }
  221. while (countBytes > 0)
  222. {
  223. var value = buffer.GetValueFromBuffer((int) fromByteIndex, TypedArrayElementType.Uint8, true, ArrayBufferOrder.Unordered);
  224. buffer.SetValueInBuffer((int) toByteIndex, TypedArrayElementType.Uint8, value, true, ArrayBufferOrder.Unordered);
  225. fromByteIndex += direction;
  226. toByteIndex += direction;
  227. countBytes--;
  228. }
  229. }
  230. return o;
  231. }
  232. /// <summary>
  233. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
  234. /// </summary>
  235. private JsValue Entries(JsValue thisObj, JsValue[] arguments)
  236. {
  237. var o = thisObj.ValidateTypedArray(_realm);
  238. return _realm.Intrinsics.ArrayIteratorPrototype.Construct(o, ArrayIteratorType.KeyAndValue);
  239. }
  240. /// <summary>
  241. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
  242. /// </summary>
  243. private JsValue Every(JsValue thisObj, JsValue[] arguments)
  244. {
  245. var o = thisObj.ValidateTypedArray(_realm);
  246. var len = o.Length;
  247. if (len == 0)
  248. {
  249. return JsBoolean.True;
  250. }
  251. var predicate = GetCallable(arguments.At(0));
  252. var thisArg = arguments.At(1);
  253. var args = _engine._jsValueArrayPool.RentArray(3);
  254. args[2] = o;
  255. for (var k = 0; k < len; k++)
  256. {
  257. args[0] = o[k];
  258. args[1] = k;
  259. if (!TypeConverter.ToBoolean(predicate.Call(thisArg, args)))
  260. {
  261. return JsBoolean.False;
  262. }
  263. }
  264. _engine._jsValueArrayPool.ReturnArray(args);
  265. return JsBoolean.True;
  266. }
  267. /// <summary>
  268. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
  269. /// </summary>
  270. private JsValue Fill(JsValue thisObj, JsValue[] arguments)
  271. {
  272. var o = thisObj.ValidateTypedArray(_realm);
  273. var start = arguments.At(1);
  274. var end = arguments.At(2);
  275. var value = o._contentType == TypedArrayContentType.BigInt
  276. ? TypeConverter.ToBigInt(arguments.At(0))
  277. : TypeConverter.ToNumber(arguments.At(0));
  278. var len = o.Length;
  279. int k;
  280. var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
  281. if (double.IsNegativeInfinity(relativeStart))
  282. {
  283. k = 0;
  284. }
  285. else if (relativeStart < 0)
  286. {
  287. k = (int) System.Math.Max(len + relativeStart, 0);
  288. }
  289. else
  290. {
  291. k = (int) System.Math.Min(relativeStart, len);
  292. }
  293. uint final;
  294. var relativeEnd = end.IsUndefined() ? len : TypeConverter.ToIntegerOrInfinity(end);
  295. if (double.IsNegativeInfinity(relativeEnd))
  296. {
  297. final = 0;
  298. }
  299. else if (relativeEnd < 0)
  300. {
  301. final = (uint) System.Math.Max(len + relativeEnd, 0);
  302. }
  303. else
  304. {
  305. final = (uint) System.Math.Min(relativeEnd, len);
  306. }
  307. o._viewedArrayBuffer.AssertNotDetached();
  308. for (var i = k; i < final; ++i)
  309. {
  310. o[i] = value;
  311. }
  312. return thisObj;
  313. }
  314. /// <summary>
  315. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
  316. /// </summary>
  317. private JsValue Filter(JsValue thisObj, JsValue[] arguments)
  318. {
  319. var callbackfn = GetCallable(arguments.At(0));
  320. var thisArg = arguments.At(1);
  321. var o = thisObj.ValidateTypedArray(_realm);
  322. var len = o.Length;
  323. var kept = new List<JsValue>();
  324. var captured = 0;
  325. var args = _engine._jsValueArrayPool.RentArray(3);
  326. args[2] = o;
  327. for (var k = 0; k < len; k++)
  328. {
  329. var kValue = o[k];
  330. args[0] = kValue;
  331. args[1] = k;
  332. var selected = callbackfn.Call(thisArg, args);
  333. if (TypeConverter.ToBoolean(selected))
  334. {
  335. kept.Add(kValue);
  336. captured++;
  337. }
  338. }
  339. _engine._jsValueArrayPool.ReturnArray(args);
  340. var a = _realm.Intrinsics.TypedArray.TypedArraySpeciesCreate(o, new JsValue[] { captured });
  341. for (var n = 0; n < captured; ++n)
  342. {
  343. a[n] = kept[n];
  344. }
  345. return a;
  346. }
  347. /// <summary>
  348. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
  349. /// </summary>
  350. private JsValue Find(JsValue thisObj, JsValue[] arguments)
  351. {
  352. return DoFind(thisObj, arguments).Value;
  353. }
  354. /// <summary>
  355. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
  356. /// </summary>
  357. private JsValue FindIndex(JsValue thisObj, JsValue[] arguments)
  358. {
  359. return DoFind(thisObj, arguments).Key;
  360. }
  361. private KeyValuePair<JsValue, JsValue> DoFind(JsValue thisObj, JsValue[] arguments)
  362. {
  363. var o = thisObj.ValidateTypedArray(_realm);
  364. var len = o.Length;
  365. var predicate = GetCallable(arguments.At(0));
  366. var thisArg = arguments.At(1);
  367. var args = _engine._jsValueArrayPool.RentArray(3);
  368. args[2] = o;
  369. for (var k = 0; k < len; k++)
  370. {
  371. var kNumber = JsNumber.Create(k);
  372. var kValue = o[k];
  373. args[0] = kValue;
  374. args[1] = kNumber;
  375. if (TypeConverter.ToBoolean(predicate.Call(thisArg, args)))
  376. {
  377. return new KeyValuePair<JsValue, JsValue>(kNumber, kValue);
  378. }
  379. }
  380. return new KeyValuePair<JsValue, JsValue>(JsNumber.IntegerNegativeOne, Undefined);
  381. }
  382. /// <summary>
  383. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
  384. /// </summary>
  385. private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
  386. {
  387. var callbackfn = GetCallable(arguments.At(0));
  388. var thisArg = arguments.At(1);
  389. var o = thisObj.ValidateTypedArray(_realm);
  390. var len = o.Length;
  391. var args = _engine._jsValueArrayPool.RentArray(3);
  392. args[2] = o;
  393. for (var k = 0; k < len; k++)
  394. {
  395. var kValue = o[k];
  396. args[0] = kValue;
  397. args[1] = k;
  398. callbackfn.Call(thisArg, args);
  399. }
  400. _engine._jsValueArrayPool.ReturnArray(args);
  401. return Undefined;
  402. }
  403. /// <summary>
  404. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
  405. /// </summary>
  406. private JsValue Includes(JsValue thisObj, JsValue[] arguments)
  407. {
  408. var o = thisObj.ValidateTypedArray(_realm);
  409. var len = o.Length;
  410. if (len == 0)
  411. {
  412. return false;
  413. }
  414. var searchElement = arguments.At(0);
  415. var fromIndex = arguments.At(1, 0);
  416. var n = TypeConverter.ToIntegerOrInfinity(fromIndex);
  417. if (double.IsPositiveInfinity(n))
  418. {
  419. return JsBoolean.False;
  420. }
  421. else if (double.IsNegativeInfinity(n))
  422. {
  423. n = 0;
  424. }
  425. long k;
  426. if (n >= 0)
  427. {
  428. k = (long) n;
  429. }
  430. else
  431. {
  432. k = (long) (len + n);
  433. if (k < 0)
  434. {
  435. k = 0;
  436. }
  437. }
  438. while (k < len)
  439. {
  440. var value = o[(int) k];
  441. if (JintBinaryExpression.SameValueZero(value, searchElement))
  442. {
  443. return JsBoolean.True;
  444. }
  445. k++;
  446. }
  447. return JsBoolean.False;
  448. }
  449. /// <summary>
  450. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
  451. /// </summary>
  452. private JsValue IndexOf(JsValue thisObj, JsValue[] arguments)
  453. {
  454. var searchElement = arguments.At(0);
  455. var fromIndex = arguments.At(1);
  456. var o = thisObj.ValidateTypedArray(_realm);
  457. var len = o.Length;
  458. if (len == 0)
  459. {
  460. return JsNumber.IntegerNegativeOne;
  461. }
  462. var n = TypeConverter.ToIntegerOrInfinity(fromIndex);
  463. if (double.IsPositiveInfinity(n))
  464. {
  465. return JsNumber.IntegerNegativeOne;
  466. }
  467. else if (double.IsNegativeInfinity(n))
  468. {
  469. n = 0;
  470. }
  471. long k;
  472. if (n >= 0)
  473. {
  474. k = (long) n;
  475. }
  476. else
  477. {
  478. k = (long) (len + n);
  479. if (k < 0)
  480. {
  481. k = 0;
  482. }
  483. }
  484. for (; k < len; k++)
  485. {
  486. var kPresent = o.HasProperty(k);
  487. if (kPresent)
  488. {
  489. var elementK = o[(int) k];
  490. var same = JintBinaryExpression.StrictlyEqual(elementK, searchElement);
  491. if (same)
  492. {
  493. return k;
  494. }
  495. }
  496. }
  497. return JsNumber.IntegerNegativeOne;
  498. }
  499. /// <summary>
  500. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
  501. /// </summary>
  502. private JsValue Join(JsValue thisObj, JsValue[] arguments)
  503. {
  504. var o = thisObj.ValidateTypedArray(_realm);
  505. var separator = arguments.At(0);
  506. var len = o.Length;
  507. var sep = TypeConverter.ToString(separator.IsUndefined() ? JsString.CommaString : separator);
  508. // as per the spec, this has to be called after ToString(separator)
  509. if (len == 0)
  510. {
  511. return JsString.Empty;
  512. }
  513. static string StringFromJsValue(JsValue value)
  514. {
  515. return value.IsUndefined()
  516. ? ""
  517. : TypeConverter.ToString(value);
  518. }
  519. var s = StringFromJsValue(o[0]);
  520. if (len == 1)
  521. {
  522. return s;
  523. }
  524. using var sb = StringBuilderPool.Rent();
  525. sb.Builder.Append(s);
  526. for (var k = 1; k < len; k++)
  527. {
  528. sb.Builder.Append(sep);
  529. sb.Builder.Append(StringFromJsValue(o[k]));
  530. }
  531. return sb.ToString();
  532. }
  533. /// <summary>
  534. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
  535. /// </summary>
  536. private JsValue Keys(JsValue thisObj, JsValue[] arguments)
  537. {
  538. var o = thisObj.ValidateTypedArray(_realm);
  539. return _realm.Intrinsics.ArrayIteratorPrototype.Construct(o, ArrayIteratorType.Key);
  540. }
  541. /// <summary>
  542. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
  543. /// </summary>
  544. private JsValue LastIndexOf(JsValue thisObj, JsValue[] arguments)
  545. {
  546. var searchElement = arguments.At(0);
  547. var o = thisObj.ValidateTypedArray(_realm);
  548. var len = o.Length;
  549. if (len == 0)
  550. {
  551. return JsNumber.IntegerNegativeOne;
  552. }
  553. var fromIndex = arguments.At(1, len - 1);
  554. var n = TypeConverter.ToIntegerOrInfinity(fromIndex);
  555. if (double.IsNegativeInfinity(n))
  556. {
  557. return JsNumber.IntegerNegativeOne;
  558. }
  559. long k;
  560. if (n >= 0)
  561. {
  562. k = (long) System.Math.Min(n, len - 1);
  563. }
  564. else
  565. {
  566. k = (long) (len + n);
  567. }
  568. for (; k >= 0; k--)
  569. {
  570. var kPresent = o.HasProperty(k);
  571. if (kPresent)
  572. {
  573. var elementK = o[(int) k];
  574. var same = JintBinaryExpression.StrictlyEqual(elementK, searchElement);
  575. if (same)
  576. {
  577. return k;
  578. }
  579. }
  580. }
  581. return JsNumber.IntegerNegativeOne;
  582. }
  583. /// <summary>
  584. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
  585. /// </summary>
  586. private ObjectInstance Map(JsValue thisObj, JsValue[] arguments)
  587. {
  588. var o = thisObj.ValidateTypedArray(_realm);
  589. var len = o.Length;
  590. var thisArg = arguments.At(1);
  591. var callable = GetCallable(arguments.At(0));
  592. var a = _realm.Intrinsics.TypedArray.TypedArraySpeciesCreate(o, new JsValue[] { len });
  593. var args = _engine._jsValueArrayPool.RentArray(3);
  594. args[2] = o;
  595. for (var k = 0; k < len; k++)
  596. {
  597. args[0] = o[k];
  598. args[1] = k;
  599. var mappedValue = callable.Call(thisArg, args);
  600. a[k] = mappedValue;
  601. }
  602. _engine._jsValueArrayPool.ReturnArray(args);
  603. return a;
  604. }
  605. /// <summary>
  606. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
  607. /// </summary>
  608. private JsValue Reduce(JsValue thisObj, JsValue[] arguments)
  609. {
  610. var callbackfn = GetCallable(arguments.At(0));
  611. var initialValue = arguments.At(1);
  612. var o = thisObj.ValidateTypedArray(_realm);
  613. var len = o.Length;
  614. if (len == 0 && arguments.Length < 2)
  615. {
  616. ExceptionHelper.ThrowTypeError(_realm);
  617. }
  618. var k = 0;
  619. var accumulator = Undefined;
  620. if (!initialValue.IsUndefined())
  621. {
  622. accumulator = initialValue;
  623. }
  624. else
  625. {
  626. accumulator = o[k];
  627. k++;
  628. }
  629. var args = _engine._jsValueArrayPool.RentArray(4);
  630. args[3] = o;
  631. while (k < len)
  632. {
  633. var kValue = o[k];
  634. args[0] = accumulator;
  635. args[1] = kValue;
  636. args[2] = k;
  637. accumulator = callbackfn.Call(Undefined, args);
  638. k++;
  639. }
  640. _engine._jsValueArrayPool.ReturnArray(args);
  641. return accumulator;
  642. }
  643. /// <summary>
  644. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
  645. /// </summary>
  646. private JsValue ReduceRight(JsValue thisObj, JsValue[] arguments)
  647. {
  648. var callbackfn = GetCallable(arguments.At(0));
  649. var initialValue = arguments.At(1);
  650. var o = thisObj.ValidateTypedArray(_realm);
  651. var len = (int) o.Length;
  652. if (len == 0 && arguments.Length < 2)
  653. {
  654. ExceptionHelper.ThrowTypeError(_realm);
  655. }
  656. var k = len - 1;
  657. JsValue accumulator;
  658. if (arguments.Length > 1)
  659. {
  660. accumulator = initialValue;
  661. }
  662. else
  663. {
  664. accumulator = o[k];
  665. k--;
  666. }
  667. var jsValues = _engine._jsValueArrayPool.RentArray(4);
  668. jsValues[3] = o;
  669. for (; k >= 0; k--)
  670. {
  671. jsValues[0] = accumulator;
  672. jsValues[1] = o[k];
  673. jsValues[2] = k;
  674. accumulator = callbackfn.Call(Undefined, jsValues);
  675. }
  676. _engine._jsValueArrayPool.ReturnArray(jsValues);
  677. return accumulator;
  678. }
  679. /// <summary>
  680. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
  681. /// </summary>
  682. private ObjectInstance Reverse(JsValue thisObj, JsValue[] arguments)
  683. {
  684. var o = thisObj.ValidateTypedArray(_realm);
  685. var len = (int) o.Length;
  686. var middle = (int) System.Math.Floor(len / 2.0);
  687. var lower = 0;
  688. while (lower != middle)
  689. {
  690. var upper = len - lower - 1;
  691. var lowerValue = o[lower];
  692. var upperValue = o[upper];
  693. o[lower] = upperValue;
  694. o[upper] = lowerValue;
  695. lower++;
  696. }
  697. return o;
  698. }
  699. /// <summary>
  700. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
  701. /// </summary>
  702. private JsValue Set(JsValue thisObj, JsValue[] arguments)
  703. {
  704. var target = thisObj as TypedArrayInstance;
  705. if (target is null)
  706. {
  707. ExceptionHelper.ThrowTypeError(_realm);
  708. }
  709. var source = arguments.At(0);
  710. var offset = arguments.At(1);
  711. var targetOffset = TypeConverter.ToIntegerOrInfinity(offset);
  712. if (targetOffset < 0)
  713. {
  714. ExceptionHelper.ThrowRangeError(_realm, "Invalid offset");
  715. }
  716. if (source is TypedArrayInstance typedArrayInstance)
  717. {
  718. SetTypedArrayFromTypedArray(target, targetOffset, typedArrayInstance);
  719. }
  720. else
  721. {
  722. SetTypedArrayFromArrayLike(target, targetOffset, source);
  723. }
  724. return Undefined;
  725. }
  726. /// <summary>
  727. /// https://tc39.es/ecma262/#sec-settypedarrayfromtypedarray
  728. /// </summary>
  729. private void SetTypedArrayFromTypedArray(TypedArrayInstance target, double targetOffset, TypedArrayInstance source)
  730. {
  731. var targetBuffer = target._viewedArrayBuffer;
  732. targetBuffer.AssertNotDetached();
  733. var targetLength = target._arrayLength;
  734. var srcBuffer = source._viewedArrayBuffer;
  735. srcBuffer.AssertNotDetached();
  736. var targetType = target._arrayElementType;
  737. var targetElementSize = targetType.GetElementSize();
  738. var targetByteOffset = target._byteOffset;
  739. var srcType = source._arrayElementType;
  740. var srcElementSize = srcType.GetElementSize();
  741. var srcLength = source._arrayLength;
  742. var srcByteOffset = source._byteOffset;
  743. if (double.IsNegativeInfinity(targetOffset))
  744. {
  745. ExceptionHelper.ThrowRangeError(_realm, "Invalid target offset");
  746. }
  747. if (srcLength + targetOffset > targetLength)
  748. {
  749. ExceptionHelper.ThrowRangeError(_realm, "Invalid target offset");
  750. }
  751. if (target._contentType != source._contentType)
  752. {
  753. ExceptionHelper.ThrowTypeError(_realm, "Content type mismatch");
  754. }
  755. bool same;
  756. if (srcBuffer.IsSharedArrayBuffer && targetBuffer.IsSharedArrayBuffer)
  757. {
  758. // a. If srcBuffer.[[ArrayBufferData]] and targetBuffer.[[ArrayBufferData]] are the same Shared Data Block values, let same be true; else let same be false.
  759. ExceptionHelper.ThrowNotImplementedException("SharedBuffer not implemented");
  760. same = false;
  761. }
  762. else
  763. {
  764. same = SameValue(srcBuffer, targetBuffer);
  765. }
  766. int srcByteIndex;
  767. if (same)
  768. {
  769. var srcByteLength = source._byteLength;
  770. srcBuffer = srcBuffer.CloneArrayBuffer(_realm.Intrinsics.ArrayBuffer, srcByteOffset, srcByteLength, _realm.Intrinsics.ArrayBuffer);
  771. // %ArrayBuffer% is used to clone srcBuffer because is it known to not have any observable side-effects.
  772. srcByteIndex = 0;
  773. }
  774. else
  775. {
  776. srcByteIndex = srcByteOffset;
  777. }
  778. var targetByteIndex = (int) (targetOffset * targetElementSize + targetByteOffset);
  779. var limit = targetByteIndex + targetElementSize * srcLength;
  780. if (srcType == targetType)
  781. {
  782. // NOTE: If srcType and targetType are the same, the transfer must be performed in a manner that preserves the bit-level encoding of the source data.
  783. while (targetByteIndex < limit)
  784. {
  785. var value = srcBuffer.GetValueFromBuffer(srcByteIndex, TypedArrayElementType.Uint8, true, ArrayBufferOrder.Unordered);
  786. targetBuffer.SetValueInBuffer(targetByteIndex, TypedArrayElementType.Uint8, value, true, ArrayBufferOrder.Unordered);
  787. srcByteIndex += 1;
  788. targetByteIndex += 1;
  789. }
  790. }
  791. else
  792. {
  793. while (targetByteIndex < limit)
  794. {
  795. var value = srcBuffer.GetValueFromBuffer(srcByteIndex, srcType, true, ArrayBufferOrder.Unordered);
  796. targetBuffer.SetValueInBuffer(targetByteIndex, targetType, value, true, ArrayBufferOrder.Unordered);
  797. srcByteIndex += srcElementSize;
  798. targetByteIndex += targetElementSize;
  799. }
  800. }
  801. }
  802. /// <summary>
  803. /// https://tc39.es/ecma262/#sec-settypedarrayfromarraylike
  804. /// </summary>
  805. private void SetTypedArrayFromArrayLike(TypedArrayInstance target, double targetOffset, JsValue source)
  806. {
  807. var targetBuffer = target._viewedArrayBuffer;
  808. targetBuffer.AssertNotDetached();
  809. var targetLength = target._arrayLength;
  810. var targetElementSize = target._arrayElementType.GetElementSize();
  811. var targetType = target._arrayElementType;
  812. var targetByteOffset = target._byteOffset;
  813. var src = ArrayOperations.For(TypeConverter.ToObject(_realm, source));
  814. var srcLength = src.GetLength();
  815. if (double.IsNegativeInfinity(targetOffset))
  816. {
  817. ExceptionHelper.ThrowRangeError(_realm, "Invalid target offset");
  818. }
  819. if (srcLength + targetOffset > targetLength)
  820. {
  821. ExceptionHelper.ThrowRangeError(_realm, "Invalid target offset");
  822. }
  823. var targetByteIndex = targetOffset * targetElementSize + targetByteOffset;
  824. ulong k = 0;
  825. var limit = targetByteIndex + targetElementSize * srcLength;
  826. while (targetByteIndex < limit)
  827. {
  828. double value;
  829. if (target._contentType == TypedArrayContentType.BigInt)
  830. {
  831. value = TypeConverter.ToBigInt(src.Get(k));
  832. }
  833. else
  834. {
  835. value = TypeConverter.ToNumber(src.Get(k));
  836. }
  837. targetBuffer.AssertNotDetached();
  838. targetBuffer.SetValueInBuffer((int) targetByteIndex, targetType, value, true, ArrayBufferOrder.Unordered);
  839. k++;
  840. targetByteIndex += targetElementSize;
  841. }
  842. }
  843. /// <summary>
  844. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
  845. /// </summary>
  846. private JsValue Slice(JsValue thisObj, JsValue[] arguments)
  847. {
  848. var start = arguments.At(0);
  849. var end = arguments.At(1);
  850. var o = thisObj.ValidateTypedArray(_realm);
  851. long len = o.Length;
  852. var relativeStart = TypeConverter.ToIntegerOrInfinity(start);
  853. int k;
  854. if (double.IsNegativeInfinity(relativeStart))
  855. {
  856. k = 0;
  857. }
  858. else if (relativeStart < 0)
  859. {
  860. k = (int) System.Math.Max(len + relativeStart, 0);
  861. }
  862. else
  863. {
  864. k = (int) System.Math.Min(relativeStart, len);
  865. }
  866. var relativeEnd = end.IsUndefined()
  867. ? len
  868. : TypeConverter.ToIntegerOrInfinity(end);
  869. long final;
  870. if (double.IsNegativeInfinity(relativeEnd))
  871. {
  872. final = 0;
  873. }
  874. else if (relativeEnd < 0)
  875. {
  876. final = (long) System.Math.Max(len + relativeEnd, 0);
  877. }
  878. else
  879. {
  880. final = (long) System.Math.Min(relativeEnd, len);
  881. }
  882. var count = System.Math.Max(final - k, 0);
  883. var a = _realm.Intrinsics.TypedArray.TypedArraySpeciesCreate(o, new JsValue[] { count });
  884. if (count > 0)
  885. {
  886. o._viewedArrayBuffer.AssertNotDetached();
  887. var srcType = o._arrayElementType;
  888. var targetType = a._arrayElementType;
  889. if (srcType != targetType)
  890. {
  891. var n = 0;
  892. while (k < final)
  893. {
  894. var kValue = o[k];
  895. a[n] = kValue;
  896. k++;
  897. n++;
  898. }
  899. }
  900. else
  901. {
  902. var srcBuffer = o._viewedArrayBuffer;
  903. var targetBuffer = a._viewedArrayBuffer;
  904. var elementSize = srcType.GetElementSize();
  905. var srcByteOffset = o._byteOffset;
  906. var targetByteIndex = a._byteOffset;
  907. var srcByteIndex = (int) k * elementSize + srcByteOffset;
  908. var limit = targetByteIndex + count * elementSize;
  909. while (targetByteIndex < limit)
  910. {
  911. var value = (JsNumber) srcBuffer.GetValueFromBuffer(srcByteIndex, TypedArrayElementType.Uint8, true, ArrayBufferOrder.Unordered);
  912. targetBuffer.SetValueInBuffer(targetByteIndex, TypedArrayElementType.Uint8, value._value, true, ArrayBufferOrder.Unordered);
  913. srcByteIndex++;
  914. targetByteIndex++;
  915. }
  916. }
  917. }
  918. return a;
  919. }
  920. /// <summary>
  921. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
  922. /// </summary>
  923. private JsValue Some(JsValue thisObj, JsValue[] arguments)
  924. {
  925. var o = thisObj.ValidateTypedArray(_realm);
  926. var len = o.Length;
  927. var callbackfn = GetCallable(arguments.At(0));
  928. var thisArg = arguments.At(1);
  929. var args = _engine._jsValueArrayPool.RentArray(3);
  930. args[2] = o;
  931. for (var k = 0; k < len; k++)
  932. {
  933. args[0] = o[k];
  934. args[1] = k;
  935. if (TypeConverter.ToBoolean(callbackfn.Call(thisArg, args)))
  936. {
  937. return JsBoolean.True;
  938. }
  939. }
  940. _engine._jsValueArrayPool.ReturnArray(args);
  941. return JsBoolean.False;
  942. }
  943. /// <summary>
  944. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
  945. /// </summary>
  946. private JsValue Sort(JsValue thisObj, JsValue[] arguments)
  947. {
  948. /*
  949. * %TypedArray%.prototype.sort is a distinct function that, except as described below,
  950. * implements the same requirements as those of Array.prototype.sort as defined in 23.1.3.27.
  951. * The implementation of the %TypedArray%.prototype.sort specification may be optimized with the knowledge that the this value is
  952. * an object that has a fixed length and whose integer-indexed properties are not sparse.
  953. */
  954. var obj = thisObj.ValidateTypedArray(_realm);
  955. var buffer = obj._viewedArrayBuffer;
  956. var len = obj.Length;
  957. var compareArg = arguments.At(0);
  958. ICallable compareFn = null;
  959. if (!compareArg.IsUndefined())
  960. {
  961. compareFn = GetCallable(compareArg);
  962. }
  963. if (len <= 1)
  964. {
  965. return obj;
  966. }
  967. JsValue[] array;
  968. try
  969. {
  970. var comparer = TypedArrayComparer.WithFunction(buffer, compareFn);
  971. var operations = ArrayOperations.For(obj);
  972. array = operations
  973. .OrderBy(x => x, comparer)
  974. .ToArray();
  975. }
  976. catch (InvalidOperationException e)
  977. {
  978. throw e.InnerException ?? e;
  979. }
  980. for (var i = 0; i < (uint) array.Length; ++i)
  981. {
  982. obj[i] = array[i];
  983. }
  984. return obj;
  985. }
  986. /// <summary>
  987. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
  988. /// </summary>
  989. private JsValue Subarray(JsValue thisObj, JsValue[] arguments)
  990. {
  991. var o = thisObj as TypedArrayInstance;
  992. if (o is null)
  993. {
  994. ExceptionHelper.ThrowTypeError(_realm);
  995. }
  996. var begin = arguments.At(0);
  997. var end = arguments.At(1);
  998. var buffer = o._viewedArrayBuffer;
  999. var srcLength = o.Length;
  1000. var relativeBegin = TypeConverter.ToIntegerOrInfinity(begin);
  1001. double beginIndex;
  1002. if (double.IsNegativeInfinity(relativeBegin))
  1003. {
  1004. beginIndex = 0;
  1005. }
  1006. else if (relativeBegin < 0)
  1007. {
  1008. beginIndex = System.Math.Max(srcLength + relativeBegin, 0);
  1009. }
  1010. else
  1011. {
  1012. beginIndex = System.Math.Min(relativeBegin, srcLength);
  1013. }
  1014. double relativeEnd;
  1015. if (end.IsUndefined())
  1016. {
  1017. relativeEnd = srcLength;
  1018. }
  1019. else
  1020. {
  1021. relativeEnd = TypeConverter.ToIntegerOrInfinity(end);
  1022. }
  1023. double endIndex;
  1024. if (double.IsNegativeInfinity(relativeEnd))
  1025. {
  1026. endIndex = 0;
  1027. }
  1028. else if (relativeEnd < 0)
  1029. {
  1030. endIndex = System.Math.Max(srcLength + relativeEnd, 0);
  1031. }
  1032. else
  1033. {
  1034. endIndex = System.Math.Min(relativeEnd, srcLength);
  1035. }
  1036. var newLength = System.Math.Max(endIndex - beginIndex, 0);
  1037. var elementSize = o._arrayElementType.GetElementSize();
  1038. var srcByteOffset = o._byteOffset;
  1039. var beginByteOffset = srcByteOffset + beginIndex * elementSize;
  1040. var argumentsList = new JsValue[] { buffer, beginByteOffset, newLength };
  1041. return _realm.Intrinsics.TypedArray.TypedArraySpeciesCreate(o, argumentsList);
  1042. }
  1043. /// <summary>
  1044. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
  1045. /// </summary>
  1046. private JsValue ToLocaleString(JsValue thisObj, JsValue[] arguments)
  1047. {
  1048. /*
  1049. * %TypedArray%.prototype.toLocaleString is a distinct function that implements the same algorithm as Array.prototype.toLocaleString
  1050. * as defined in 23.1.3.29 except that the this value's [[ArrayLength]] internal slot is accessed in place of performing
  1051. * a [[Get]] of "length". The implementation of the algorithm may be optimized with the knowledge that the this value is an object
  1052. * that has a fixed length and whose integer-indexed properties are not sparse. However, such optimization must not introduce
  1053. * any observable changes in the specified behaviour of the algorithm.
  1054. */
  1055. var array = thisObj.ValidateTypedArray(_realm);
  1056. var len = array.Length;
  1057. const string separator = ",";
  1058. if (len == 0)
  1059. {
  1060. return JsString.Empty;
  1061. }
  1062. JsValue r;
  1063. if (!array.TryGetValue(0, out var firstElement) || firstElement.IsNull() || firstElement.IsUndefined())
  1064. {
  1065. r = JsString.Empty;
  1066. }
  1067. else
  1068. {
  1069. var elementObj = TypeConverter.ToObject(_realm, firstElement);
  1070. var func = elementObj.Get("toLocaleString", elementObj) as ICallable;
  1071. if (func is null)
  1072. {
  1073. ExceptionHelper.ThrowTypeError(_realm);
  1074. }
  1075. r = func.Call(elementObj, Arguments.Empty);
  1076. }
  1077. for (var k = 1; k < len; k++)
  1078. {
  1079. var s = r + separator;
  1080. var elementObj = TypeConverter.ToObject(_realm, array[k]);
  1081. var func = elementObj.Get("toLocaleString", elementObj) as ICallable;
  1082. if (func is null)
  1083. {
  1084. ExceptionHelper.ThrowTypeError(_realm);
  1085. }
  1086. r = func.Call(elementObj, Arguments.Empty);
  1087. r = s + r;
  1088. }
  1089. return r;
  1090. }
  1091. /// <summary>
  1092. /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
  1093. /// </summary>
  1094. private JsValue Values(JsValue thisObj, JsValue[] arguments)
  1095. {
  1096. var o = thisObj.ValidateTypedArray(_realm);
  1097. return _realm.Intrinsics.ArrayIteratorPrototype.Construct(o, ArrayIteratorType.Value);
  1098. }
  1099. /// <summary>
  1100. /// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
  1101. /// </summary>
  1102. private static JsValue ToStringTag(JsValue thisObj, JsValue[] arguments)
  1103. {
  1104. if (thisObj is not TypedArrayInstance o)
  1105. {
  1106. return Undefined;
  1107. }
  1108. return o._arrayElementType.GetTypedArrayName();
  1109. }
  1110. private sealed class TypedArrayComparer : IComparer<JsValue>
  1111. {
  1112. public static TypedArrayComparer WithFunction(ArrayBufferInstance buffer, ICallable compare)
  1113. {
  1114. return new TypedArrayComparer(buffer, compare);
  1115. }
  1116. private readonly ArrayBufferInstance _buffer;
  1117. private readonly ICallable _compare;
  1118. private readonly JsValue[] _comparableArray = new JsValue[2];
  1119. private TypedArrayComparer(ArrayBufferInstance buffer, ICallable compare)
  1120. {
  1121. _buffer = buffer;
  1122. _compare = compare;
  1123. }
  1124. public int Compare(JsValue x, JsValue y)
  1125. {
  1126. if (_compare is not null)
  1127. {
  1128. _comparableArray[0] = x;
  1129. _comparableArray[1] = y;
  1130. var v = TypeConverter.ToNumber(_compare.Call(Undefined, _comparableArray));
  1131. _buffer.AssertNotDetached();
  1132. if (double.IsNaN(v))
  1133. {
  1134. return 0;
  1135. }
  1136. return (int) v;
  1137. }
  1138. var xValue = x.AsNumber();
  1139. var yValue = y.AsNumber();
  1140. if (double.IsNaN(xValue) && double.IsNaN(yValue))
  1141. {
  1142. return 0;
  1143. }
  1144. if (double.IsNaN(xValue))
  1145. {
  1146. return 1;
  1147. }
  1148. if (double.IsNaN(yValue))
  1149. {
  1150. return -1;
  1151. }
  1152. if (xValue < yValue)
  1153. {
  1154. return -1;
  1155. }
  1156. if (xValue > yValue)
  1157. {
  1158. return 1;
  1159. }
  1160. if (NumberInstance.IsNegativeZero(xValue) && yValue == 0)
  1161. {
  1162. return -1;
  1163. }
  1164. if (xValue == 0 && NumberInstance.IsNegativeZero(yValue))
  1165. {
  1166. return 1;
  1167. }
  1168. return 0;
  1169. }
  1170. }
  1171. }
  1172. }