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