/ runtime / JSGenericTypedArrayViewPrototypeFunctions.h
JSGenericTypedArrayViewPrototypeFunctions.h
  1  /*
  2   * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #pragma once
 27  
 28  #include "Error.h"
 29  #include "JSArrayBufferViewInlines.h"
 30  #include "JSCBuiltins.h"
 31  #include "JSCJSValueInlines.h"
 32  #include "JSFunction.h"
 33  #include "JSGenericTypedArrayViewInlines.h"
 34  #include "JSGenericTypedArrayViewPrototypeInlines.h"
 35  #include "JSStringJoiner.h"
 36  #include "StructureInlines.h"
 37  #include "TypedArrayAdaptors.h"
 38  #include "TypedArrayController.h"
 39  #include <wtf/StdLibExtras.h>
 40  
 41  namespace JSC {
 42  
 43  // This implements 22.2.4.7 TypedArraySpeciesCreate
 44  // Note, that this function throws.
 45  template<typename Functor>
 46  inline JSArrayBufferView* speciesConstruct(JSGlobalObject* globalObject, JSObject* exemplar, MarkedArgumentBuffer& args, const Functor& defaultConstructor)
 47  {
 48      VM& vm = getVM(globalObject);
 49      auto scope = DECLARE_THROW_SCOPE(vm);
 50  
 51      JSValue constructor = exemplar->get(globalObject, vm.propertyNames->constructor);
 52      RETURN_IF_EXCEPTION(scope, nullptr);
 53  
 54      if (constructor.isUndefined())
 55          RELEASE_AND_RETURN(scope, defaultConstructor());
 56  
 57      if (!constructor.isObject()) {
 58          throwTypeError(globalObject, scope, "constructor Property should not be null"_s);
 59          return nullptr;
 60      }
 61  
 62      JSValue species = constructor.get(globalObject, vm.propertyNames->speciesSymbol);
 63      RETURN_IF_EXCEPTION(scope, nullptr);
 64  
 65      if (species.isUndefinedOrNull())
 66          RELEASE_AND_RETURN(scope, defaultConstructor());
 67  
 68  
 69      JSValue result = construct(globalObject, species, args, "species is not a constructor");
 70      RETURN_IF_EXCEPTION(scope, nullptr);
 71  
 72      if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(vm, result)) {
 73          if (view->type() == DataViewType) {
 74              throwTypeError(globalObject, scope, "species constructor did not return a TypedArray View"_s);
 75              return nullptr;
 76          }
 77  
 78          if (!view->isDetached())
 79              return view;
 80  
 81          throwTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 82          return nullptr;
 83      }
 84  
 85      throwTypeError(globalObject, scope, "species constructor did not return a TypedArray View"_s);
 86      return nullptr;
 87  }
 88  
 89  inline unsigned argumentClampedIndexFromStartOrEnd(JSGlobalObject* globalObject, JSValue value, unsigned length, unsigned undefinedValue = 0)
 90  {
 91      if (value.isUndefined())
 92          return undefinedValue;
 93  
 94      double indexDouble = value.toInteger(globalObject);
 95      if (indexDouble < 0) {
 96          indexDouble += length;
 97          return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
 98      }
 99      return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
100  }
101  
102  template<typename ViewClass>
103  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncSet(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
104  {
105      auto scope = DECLARE_THROW_SCOPE(vm);
106  
107      // 22.2.3.22
108      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
109  
110      if (UNLIKELY(!callFrame->argumentCount()))
111          return throwVMTypeError(globalObject, scope, "Expected at least one argument"_s);
112  
113      unsigned offset;
114      if (callFrame->argumentCount() >= 2) {
115          double offsetNumber = callFrame->uncheckedArgument(1).toInteger(globalObject);
116          RETURN_IF_EXCEPTION(scope, encodedJSValue());
117          if (UNLIKELY(offsetNumber < 0))
118              return throwVMRangeError(globalObject, scope, "Offset should not be negative");
119          offset = static_cast<unsigned>(std::min(offsetNumber, static_cast<double>(std::numeric_limits<unsigned>::max())));
120      } else
121          offset = 0;
122  
123      if (UNLIKELY(thisObject->isDetached()))
124          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
125  
126      JSObject* sourceArray = callFrame->uncheckedArgument(0).toObject(globalObject);
127      RETURN_IF_EXCEPTION(scope, { });
128  
129      unsigned length;
130      if (isTypedView(sourceArray->classInfo(vm)->typedArrayStorageType)) {
131          JSArrayBufferView* sourceView = jsCast<JSArrayBufferView*>(sourceArray);
132          if (UNLIKELY(sourceView->isDetached()))
133              return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
134  
135          length = jsCast<JSArrayBufferView*>(sourceArray)->length();
136      } else {
137          JSValue lengthValue = sourceArray->get(globalObject, vm.propertyNames->length);
138          RETURN_IF_EXCEPTION(scope, encodedJSValue());
139          length = lengthValue.toUInt32(globalObject);
140      }
141  
142      RETURN_IF_EXCEPTION(scope, encodedJSValue());
143  
144      scope.release();
145      thisObject->set(globalObject, offset, sourceArray, 0, length, CopyType::Unobservable);
146      return JSValue::encode(jsUndefined());
147  }
148  
149  template<typename ViewClass>
150  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncCopyWithin(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
151  {
152      auto scope = DECLARE_THROW_SCOPE(vm);
153  
154      // 22.2.3.5
155      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
156      if (thisObject->isDetached())
157          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
158  
159      long length = thisObject->length();
160      long to = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(0), length);
161      RETURN_IF_EXCEPTION(scope, encodedJSValue());
162      long from = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
163      RETURN_IF_EXCEPTION(scope, encodedJSValue());
164      long final = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(2), length, length);
165      RETURN_IF_EXCEPTION(scope, encodedJSValue());
166  
167      if (final < from)
168          return JSValue::encode(callFrame->thisValue());
169  
170      long count = std::min(length - std::max(to, from), final - from);
171  
172      if (thisObject->isDetached())
173          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
174  
175      typename ViewClass::ElementType* array = thisObject->typedVector();
176      memmove(array + to, array + from, count * thisObject->elementSize);
177  
178      return JSValue::encode(callFrame->thisValue());
179  }
180  
181  template<typename ViewClass>
182  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIncludes(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
183  {
184      auto scope = DECLARE_THROW_SCOPE(vm);
185  
186      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
187      if (thisObject->isDetached())
188          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
189  
190      unsigned length = thisObject->length();
191  
192      if (!length)
193          return JSValue::encode(jsBoolean(false));
194  
195      JSValue valueToFind = callFrame->argument(0);
196  
197      unsigned index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
198      RETURN_IF_EXCEPTION(scope, encodedJSValue());
199  
200      if (thisObject->isDetached())
201          return JSValue::encode(jsBoolean(valueToFind.isUndefined()));
202  
203      typename ViewClass::ElementType* array = thisObject->typedVector();
204      auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
205      if (!targetOption)
206          return JSValue::encode(jsBoolean(false));
207  
208      scope.assertNoException();
209      RELEASE_ASSERT(!thisObject->isDetached());
210  
211      if (std::isnan(static_cast<double>(*targetOption))) {
212          for (; index < length; ++index) {
213              if (std::isnan(static_cast<double>(array[index])))
214                  return JSValue::encode(jsBoolean(true));
215          }
216      } else {
217          for (; index < length; ++index) {
218              if (array[index] == targetOption)
219                  return JSValue::encode(jsBoolean(true));
220          }
221      }
222  
223      return JSValue::encode(jsBoolean(false));
224  }
225  
226  template<typename ViewClass>
227  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIndexOf(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
228  {
229      auto scope = DECLARE_THROW_SCOPE(vm);
230  
231      // 22.2.3.13
232      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
233      if (thisObject->isDetached())
234          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
235  
236      unsigned length = thisObject->length();
237  
238      if (!length)
239          return JSValue::encode(jsNumber(-1));
240  
241      JSValue valueToFind = callFrame->argument(0);
242      unsigned index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
243      RETURN_IF_EXCEPTION(scope, encodedJSValue());
244  
245      if (thisObject->isDetached())
246          return JSValue::encode(jsNumber(-1));
247  
248      typename ViewClass::ElementType* array = thisObject->typedVector();
249      auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
250      if (!targetOption)
251          return JSValue::encode(jsNumber(-1));
252      scope.assertNoException();
253      RELEASE_ASSERT(!thisObject->isDetached());
254  
255      for (; index < length; ++index) {
256          if (array[index] == targetOption)
257              return JSValue::encode(jsNumber(index));
258      }
259  
260      return JSValue::encode(jsNumber(-1));
261  }
262  
263  template<typename ViewClass>
264  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncJoin(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
265  {
266      auto scope = DECLARE_THROW_SCOPE(vm);
267  
268      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
269      if (thisObject->isDetached())
270          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
271  
272      unsigned length = thisObject->length();
273      auto joinWithSeparator = [&] (StringView separator) -> EncodedJSValue {
274          JSStringJoiner joiner(globalObject, separator, length);
275          RETURN_IF_EXCEPTION(scope, encodedJSValue());
276          if (!thisObject->isDetached()) {
277              for (unsigned i = 0; i < length; i++) {
278                  joiner.append(globalObject, thisObject->getIndexQuickly(i));
279                  RETURN_IF_EXCEPTION(scope, encodedJSValue());
280              }
281          } else {
282              for (unsigned i = 0; i < length; i++)
283                  joiner.appendEmptyString();
284          }
285          RELEASE_AND_RETURN(scope, JSValue::encode(joiner.join(globalObject)));
286      };
287  
288      JSValue separatorValue = callFrame->argument(0);
289      if (separatorValue.isUndefined()) {
290          const LChar* comma = reinterpret_cast<const LChar*>(",");
291          return joinWithSeparator({ comma, 1 });
292      }
293  
294      JSString* separatorString = separatorValue.toString(globalObject);
295      RETURN_IF_EXCEPTION(scope, encodedJSValue());
296  
297      auto viewWithString = separatorString->viewWithUnderlyingString(globalObject);
298      RETURN_IF_EXCEPTION(scope, encodedJSValue());
299      return joinWithSeparator(viewWithString.view);
300  }
301  
302  template<typename ViewClass>
303  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncLastIndexOf(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
304  {
305      auto scope = DECLARE_THROW_SCOPE(vm);
306  
307      // 22.2.3.16
308      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
309      if (thisObject->isDetached())
310          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
311  
312      unsigned length = thisObject->length();
313  
314      if (!length)
315          return JSValue::encode(jsNumber(-1));
316  
317      JSValue valueToFind = callFrame->argument(0);
318  
319      int index = length - 1;
320      if (callFrame->argumentCount() >= 2) {
321          JSValue fromValue = callFrame->uncheckedArgument(1);
322          double fromDouble = fromValue.toInteger(globalObject);
323          RETURN_IF_EXCEPTION(scope, encodedJSValue());
324          if (fromDouble < 0) {
325              fromDouble += length;
326              if (fromDouble < 0)
327                  return JSValue::encode(jsNumber(-1));
328          }
329          if (fromDouble < length)
330              index = static_cast<unsigned>(fromDouble);
331      }
332  
333      if (thisObject->isDetached())
334          return JSValue::encode(jsNumber(-1));
335  
336      auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
337      if (!targetOption)
338          return JSValue::encode(jsNumber(-1));
339  
340      typename ViewClass::ElementType* array = thisObject->typedVector();
341      scope.assertNoException();
342      RELEASE_ASSERT(!thisObject->isDetached());
343  
344      for (; index >= 0; --index) {
345          if (array[index] == targetOption)
346              return JSValue::encode(jsNumber(index));
347      }
348  
349      return JSValue::encode(jsNumber(-1));
350  }
351  
352  template<typename ViewClass>
353  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoGetterFuncBuffer(VM&, JSGlobalObject* globalObject, CallFrame* callFrame)
354  {
355      // 22.2.3.3
356      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
357  
358      return JSValue::encode(thisObject->possiblySharedJSBuffer(globalObject));
359  }
360  
361  template<typename ViewClass>
362  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoGetterFuncLength(VM&, JSGlobalObject*, CallFrame* callFrame)
363  {
364      // 22.2.3.17
365      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
366  
367      return JSValue::encode(jsNumber(thisObject->length()));
368  }
369  
370  template<typename ViewClass>
371  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoGetterFuncByteLength(VM&, JSGlobalObject*, CallFrame* callFrame)
372  {
373      // 22.2.3.2
374      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
375  
376      return JSValue::encode(jsNumber(thisObject->byteLength()));
377  }
378  
379  template<typename ViewClass>
380  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoGetterFuncByteOffset(VM&, JSGlobalObject*, CallFrame* callFrame)
381  {
382      // 22.2.3.3
383      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
384  
385      return JSValue::encode(jsNumber(thisObject->byteOffset()));
386  }
387  
388  template<typename ViewClass>
389  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncReverse(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
390  {
391      auto scope = DECLARE_THROW_SCOPE(vm);
392  
393      // 22.2.3.21
394      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
395      if (thisObject->isDetached())
396          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
397  
398      typename ViewClass::ElementType* array = thisObject->typedVector();
399      std::reverse(array, array + thisObject->length());
400  
401      return JSValue::encode(thisObject);
402  }
403  
404  template<typename ViewClass>
405  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewPrivateFuncSort(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
406  {
407      auto scope = DECLARE_THROW_SCOPE(vm);
408  
409      // 22.2.3.25
410      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->argument(0));
411      if (thisObject->isDetached())
412          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
413  
414      thisObject->sort();
415  
416      return JSValue::encode(thisObject);
417  }
418  
419  template<typename ViewClass>
420  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncSlice(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame)
421  {
422      auto scope = DECLARE_THROW_SCOPE(vm);
423  
424      // 22.2.3.26
425  
426      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
427      if (thisObject->isDetached())
428          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
429  
430      unsigned thisLength = thisObject->length();
431  
432      unsigned begin = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(0), thisLength);
433      RETURN_IF_EXCEPTION(scope, encodedJSValue());
434      unsigned end = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), thisLength, thisLength);
435      RETURN_IF_EXCEPTION(scope, encodedJSValue());
436  
437      if (thisObject->isDetached())
438          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
439  
440      // Clamp end to begin.
441      end = std::max(begin, end);
442  
443      ASSERT(end >= begin);
444      unsigned length = end - begin;
445  
446      MarkedArgumentBuffer args;
447      args.append(jsNumber(length));
448      ASSERT(!args.hasOverflowed());
449  
450      JSArrayBufferView* result = speciesConstruct(globalObject, thisObject, args, [&]() {
451          Structure* structure = globalObject->typedArrayStructure(ViewClass::TypedArrayStorageType);
452          return ViewClass::createUninitialized(globalObject, structure, length);
453      });
454      RETURN_IF_EXCEPTION(scope, encodedJSValue());
455      ASSERT(!result->isDetached());
456  
457      // We return early here since we don't allocate a backing store if length is 0 and memmove does not like nullptrs
458      if (!length)
459          return JSValue::encode(result);
460  
461      if (thisObject->isDetached())
462          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
463  
464      // The species constructor may return an array with any arbitrary length.
465      if (result->length() < length)
466          return throwVMTypeError(globalObject, scope, "TypedArray.prototype.slice constructed typed array of insufficient length"_s);
467  
468      switch (result->classInfo(vm)->typedArrayStorageType) {
469      case TypeInt8:
470          scope.release();
471          jsCast<JSInt8Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
472          return JSValue::encode(result);
473      case TypeInt16:
474          scope.release();
475          jsCast<JSInt16Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
476          return JSValue::encode(result);
477      case TypeInt32:
478          scope.release();
479          jsCast<JSInt32Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
480          return JSValue::encode(result);
481      case TypeUint8:
482          scope.release();
483          jsCast<JSUint8Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
484          return JSValue::encode(result);
485      case TypeUint8Clamped:
486          scope.release();
487          jsCast<JSUint8ClampedArray*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
488          return JSValue::encode(result);
489      case TypeUint16:
490          scope.release();
491          jsCast<JSUint16Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
492          return JSValue::encode(result);
493      case TypeUint32:
494          scope.release();
495          jsCast<JSUint32Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
496          return JSValue::encode(result);
497      case TypeFloat32:
498          scope.release();
499          jsCast<JSFloat32Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
500          return JSValue::encode(result);
501      case TypeFloat64:
502          scope.release();
503          jsCast<JSFloat64Array*>(result)->set(globalObject, 0, thisObject, begin, length, CopyType::LeftToRight);
504          return JSValue::encode(result);
505      default:
506          RELEASE_ASSERT_NOT_REACHED();
507      }
508  }
509  
510  template<typename ViewClass>
511  ALWAYS_INLINE EncodedJSValue genericTypedArrayViewPrivateFuncSubarrayCreate(VM&vm, JSGlobalObject* globalObject, CallFrame* callFrame)
512  {
513      auto scope = DECLARE_THROW_SCOPE(vm);
514  
515      // 22.2.3.23
516  
517      ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
518      if (thisObject->isDetached())
519          return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
520  
521      // Get the length here; later assert that the length didn't change.
522      unsigned thisLength = thisObject->length();
523  
524      // I would assert that the arguments are integers here but that's not true since
525      // https://tc39.github.io/ecma262/#sec-tointeger allows the result of the operation
526      // to be +/- Infinity and -0.
527      ASSERT(callFrame->argument(0).isNumber());
528      ASSERT(callFrame->argument(1).isUndefined() || callFrame->argument(1).isNumber());
529      unsigned begin = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(0), thisLength);
530      scope.assertNoException();
531      unsigned end = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), thisLength, thisLength);
532      scope.assertNoException();
533  
534      RELEASE_ASSERT(!thisObject->isDetached());
535  
536      // Clamp end to begin.
537      end = std::max(begin, end);
538  
539      ASSERT(end >= begin);
540      unsigned offset = begin;
541      unsigned length = end - begin;
542  
543      RefPtr<ArrayBuffer> arrayBuffer = thisObject->possiblySharedBuffer();
544      if (UNLIKELY(!arrayBuffer)) {
545          throwOutOfMemoryError(globalObject, scope);
546          return encodedJSValue();
547      }
548      RELEASE_ASSERT(thisLength == thisObject->length());
549  
550      unsigned newByteOffset = thisObject->byteOffset() + offset * ViewClass::elementSize;
551  
552      JSObject* defaultConstructor = globalObject->typedArrayConstructor(ViewClass::TypedArrayStorageType);
553      JSValue species = callFrame->uncheckedArgument(2);
554      if (species == defaultConstructor) {
555          Structure* structure = globalObject->typedArrayStructure(ViewClass::TypedArrayStorageType);
556  
557          RELEASE_AND_RETURN(scope, JSValue::encode(ViewClass::create(
558              globalObject, structure, WTFMove(arrayBuffer),
559              thisObject->byteOffset() + offset * ViewClass::elementSize,
560              length)));
561      }
562  
563      MarkedArgumentBuffer args;
564      args.append(vm.m_typedArrayController->toJS(globalObject, thisObject->globalObject(vm), arrayBuffer.get()));
565      args.append(jsNumber(newByteOffset));
566      args.append(jsNumber(length));
567      ASSERT(!args.hasOverflowed());
568  
569      JSObject* result = construct(globalObject, species, args, "species is not a constructor");
570      RETURN_IF_EXCEPTION(scope, encodedJSValue());
571  
572      if (jsDynamicCast<JSArrayBufferView*>(vm, result))
573          return JSValue::encode(result);
574  
575      throwTypeError(globalObject, scope, "species constructor did not return a TypedArray View"_s);
576      return JSValue::encode(JSValue());
577  }
578  
579  } // namespace JSC