[JSC] Pass VM& parameter as much as possible
[WebKit.git] / Source / JavaScriptCore / runtime / JSGenericTypedArrayViewPrototypeFunctions.h
1 /*
2  * Copyright (C) 2015-2017 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(ExecState* exec, JSObject* exemplar, MarkedArgumentBuffer& args, const Functor& defaultConstructor)
47 {
48     VM& vm = exec->vm();
49     auto scope = DECLARE_THROW_SCOPE(vm);
50
51     JSValue constructor = exemplar->get(exec, vm.propertyNames->constructor);
52     RETURN_IF_EXCEPTION(scope, nullptr);
53
54     if (constructor.isUndefined()) {
55         scope.release();
56         return defaultConstructor();
57     }
58     if (!constructor.isObject()) {
59         throwTypeError(exec, scope, ASCIILiteral("constructor Property should not be null"));
60         return nullptr;
61     }
62
63     JSValue species = constructor.get(exec, vm.propertyNames->speciesSymbol);
64     RETURN_IF_EXCEPTION(scope, nullptr);
65
66     if (species.isUndefinedOrNull()) {
67         scope.release();
68         return defaultConstructor();
69     }
70
71     JSValue result = construct(exec, species, args, "species is not a constructor");
72     RETURN_IF_EXCEPTION(scope, nullptr);
73
74     if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(vm, result)) {
75         if (!view->isNeutered())
76             return view;
77
78         throwTypeError(exec, scope, ASCIILiteral(typedArrayBufferHasBeenDetachedErrorMessage));
79         return nullptr;
80     }
81
82     throwTypeError(exec, scope, ASCIILiteral("species constructor did not return a TypedArray View"));
83     return nullptr;
84 }
85
86 inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
87 {
88     JSValue value = exec->argument(argument);
89     if (value.isUndefined())
90         return undefinedValue;
91
92     double indexDouble = value.toInteger(exec);
93     if (indexDouble < 0) {
94         indexDouble += length;
95         return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
96     }
97     return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
98 }
99
100 template<typename ViewClass>
101 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSet(VM& vm, ExecState* exec)
102 {
103     auto scope = DECLARE_THROW_SCOPE(vm);
104
105     // 22.2.3.22
106     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
107
108     if (UNLIKELY(!exec->argumentCount()))
109         return throwVMTypeError(exec, scope, ASCIILiteral("Expected at least one argument"));
110
111     unsigned offset;
112     if (exec->argumentCount() >= 2) {
113         double offsetNumber = exec->uncheckedArgument(1).toInteger(exec);
114         RETURN_IF_EXCEPTION(scope, encodedJSValue());
115         if (UNLIKELY(offsetNumber < 0))
116             return throwVMRangeError(exec, scope, "Offset should not be negative");
117         offset = static_cast<unsigned>(std::min(offsetNumber, static_cast<double>(std::numeric_limits<unsigned>::max())));
118     } else
119         offset = 0;
120
121     if (UNLIKELY(thisObject->isNeutered()))
122         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
123
124     JSObject* sourceArray = jsDynamicCast<JSObject*>(vm, exec->uncheckedArgument(0));
125     if (UNLIKELY(!sourceArray))
126         return throwVMTypeError(exec, scope, ASCIILiteral("First argument should be an object"));
127
128     unsigned length;
129     if (isTypedView(sourceArray->classInfo(vm)->typedArrayStorageType)) {
130         JSArrayBufferView* sourceView = jsCast<JSArrayBufferView*>(sourceArray);
131         if (UNLIKELY(sourceView->isNeutered()))
132             return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
133
134         length = jsCast<JSArrayBufferView*>(sourceArray)->length();
135     } else {
136         JSValue lengthValue = sourceArray->get(exec, vm.propertyNames->length);
137         RETURN_IF_EXCEPTION(scope, encodedJSValue());
138         length = lengthValue.toUInt32(exec);
139     }
140
141     RETURN_IF_EXCEPTION(scope, encodedJSValue());
142
143     scope.release();
144     thisObject->set(exec, offset, sourceArray, 0, length, CopyType::Unobservable);
145     return JSValue::encode(jsUndefined());
146 }
147
148 template<typename ViewClass>
149 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncCopyWithin(VM& vm, ExecState* exec)
150 {
151     auto scope = DECLARE_THROW_SCOPE(vm);
152
153     // 22.2.3.5
154     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
155     if (thisObject->isNeutered())
156         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
157
158     long length = thisObject->length();
159     long to = argumentClampedIndexFromStartOrEnd(exec, 0, length);
160     RETURN_IF_EXCEPTION(scope, encodedJSValue());
161     long from = argumentClampedIndexFromStartOrEnd(exec, 1, length);
162     RETURN_IF_EXCEPTION(scope, encodedJSValue());
163     long final = argumentClampedIndexFromStartOrEnd(exec, 2, length, length);
164     RETURN_IF_EXCEPTION(scope, encodedJSValue());
165
166     if (final < from)
167         return JSValue::encode(exec->thisValue());
168
169     long count = std::min(length - std::max(to, from), final - from);
170
171     if (thisObject->isNeutered())
172         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
173
174     typename ViewClass::ElementType* array = thisObject->typedVector();
175     memmove(array + to, array + from, count * thisObject->elementSize);
176
177     return JSValue::encode(exec->thisValue());
178 }
179
180 template<typename ViewClass>
181 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncIncludes(VM& vm, ExecState* exec)
182 {
183     auto scope = DECLARE_THROW_SCOPE(vm);
184
185     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
186     if (thisObject->isNeutered())
187         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
188
189     unsigned length = thisObject->length();
190
191     if (!length)
192         return JSValue::encode(jsBoolean(false));
193
194     JSValue valueToFind = exec->argument(0);
195
196     unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
197     RETURN_IF_EXCEPTION(scope, encodedJSValue());
198
199     if (thisObject->isNeutered())
200         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
201
202     typename ViewClass::ElementType* array = thisObject->typedVector();
203     auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
204     if (!targetOption)
205         return JSValue::encode(jsBoolean(false));
206
207     scope.assertNoException();
208     RELEASE_ASSERT(!thisObject->isNeutered());
209
210     if (std::isnan(static_cast<double>(*targetOption))) {
211         for (; index < length; ++index) {
212             if (std::isnan(static_cast<double>(array[index])))
213                 return JSValue::encode(jsBoolean(true));
214         }
215     } else {
216         for (; index < length; ++index) {
217             if (array[index] == targetOption)
218                 return JSValue::encode(jsBoolean(true));
219         }
220     }
221
222     return JSValue::encode(jsBoolean(false));
223 }
224
225 template<typename ViewClass>
226 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncIndexOf(VM& vm, ExecState* exec)
227 {
228     auto scope = DECLARE_THROW_SCOPE(vm);
229
230     // 22.2.3.13
231     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
232     if (thisObject->isNeutered())
233         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
234
235     if (!exec->argumentCount())
236         return throwVMTypeError(exec, scope, ASCIILiteral("Expected at least one argument"));
237
238     unsigned length = thisObject->length();
239
240     JSValue valueToFind = exec->argument(0);
241     unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
242     RETURN_IF_EXCEPTION(scope, encodedJSValue());
243
244     if (thisObject->isNeutered())
245         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
246
247     typename ViewClass::ElementType* array = thisObject->typedVector();
248     auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
249     if (!targetOption)
250         return JSValue::encode(jsNumber(-1));
251     scope.assertNoException();
252     RELEASE_ASSERT(!thisObject->isNeutered());
253
254     for (; index < length; ++index) {
255         if (array[index] == targetOption)
256             return JSValue::encode(jsNumber(index));
257     }
258
259     return JSValue::encode(jsNumber(-1));
260 }
261
262 template<typename ViewClass>
263 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncJoin(VM& vm, ExecState* exec)
264 {
265     auto scope = DECLARE_THROW_SCOPE(vm);
266
267     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
268     if (thisObject->isNeutered())
269         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
270
271     // 22.2.3.14
272     auto joinWithSeparator = [&] (StringView separator) -> EncodedJSValue {
273         ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
274         unsigned length = thisObject->length();
275
276         JSStringJoiner joiner(*exec, separator, length);
277         RETURN_IF_EXCEPTION(scope, encodedJSValue());
278         for (unsigned i = 0; i < length; i++) {
279             joiner.append(*exec, thisObject->getIndexQuickly(i));
280             RETURN_IF_EXCEPTION(scope, encodedJSValue());
281         }
282         scope.release();
283         return JSValue::encode(joiner.join(*exec));
284     };
285
286     JSValue separatorValue = exec->argument(0);
287     if (separatorValue.isUndefined()) {
288         const LChar* comma = reinterpret_cast<const LChar*>(",");
289         return joinWithSeparator({ comma, 1 });
290     }
291
292     JSString* separatorString = separatorValue.toString(exec);
293     RETURN_IF_EXCEPTION(scope, encodedJSValue());
294
295     if (thisObject->isNeutered())
296         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
297     auto viewWithString = separatorString->viewWithUnderlyingString(exec);
298     RETURN_IF_EXCEPTION(scope, encodedJSValue());
299     return joinWithSeparator(viewWithString.view);
300 }
301
302 template<typename ViewClass>
303 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncLastIndexOf(VM& vm, ExecState* exec)
304 {
305     auto scope = DECLARE_THROW_SCOPE(vm);
306
307     // 22.2.3.16
308     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
309     if (thisObject->isNeutered())
310         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
311
312     if (!exec->argumentCount())
313         return throwVMTypeError(exec, scope, ASCIILiteral("Expected at least one argument"));
314
315     unsigned length = thisObject->length();
316
317     JSValue valueToFind = exec->argument(0);
318
319     int index = length - 1;
320     if (exec->argumentCount() >= 2) {
321         JSValue fromValue = exec->uncheckedArgument(1);
322         double fromDouble = fromValue.toInteger(exec);
323         if (fromDouble < 0) {
324             fromDouble += length;
325             if (fromDouble < 0)
326                 return JSValue::encode(jsNumber(-1));
327         }
328         if (fromDouble < length)
329             index = static_cast<unsigned>(fromDouble);
330     }
331
332     RETURN_IF_EXCEPTION(scope, encodedJSValue());
333
334     if (thisObject->isNeutered())
335         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
336
337     auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
338     if (!targetOption)
339         return JSValue::encode(jsNumber(-1));
340
341     typename ViewClass::ElementType* array = thisObject->typedVector();
342     scope.assertNoException();
343     RELEASE_ASSERT(!thisObject->isNeutered());
344
345     for (; index >= 0; --index) {
346         if (array[index] == targetOption)
347             return JSValue::encode(jsNumber(index));
348     }
349
350     return JSValue::encode(jsNumber(-1));
351 }
352
353 template<typename ViewClass>
354 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncBuffer(VM&, ExecState* exec)
355 {
356     // 22.2.3.3
357     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
358
359     return JSValue::encode(thisObject->possiblySharedJSBuffer(exec));
360 }
361
362 template<typename ViewClass>
363 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncLength(VM&, ExecState* exec)
364 {
365     // 22.2.3.17
366     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
367
368     return JSValue::encode(jsNumber(thisObject->length()));
369 }
370
371 template<typename ViewClass>
372 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncByteLength(VM&, ExecState* exec)
373 {
374     // 22.2.3.2
375     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
376
377     return JSValue::encode(jsNumber(thisObject->byteLength()));
378 }
379
380 template<typename ViewClass>
381 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncByteOffset(VM&, ExecState* exec)
382 {
383     // 22.2.3.3
384     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
385
386     return JSValue::encode(jsNumber(thisObject->byteOffset()));
387 }
388
389 template<typename ViewClass>
390 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncReverse(VM& vm, ExecState* exec)
391 {
392 //    VM& vm = exec->vm();
393     auto scope = DECLARE_THROW_SCOPE(vm);
394
395     // 22.2.3.21
396     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
397     if (thisObject->isNeutered())
398         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
399
400     typename ViewClass::ElementType* array = thisObject->typedVector();
401     std::reverse(array, array + thisObject->length());
402
403     return JSValue::encode(thisObject);
404 }
405
406 template<typename ViewClass>
407 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSort(VM& vm, ExecState* exec)
408 {
409 //    VM& vm = exec->vm();
410     auto scope = DECLARE_THROW_SCOPE(vm);
411
412     // 22.2.3.25
413     ViewClass* thisObject = jsCast<ViewClass*>(exec->argument(0));
414     if (thisObject->isNeutered())
415         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
416
417     thisObject->sort();
418
419     return JSValue::encode(thisObject);
420 }
421
422 template<typename ViewClass>
423 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSlice(VM& vm, ExecState* exec)
424 {
425     auto scope = DECLARE_THROW_SCOPE(vm);
426
427     // 22.2.3.26
428     JSFunction* callee = jsCast<JSFunction*>(exec->jsCallee());
429
430     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
431     if (thisObject->isNeutered())
432         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
433
434     unsigned thisLength = thisObject->length();
435
436     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, thisLength);
437     RETURN_IF_EXCEPTION(scope, encodedJSValue());
438     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, thisLength, thisLength);
439     RETURN_IF_EXCEPTION(scope, encodedJSValue());
440
441     if (thisObject->isNeutered())
442         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
443
444     // Clamp end to begin.
445     end = std::max(begin, end);
446
447     ASSERT(end >= begin);
448     unsigned length = end - begin;
449
450     MarkedArgumentBuffer args;
451     args.append(jsNumber(length));
452     ASSERT(!args.hasOverflowed());
453
454     JSArrayBufferView* result = speciesConstruct(exec, thisObject, args, [&]() {
455         Structure* structure = callee->globalObject(vm)->typedArrayStructure(ViewClass::TypedArrayStorageType);
456         return ViewClass::createUninitialized(exec, structure, length);
457     });
458     RETURN_IF_EXCEPTION(scope, encodedJSValue());
459
460     ASSERT(!result->isNeutered());
461     if (thisObject->isNeutered())
462         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
463
464     // We return early here since we don't allocate a backing store if length is 0 and memmove does not like nullptrs
465     if (!length)
466         return JSValue::encode(result);
467
468     // The species constructor may return an array with any arbitrary length.
469     length = std::min(length, result->length());
470     switch (result->classInfo(vm)->typedArrayStorageType) {
471     case TypeInt8:
472         scope.release();
473         jsCast<JSInt8Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
474         return JSValue::encode(result);
475     case TypeInt16:
476         scope.release();
477         jsCast<JSInt16Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
478         return JSValue::encode(result);
479     case TypeInt32:
480         scope.release();
481         jsCast<JSInt32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
482         return JSValue::encode(result);
483     case TypeUint8:
484         scope.release();
485         jsCast<JSUint8Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
486         return JSValue::encode(result);
487     case TypeUint8Clamped:
488         scope.release();
489         jsCast<JSUint8ClampedArray*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
490         return JSValue::encode(result);
491     case TypeUint16:
492         scope.release();
493         jsCast<JSUint16Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
494         return JSValue::encode(result);
495     case TypeUint32:
496         scope.release();
497         jsCast<JSUint32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
498         return JSValue::encode(result);
499     case TypeFloat32:
500         scope.release();
501         jsCast<JSFloat32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
502         return JSValue::encode(result);
503     case TypeFloat64:
504         scope.release();
505         jsCast<JSFloat64Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
506         return JSValue::encode(result);
507     default:
508         RELEASE_ASSERT_NOT_REACHED();
509     }
510 }
511
512 template<typename ViewClass>
513 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSubarrayCreate(VM&vm, ExecState* exec)
514 {
515     auto scope = DECLARE_THROW_SCOPE(vm);
516
517     // 22.2.3.23
518     JSFunction* callee = jsCast<JSFunction*>(exec->jsCallee());
519
520     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
521     if (thisObject->isNeutered())
522         return throwVMTypeError(exec, scope, typedArrayBufferHasBeenDetachedErrorMessage);
523
524     // Get the length here; later assert that the length didn't change.
525     unsigned thisLength = thisObject->length();
526
527     // I would assert that the arguments are integers here but that's not true since
528     // https://tc39.github.io/ecma262/#sec-tointeger allows the result of the operation
529     // to be +/- Infinity and -0.
530     ASSERT(exec->argument(0).isNumber());
531     ASSERT(exec->argument(1).isUndefined() || exec->argument(1).isNumber());
532     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, thisLength);
533     scope.assertNoException();
534     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, thisLength, thisLength);
535     scope.assertNoException();
536
537     RELEASE_ASSERT(!thisObject->isNeutered());
538
539     // Clamp end to begin.
540     end = std::max(begin, end);
541
542     ASSERT(end >= begin);
543     unsigned offset = begin;
544     unsigned length = end - begin;
545
546     RefPtr<ArrayBuffer> arrayBuffer = thisObject->possiblySharedBuffer();
547     RELEASE_ASSERT(thisLength == thisObject->length());
548
549     unsigned newByteOffset = thisObject->byteOffset() + offset * ViewClass::elementSize;
550
551     JSObject* defaultConstructor = callee->globalObject(vm)->typedArrayConstructor(ViewClass::TypedArrayStorageType);
552     JSValue species = exec->uncheckedArgument(2);
553     if (species == defaultConstructor) {
554         Structure* structure = callee->globalObject(vm)->typedArrayStructure(ViewClass::TypedArrayStorageType);
555
556         scope.release();
557         return JSValue::encode(ViewClass::create(
558             exec, structure, WTFMove(arrayBuffer),
559             thisObject->byteOffset() + offset * ViewClass::elementSize,
560             length));
561     }
562
563     MarkedArgumentBuffer args;
564     args.append(vm.m_typedArrayController->toJS(exec, thisObject->globalObject(vm), arrayBuffer.get()));
565     args.append(jsNumber(newByteOffset));
566     args.append(jsNumber(length));
567     ASSERT(!args.hasOverflowed());
568
569     JSObject* result = construct(exec, 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(exec, scope, ASCIILiteral("species constructor did not return a TypedArray View"));
576     return JSValue::encode(JSValue());
577 }
578
579 } // namespace JSC