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