DataViewObject.cpp (39378B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "builtin/DataViewObject.h" 8 9 #include "mozilla/EndianUtils.h" 10 #include "mozilla/IntegerTypeTraits.h" 11 #include "mozilla/WrappingOperations.h" 12 13 #include <algorithm> 14 #include <string.h> 15 #include <type_traits> 16 17 #include "jsnum.h" 18 19 #include "jit/AtomicOperations.h" 20 #include "jit/InlinableNatives.h" 21 #include "js/Conversions.h" 22 #include "js/experimental/TypedData.h" // JS_NewDataView 23 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 24 #include "js/PropertySpec.h" 25 #include "js/Wrapper.h" 26 #include "util/DifferentialTesting.h" 27 #include "vm/ArrayBufferObject.h" 28 #include "vm/Compartment.h" 29 #include "vm/Float16.h" 30 #include "vm/GlobalObject.h" 31 #include "vm/Interpreter.h" 32 #include "vm/JSContext.h" 33 #include "vm/JSObject.h" 34 #include "vm/SharedMem.h" 35 #include "vm/Uint8Clamped.h" 36 #include "vm/WrapperObject.h" 37 38 #include "vm/ArrayBufferObject-inl.h" 39 #include "vm/NativeObject-inl.h" 40 41 using namespace js; 42 43 using JS::CanonicalizeNaN; 44 using JS::ToInt32; 45 using mozilla::WrapToSigned; 46 47 static bool IsDataView(HandleValue v) { 48 return v.isObject() && v.toObject().is<DataViewObject>(); 49 } 50 51 DataViewObject* DataViewObject::create( 52 JSContext* cx, size_t byteOffset, size_t byteLength, 53 Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) { 54 MOZ_ASSERT(!arrayBuffer->isResizable()); 55 MOZ_ASSERT(!arrayBuffer->isDetached()); 56 MOZ_ASSERT(!arrayBuffer->isImmutable()); 57 58 auto* obj = NewObjectWithClassProto<FixedLengthDataViewObject>(cx, proto); 59 if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength, 60 /* bytesPerElement = */ 1)) { 61 return nullptr; 62 } 63 64 return obj; 65 } 66 67 ResizableDataViewObject* ResizableDataViewObject::create( 68 JSContext* cx, size_t byteOffset, size_t byteLength, AutoLength autoLength, 69 Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) { 70 MOZ_ASSERT(arrayBuffer->isResizable()); 71 MOZ_ASSERT(!arrayBuffer->isDetached()); 72 MOZ_ASSERT(!arrayBuffer->isImmutable()); 73 MOZ_ASSERT(autoLength == AutoLength::No || byteLength == 0, 74 "byte length is zero for 'auto' length views"); 75 76 auto* obj = NewObjectWithClassProto<ResizableDataViewObject>(cx, proto); 77 if (!obj || !obj->initResizable(cx, arrayBuffer, byteOffset, byteLength, 78 /* bytesPerElement = */ 1, autoLength)) { 79 return nullptr; 80 } 81 82 return obj; 83 } 84 85 ImmutableDataViewObject* ImmutableDataViewObject::create( 86 JSContext* cx, size_t byteOffset, size_t byteLength, 87 Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) { 88 MOZ_ASSERT(!arrayBuffer->isResizable()); 89 MOZ_ASSERT(!arrayBuffer->isDetached()); 90 MOZ_ASSERT(arrayBuffer->isImmutable()); 91 92 auto* obj = NewObjectWithClassProto<ImmutableDataViewObject>(cx, proto); 93 if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength, 94 /* bytesPerElement = */ 1)) { 95 return nullptr; 96 } 97 98 return obj; 99 } 100 101 // ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f 102 // 24.3.2.1 DataView (extracted part of the main algorithm) 103 bool DataViewObject::getAndCheckConstructorArgs( 104 JSContext* cx, HandleObject bufobj, const CallArgs& args, 105 size_t* byteOffsetPtr, size_t* byteLengthPtr, AutoLength* autoLengthPtr) { 106 // Step 3. 107 if (!bufobj->is<ArrayBufferObjectMaybeShared>()) { 108 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 109 JSMSG_NOT_EXPECTED_TYPE, "DataView", 110 "ArrayBuffer", bufobj->getClass()->name); 111 return false; 112 } 113 auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>(); 114 115 // Step 4. 116 uint64_t offset; 117 if (!ToIndex(cx, args.get(1), &offset)) { 118 return false; 119 } 120 121 // Step 5. 122 if (buffer->isDetached()) { 123 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 124 JSMSG_TYPED_ARRAY_DETACHED); 125 return false; 126 } 127 128 // Step 6. 129 size_t bufferByteLength = buffer->byteLength(); 130 131 // Step 7. 132 if (offset > bufferByteLength) { 133 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 134 JSMSG_OFFSET_OUT_OF_BUFFER); 135 return false; 136 } 137 MOZ_ASSERT(offset <= ArrayBufferObject::ByteLengthLimit); 138 139 uint64_t viewByteLength = 0; 140 auto autoLength = AutoLength::No; 141 if (!args.hasDefined(2)) { 142 if (buffer->isResizable()) { 143 autoLength = AutoLength::Yes; 144 } else { 145 // Step 8.a 146 viewByteLength = bufferByteLength - offset; 147 } 148 } else { 149 // Step 9.a. 150 if (!ToIndex(cx, args.get(2), &viewByteLength)) { 151 return false; 152 } 153 154 MOZ_ASSERT(offset + viewByteLength >= offset, 155 "can't overflow: both numbers are less than " 156 "DOUBLE_INTEGRAL_PRECISION_LIMIT"); 157 158 // Step 9.b. 159 if (offset + viewByteLength > bufferByteLength) { 160 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 161 JSMSG_INVALID_DATA_VIEW_LENGTH); 162 return false; 163 } 164 } 165 MOZ_ASSERT(viewByteLength <= ArrayBufferObject::ByteLengthLimit); 166 167 *byteOffsetPtr = offset; 168 *byteLengthPtr = viewByteLength; 169 *autoLengthPtr = autoLength; 170 return true; 171 } 172 173 static bool CheckConstructorArgs(JSContext* cx, 174 Handle<ArrayBufferObjectMaybeShared*> buffer, 175 size_t byteOffset, size_t byteLength) { 176 if (buffer->isDetached()) { 177 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 178 JSMSG_TYPED_ARRAY_DETACHED); 179 return false; 180 } 181 182 if (buffer->isResizable()) { 183 size_t bufferByteLength = buffer->byteLength(); 184 if (byteOffset + byteLength > bufferByteLength) { 185 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 186 JSMSG_OFFSET_OUT_OF_BUFFER); 187 return false; 188 } 189 } 190 191 return true; 192 } 193 194 bool DataViewObject::constructSameCompartment(JSContext* cx, 195 HandleObject bufobj, 196 const CallArgs& args) { 197 MOZ_ASSERT(args.isConstructing()); 198 cx->check(bufobj); 199 200 size_t byteOffset = 0; 201 size_t byteLength = 0; 202 auto autoLength = AutoLength::No; 203 if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength, 204 &autoLength)) { 205 return false; 206 } 207 208 RootedObject proto(cx); 209 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) { 210 return false; 211 } 212 213 auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>(); 214 215 // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer, 216 // so we have to revalidate the arguments. 217 if (!CheckConstructorArgs(cx, buffer, byteOffset, byteLength)) { 218 return false; 219 } 220 221 DataViewObject* obj; 222 if (buffer->isResizable()) { 223 obj = ResizableDataViewObject::create(cx, byteOffset, byteLength, 224 autoLength, buffer, proto); 225 } else if (buffer->isImmutable()) { 226 obj = ImmutableDataViewObject::create(cx, byteOffset, byteLength, buffer, 227 proto); 228 } else { 229 obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto); 230 } 231 if (!obj) { 232 return false; 233 } 234 args.rval().setObject(*obj); 235 return true; 236 } 237 238 // Create a DataView object in another compartment. 239 // 240 // ES6 supports creating a DataView in global A (using global A's DataView 241 // constructor) backed by an ArrayBuffer created in global B. 242 // 243 // Our DataViewObject implementation doesn't support a DataView in 244 // compartment A backed by an ArrayBuffer in compartment B. So in this case, 245 // we create the DataView in B (!) and return a cross-compartment wrapper. 246 // 247 // Extra twist: the spec says the new DataView's [[Prototype]] must be 248 // A's DataView.prototype. So even though we're creating the DataView in B, 249 // its [[Prototype]] must be (a cross-compartment wrapper for) the 250 // DataView.prototype in A. 251 bool DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, 252 const CallArgs& args) { 253 MOZ_ASSERT(args.isConstructing()); 254 MOZ_ASSERT(bufobj->is<WrapperObject>()); 255 256 RootedObject unwrapped(cx, CheckedUnwrapStatic(bufobj)); 257 if (!unwrapped) { 258 ReportAccessDenied(cx); 259 return false; 260 } 261 262 // NB: This entails the IsArrayBuffer check 263 size_t byteOffset = 0; 264 size_t byteLength = 0; 265 auto autoLength = AutoLength::No; 266 if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength, 267 &autoLength)) { 268 return false; 269 } 270 271 // Make sure to get the [[Prototype]] for the created view from this 272 // compartment. 273 RootedObject proto(cx); 274 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) { 275 return false; 276 } 277 278 auto unwrappedBuffer = unwrapped.as<ArrayBufferObjectMaybeShared>(); 279 280 // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer, 281 // so we have to revalidate the arguments. 282 if (!CheckConstructorArgs(cx, unwrappedBuffer, byteOffset, byteLength)) { 283 return false; 284 } 285 286 Rooted<GlobalObject*> global(cx, cx->realm()->maybeGlobal()); 287 if (!proto) { 288 proto = GlobalObject::getOrCreateDataViewPrototype(cx, global); 289 if (!proto) { 290 return false; 291 } 292 } 293 294 RootedObject dv(cx); 295 { 296 JSAutoRealm ar(cx, unwrapped); 297 298 RootedObject wrappedProto(cx, proto); 299 if (!cx->compartment()->wrap(cx, &wrappedProto)) { 300 return false; 301 } 302 303 if (unwrappedBuffer->isResizable()) { 304 dv = ResizableDataViewObject::create(cx, byteOffset, byteLength, 305 autoLength, unwrappedBuffer, 306 wrappedProto); 307 } else if (unwrappedBuffer->isImmutable()) { 308 dv = ImmutableDataViewObject::create(cx, byteOffset, byteLength, 309 unwrappedBuffer, wrappedProto); 310 } else { 311 dv = DataViewObject::create(cx, byteOffset, byteLength, unwrappedBuffer, 312 wrappedProto); 313 } 314 if (!dv) { 315 return false; 316 } 317 } 318 319 if (!cx->compartment()->wrap(cx, &dv)) { 320 return false; 321 } 322 323 args.rval().setObject(*dv); 324 return true; 325 } 326 327 bool DataViewObject::construct(JSContext* cx, unsigned argc, Value* vp) { 328 CallArgs args = CallArgsFromVp(argc, vp); 329 330 if (!ThrowIfNotConstructing(cx, args, "DataView")) { 331 return false; 332 } 333 334 RootedObject bufobj(cx); 335 if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj)) { 336 return false; 337 } 338 339 if (bufobj->is<WrapperObject>()) { 340 return constructWrapped(cx, bufobj, args); 341 } 342 return constructSameCompartment(cx, bufobj, args); 343 } 344 345 template <typename NativeType> 346 SharedMem<uint8_t*> DataViewObject::getDataPointer(uint64_t offset, 347 size_t length, 348 bool* isSharedMemory) { 349 MOZ_ASSERT(length <= *byteLength()); 350 MOZ_ASSERT(offsetIsInBounds<NativeType>(offset, length)); 351 352 MOZ_ASSERT(offset < SIZE_MAX); 353 *isSharedMemory = this->isSharedMemory(); 354 return dataPointerEither().cast<uint8_t*>() + size_t(offset); 355 } 356 357 static void ReportOutOfBounds(JSContext* cx, DataViewObject* dataView) { 358 if (dataView->hasDetachedBuffer()) { 359 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 360 JSMSG_TYPED_ARRAY_DETACHED); 361 } else { 362 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 363 JSMSG_TYPED_ARRAY_RESIZED_BOUNDS); 364 } 365 } 366 367 template <typename T> 368 static inline std::enable_if_t<sizeof(T) != 1> SwapBytes(T* value, 369 bool isLittleEndian) { 370 if (isLittleEndian) { 371 mozilla::NativeEndian::swapToLittleEndianInPlace(value, 1); 372 } else { 373 mozilla::NativeEndian::swapToBigEndianInPlace(value, 1); 374 } 375 } 376 377 template <typename T> 378 static inline std::enable_if_t<sizeof(T) == 1> SwapBytes(T* value, 379 bool isLittleEndian) { 380 // mozilla::NativeEndian doesn't support int8_t/uint8_t types. 381 } 382 383 static inline void Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes) { 384 memcpy(dest, src, nbytes); 385 } 386 387 static inline void Memcpy(uint8_t* dest, SharedMem<uint8_t*> src, 388 size_t nbytes) { 389 jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes); 390 } 391 392 static inline void Memcpy(SharedMem<uint8_t*> dest, uint8_t* src, 393 size_t nbytes) { 394 jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes); 395 } 396 397 template <typename DataType, typename BufferPtrType> 398 struct DataViewIO { 399 using ReadWriteType = 400 typename mozilla::UnsignedStdintTypeForSize<sizeof(DataType)>::Type; 401 402 static constexpr auto alignMask = 403 std::min<size_t>(alignof(void*), sizeof(DataType)) - 1; 404 405 static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer, 406 bool isLittleEndian) { 407 MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & alignMask) == 0); 408 Memcpy((uint8_t*)dest, unalignedBuffer, sizeof(ReadWriteType)); 409 ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest); 410 SwapBytes(rwDest, isLittleEndian); 411 } 412 413 static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src, 414 bool isLittleEndian) { 415 MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & alignMask) == 0); 416 ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src); 417 SwapBytes(&temp, isLittleEndian); 418 Memcpy(unalignedBuffer, (uint8_t*)&temp, sizeof(ReadWriteType)); 419 } 420 }; 421 422 template <typename NativeType> 423 NativeType DataViewObject::read(uint64_t offset, size_t length, 424 bool isLittleEndian) { 425 bool isSharedMemory; 426 SharedMem<uint8_t*> data = 427 getDataPointer<NativeType>(offset, length, &isSharedMemory); 428 MOZ_ASSERT(data); 429 430 NativeType val{}; 431 if (isSharedMemory) { 432 DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data, 433 isLittleEndian); 434 } else { 435 DataViewIO<NativeType, uint8_t*>::fromBuffer(&val, data.unwrapUnshared(), 436 isLittleEndian); 437 } 438 439 return val; 440 } 441 442 template uint32_t DataViewObject::read(uint64_t offset, size_t length, 443 bool isLittleEndian); 444 445 // https://tc39.github.io/ecma262/#sec-getviewvalue 446 // GetViewValue ( view, requestIndex, isLittleEndian, type ) 447 template <typename NativeType> 448 /* static */ 449 bool DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj, 450 const CallArgs& args, NativeType* val) { 451 // Step 1. done by the caller 452 // Step 2. unnecessary assert 453 454 // Step 3. 455 uint64_t getIndex; 456 if (!ToIndex(cx, args.get(0), &getIndex)) { 457 return false; 458 } 459 460 // Step 4. 461 bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]); 462 463 // Steps 5-6. 464 auto viewSize = obj->byteLength(); 465 if (MOZ_UNLIKELY(!viewSize)) { 466 ReportOutOfBounds(cx, obj); 467 return false; 468 } 469 470 // Steps 7-10. 471 if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) { 472 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 473 JSMSG_OFFSET_OUT_OF_DATAVIEW); 474 return false; 475 } 476 477 // Steps 11-12. 478 *val = obj->read<NativeType>(getIndex, *viewSize, isLittleEndian); 479 return true; 480 } 481 482 template <typename T> 483 static inline T WrappingConvert(int32_t value) { 484 if (std::is_unsigned_v<T>) { 485 return static_cast<T>(value); 486 } 487 488 return WrapToSigned(static_cast<typename std::make_unsigned_t<T>>(value)); 489 } 490 491 template <typename NativeType> 492 static inline bool WebIDLCast(JSContext* cx, HandleValue value, 493 NativeType* out) { 494 int32_t i; 495 if (!ToInt32(cx, value, &i)) { 496 return false; 497 } 498 499 *out = WrappingConvert<NativeType>(i); 500 return true; 501 } 502 503 template <> 504 inline bool WebIDLCast<int64_t>(JSContext* cx, HandleValue value, 505 int64_t* out) { 506 BigInt* bi = ToBigInt(cx, value); 507 if (!bi) { 508 return false; 509 } 510 *out = BigInt::toInt64(bi); 511 return true; 512 } 513 514 template <> 515 inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value, 516 uint64_t* out) { 517 BigInt* bi = ToBigInt(cx, value); 518 if (!bi) { 519 return false; 520 } 521 *out = BigInt::toUint64(bi); 522 return true; 523 } 524 525 template <> 526 inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value, 527 float16* out) { 528 double temp; 529 if (!ToNumber(cx, value, &temp)) { 530 return false; 531 } 532 *out = float16(temp); 533 return true; 534 } 535 536 template <> 537 inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) { 538 double temp; 539 if (!ToNumber(cx, value, &temp)) { 540 return false; 541 } 542 *out = static_cast<float>(temp); 543 return true; 544 } 545 546 template <> 547 inline bool WebIDLCast<double>(JSContext* cx, HandleValue value, double* out) { 548 return ToNumber(cx, value, out); 549 } 550 551 // https://tc39.github.io/ecma262/#sec-setviewvalue 552 // SetViewValue ( view, requestIndex, isLittleEndian, type, value ) 553 template <typename NativeType> 554 /* static */ 555 bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj, 556 const CallArgs& args) { 557 // Step 1. done by the caller 558 // Step 2. unnecessary assert 559 560 // Additional step from Immutable ArrayBuffer proposal. 561 if (obj->is<ImmutableDataViewObject>()) { 562 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 563 JSMSG_ARRAYBUFFER_IMMUTABLE); 564 return false; 565 } 566 567 // Step 3. 568 uint64_t getIndex; 569 if (!ToIndex(cx, args.get(0), &getIndex)) { 570 return false; 571 } 572 573 // Steps 4-5. Call ToBigInt(value) or ToNumber(value) depending on the type. 574 NativeType value; 575 if (!WebIDLCast(cx, args.get(1), &value)) { 576 return false; 577 } 578 579 // See the comment in ElementSpecific::doubleToNative. 580 if constexpr (!std::numeric_limits<NativeType>::is_integer) { 581 if (js::SupportDifferentialTesting()) { 582 value = JS::CanonicalizeNaN(static_cast<double>(value)); 583 } 584 } 585 586 // Step 6. 587 bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]); 588 589 // Steps 7-8. 590 auto viewSize = obj->byteLength(); 591 if (MOZ_UNLIKELY(!viewSize)) { 592 ReportOutOfBounds(cx, obj); 593 return false; 594 } 595 596 // Steps 9-12. 597 if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) { 598 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 599 JSMSG_OFFSET_OUT_OF_DATAVIEW); 600 return false; 601 } 602 603 // Steps 13-14. 604 bool isSharedMemory; 605 SharedMem<uint8_t*> data = 606 obj->getDataPointer<NativeType>(getIndex, *viewSize, &isSharedMemory); 607 MOZ_ASSERT(data); 608 609 if (isSharedMemory) { 610 DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(data, &value, 611 isLittleEndian); 612 } else { 613 DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value, 614 isLittleEndian); 615 } 616 return true; 617 } 618 619 bool DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args) { 620 MOZ_ASSERT(IsDataView(args.thisv())); 621 622 Rooted<DataViewObject*> thisView( 623 cx, &args.thisv().toObject().as<DataViewObject>()); 624 625 int8_t val; 626 if (!read(cx, thisView, args, &val)) { 627 return false; 628 } 629 args.rval().setInt32(val); 630 return true; 631 } 632 633 bool DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp) { 634 CallArgs args = CallArgsFromVp(argc, vp); 635 return CallNonGenericMethod<IsDataView, getInt8Impl>(cx, args); 636 } 637 638 bool DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args) { 639 MOZ_ASSERT(IsDataView(args.thisv())); 640 641 Rooted<DataViewObject*> thisView( 642 cx, &args.thisv().toObject().as<DataViewObject>()); 643 644 uint8_t val; 645 if (!read(cx, thisView, args, &val)) { 646 return false; 647 } 648 args.rval().setInt32(val); 649 return true; 650 } 651 652 bool DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp) { 653 CallArgs args = CallArgsFromVp(argc, vp); 654 return CallNonGenericMethod<IsDataView, getUint8Impl>(cx, args); 655 } 656 657 bool DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args) { 658 MOZ_ASSERT(IsDataView(args.thisv())); 659 660 Rooted<DataViewObject*> thisView( 661 cx, &args.thisv().toObject().as<DataViewObject>()); 662 663 int16_t val; 664 if (!read(cx, thisView, args, &val)) { 665 return false; 666 } 667 args.rval().setInt32(val); 668 return true; 669 } 670 671 bool DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp) { 672 CallArgs args = CallArgsFromVp(argc, vp); 673 return CallNonGenericMethod<IsDataView, getInt16Impl>(cx, args); 674 } 675 676 bool DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args) { 677 MOZ_ASSERT(IsDataView(args.thisv())); 678 679 Rooted<DataViewObject*> thisView( 680 cx, &args.thisv().toObject().as<DataViewObject>()); 681 682 uint16_t val; 683 if (!read(cx, thisView, args, &val)) { 684 return false; 685 } 686 args.rval().setInt32(val); 687 return true; 688 } 689 690 bool DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp) { 691 CallArgs args = CallArgsFromVp(argc, vp); 692 return CallNonGenericMethod<IsDataView, getUint16Impl>(cx, args); 693 } 694 695 bool DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args) { 696 MOZ_ASSERT(IsDataView(args.thisv())); 697 698 Rooted<DataViewObject*> thisView( 699 cx, &args.thisv().toObject().as<DataViewObject>()); 700 701 int32_t val; 702 if (!read(cx, thisView, args, &val)) { 703 return false; 704 } 705 args.rval().setInt32(val); 706 return true; 707 } 708 709 bool DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp) { 710 CallArgs args = CallArgsFromVp(argc, vp); 711 return CallNonGenericMethod<IsDataView, getInt32Impl>(cx, args); 712 } 713 714 bool DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args) { 715 MOZ_ASSERT(IsDataView(args.thisv())); 716 717 Rooted<DataViewObject*> thisView( 718 cx, &args.thisv().toObject().as<DataViewObject>()); 719 720 uint32_t val; 721 if (!read(cx, thisView, args, &val)) { 722 return false; 723 } 724 args.rval().setNumber(val); 725 return true; 726 } 727 728 bool DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp) { 729 CallArgs args = CallArgsFromVp(argc, vp); 730 return CallNonGenericMethod<IsDataView, getUint32Impl>(cx, args); 731 } 732 733 // BigInt proposal 7.26 734 // DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] ) 735 bool DataViewObject::getBigInt64Impl(JSContext* cx, const CallArgs& args) { 736 MOZ_ASSERT(IsDataView(args.thisv())); 737 738 Rooted<DataViewObject*> thisView( 739 cx, &args.thisv().toObject().as<DataViewObject>()); 740 741 int64_t val; 742 if (!read(cx, thisView, args, &val)) { 743 return false; 744 } 745 746 BigInt* bi = BigInt::createFromInt64(cx, val); 747 if (!bi) { 748 return false; 749 } 750 args.rval().setBigInt(bi); 751 return true; 752 } 753 754 bool DataViewObject::fun_getBigInt64(JSContext* cx, unsigned argc, Value* vp) { 755 CallArgs args = CallArgsFromVp(argc, vp); 756 return CallNonGenericMethod<IsDataView, getBigInt64Impl>(cx, args); 757 } 758 759 // BigInt proposal 7.27 760 // DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] ) 761 bool DataViewObject::getBigUint64Impl(JSContext* cx, const CallArgs& args) { 762 MOZ_ASSERT(IsDataView(args.thisv())); 763 764 Rooted<DataViewObject*> thisView( 765 cx, &args.thisv().toObject().as<DataViewObject>()); 766 767 int64_t val; 768 if (!read(cx, thisView, args, &val)) { 769 return false; 770 } 771 772 BigInt* bi = BigInt::createFromUint64(cx, val); 773 if (!bi) { 774 return false; 775 } 776 args.rval().setBigInt(bi); 777 return true; 778 } 779 780 bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) { 781 CallArgs args = CallArgsFromVp(argc, vp); 782 return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args); 783 } 784 785 bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) { 786 MOZ_ASSERT(IsDataView(args.thisv())); 787 788 Rooted<DataViewObject*> thisView( 789 cx, &args.thisv().toObject().as<DataViewObject>()); 790 791 float16 val{}; 792 if (!read(cx, thisView, args, &val)) { 793 return false; 794 } 795 796 args.rval().setDouble(CanonicalizeNaN(static_cast<double>(val))); 797 return true; 798 } 799 800 bool DataViewObject::fun_getFloat16(JSContext* cx, unsigned argc, Value* vp) { 801 CallArgs args = CallArgsFromVp(argc, vp); 802 return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args); 803 } 804 805 bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) { 806 MOZ_ASSERT(IsDataView(args.thisv())); 807 808 Rooted<DataViewObject*> thisView( 809 cx, &args.thisv().toObject().as<DataViewObject>()); 810 811 float val; 812 if (!read(cx, thisView, args, &val)) { 813 return false; 814 } 815 816 args.rval().setDouble(CanonicalizeNaN(val)); 817 return true; 818 } 819 820 bool DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp) { 821 CallArgs args = CallArgsFromVp(argc, vp); 822 return CallNonGenericMethod<IsDataView, getFloat32Impl>(cx, args); 823 } 824 825 bool DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args) { 826 MOZ_ASSERT(IsDataView(args.thisv())); 827 828 Rooted<DataViewObject*> thisView( 829 cx, &args.thisv().toObject().as<DataViewObject>()); 830 831 double val; 832 if (!read(cx, thisView, args, &val)) { 833 return false; 834 } 835 836 args.rval().setDouble(CanonicalizeNaN(val)); 837 return true; 838 } 839 840 bool DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp) { 841 CallArgs args = CallArgsFromVp(argc, vp); 842 return CallNonGenericMethod<IsDataView, getFloat64Impl>(cx, args); 843 } 844 845 bool DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args) { 846 MOZ_ASSERT(IsDataView(args.thisv())); 847 848 Rooted<DataViewObject*> thisView( 849 cx, &args.thisv().toObject().as<DataViewObject>()); 850 851 if (!write<int8_t>(cx, thisView, args)) { 852 return false; 853 } 854 args.rval().setUndefined(); 855 return true; 856 } 857 858 bool DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp) { 859 CallArgs args = CallArgsFromVp(argc, vp); 860 return CallNonGenericMethod<IsDataView, setInt8Impl>(cx, args); 861 } 862 863 bool DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args) { 864 MOZ_ASSERT(IsDataView(args.thisv())); 865 866 Rooted<DataViewObject*> thisView( 867 cx, &args.thisv().toObject().as<DataViewObject>()); 868 869 if (!write<uint8_t>(cx, thisView, args)) { 870 return false; 871 } 872 args.rval().setUndefined(); 873 return true; 874 } 875 876 bool DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp) { 877 CallArgs args = CallArgsFromVp(argc, vp); 878 return CallNonGenericMethod<IsDataView, setUint8Impl>(cx, args); 879 } 880 881 bool DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args) { 882 MOZ_ASSERT(IsDataView(args.thisv())); 883 884 Rooted<DataViewObject*> thisView( 885 cx, &args.thisv().toObject().as<DataViewObject>()); 886 887 if (!write<int16_t>(cx, thisView, args)) { 888 return false; 889 } 890 args.rval().setUndefined(); 891 return true; 892 } 893 894 bool DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp) { 895 CallArgs args = CallArgsFromVp(argc, vp); 896 return CallNonGenericMethod<IsDataView, setInt16Impl>(cx, args); 897 } 898 899 bool DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args) { 900 MOZ_ASSERT(IsDataView(args.thisv())); 901 902 Rooted<DataViewObject*> thisView( 903 cx, &args.thisv().toObject().as<DataViewObject>()); 904 905 if (!write<uint16_t>(cx, thisView, args)) { 906 return false; 907 } 908 args.rval().setUndefined(); 909 return true; 910 } 911 912 bool DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp) { 913 CallArgs args = CallArgsFromVp(argc, vp); 914 return CallNonGenericMethod<IsDataView, setUint16Impl>(cx, args); 915 } 916 917 bool DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args) { 918 MOZ_ASSERT(IsDataView(args.thisv())); 919 920 Rooted<DataViewObject*> thisView( 921 cx, &args.thisv().toObject().as<DataViewObject>()); 922 923 if (!write<int32_t>(cx, thisView, args)) { 924 return false; 925 } 926 args.rval().setUndefined(); 927 return true; 928 } 929 930 bool DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp) { 931 CallArgs args = CallArgsFromVp(argc, vp); 932 return CallNonGenericMethod<IsDataView, setInt32Impl>(cx, args); 933 } 934 935 bool DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args) { 936 MOZ_ASSERT(IsDataView(args.thisv())); 937 938 Rooted<DataViewObject*> thisView( 939 cx, &args.thisv().toObject().as<DataViewObject>()); 940 941 if (!write<uint32_t>(cx, thisView, args)) { 942 return false; 943 } 944 args.rval().setUndefined(); 945 return true; 946 } 947 948 bool DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp) { 949 CallArgs args = CallArgsFromVp(argc, vp); 950 return CallNonGenericMethod<IsDataView, setUint32Impl>(cx, args); 951 } 952 953 // BigInt proposal 7.28 954 // DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] ) 955 bool DataViewObject::setBigInt64Impl(JSContext* cx, const CallArgs& args) { 956 MOZ_ASSERT(IsDataView(args.thisv())); 957 958 Rooted<DataViewObject*> thisView( 959 cx, &args.thisv().toObject().as<DataViewObject>()); 960 961 if (!write<int64_t>(cx, thisView, args)) { 962 return false; 963 } 964 args.rval().setUndefined(); 965 return true; 966 } 967 968 bool DataViewObject::fun_setBigInt64(JSContext* cx, unsigned argc, Value* vp) { 969 CallArgs args = CallArgsFromVp(argc, vp); 970 return CallNonGenericMethod<IsDataView, setBigInt64Impl>(cx, args); 971 } 972 973 // BigInt proposal 7.29 974 // DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] ) 975 bool DataViewObject::setBigUint64Impl(JSContext* cx, const CallArgs& args) { 976 MOZ_ASSERT(IsDataView(args.thisv())); 977 978 Rooted<DataViewObject*> thisView( 979 cx, &args.thisv().toObject().as<DataViewObject>()); 980 981 if (!write<uint64_t>(cx, thisView, args)) { 982 return false; 983 } 984 args.rval().setUndefined(); 985 return true; 986 } 987 988 bool DataViewObject::fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp) { 989 CallArgs args = CallArgsFromVp(argc, vp); 990 return CallNonGenericMethod<IsDataView, setBigUint64Impl>(cx, args); 991 } 992 993 bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) { 994 MOZ_ASSERT(IsDataView(args.thisv())); 995 996 Rooted<DataViewObject*> thisView( 997 cx, &args.thisv().toObject().as<DataViewObject>()); 998 999 if (!write<float16>(cx, thisView, args)) { 1000 return false; 1001 } 1002 args.rval().setUndefined(); 1003 return true; 1004 } 1005 1006 bool DataViewObject::fun_setFloat16(JSContext* cx, unsigned argc, Value* vp) { 1007 CallArgs args = CallArgsFromVp(argc, vp); 1008 return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args); 1009 } 1010 1011 bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) { 1012 MOZ_ASSERT(IsDataView(args.thisv())); 1013 1014 Rooted<DataViewObject*> thisView( 1015 cx, &args.thisv().toObject().as<DataViewObject>()); 1016 1017 if (!write<float>(cx, thisView, args)) { 1018 return false; 1019 } 1020 args.rval().setUndefined(); 1021 return true; 1022 } 1023 1024 bool DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp) { 1025 CallArgs args = CallArgsFromVp(argc, vp); 1026 return CallNonGenericMethod<IsDataView, setFloat32Impl>(cx, args); 1027 } 1028 1029 bool DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args) { 1030 MOZ_ASSERT(IsDataView(args.thisv())); 1031 1032 Rooted<DataViewObject*> thisView( 1033 cx, &args.thisv().toObject().as<DataViewObject>()); 1034 1035 if (!write<double>(cx, thisView, args)) { 1036 return false; 1037 } 1038 args.rval().setUndefined(); 1039 return true; 1040 } 1041 1042 bool DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp) { 1043 CallArgs args = CallArgsFromVp(argc, vp); 1044 return CallNonGenericMethod<IsDataView, setFloat64Impl>(cx, args); 1045 } 1046 1047 bool DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args) { 1048 auto* thisView = &args.thisv().toObject().as<DataViewObject>(); 1049 args.rval().set(thisView->bufferValue()); 1050 return true; 1051 } 1052 1053 bool DataViewObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp) { 1054 CallArgs args = CallArgsFromVp(argc, vp); 1055 return CallNonGenericMethod<IsDataView, bufferGetterImpl>(cx, args); 1056 } 1057 1058 bool DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args) { 1059 auto* thisView = &args.thisv().toObject().as<DataViewObject>(); 1060 1061 // Step 6. 1062 auto byteLength = thisView->byteLength(); 1063 if (MOZ_UNLIKELY(!byteLength)) { 1064 ReportOutOfBounds(cx, thisView); 1065 return false; 1066 } 1067 1068 // Step 7. 1069 args.rval().set(NumberValue(*byteLength)); 1070 return true; 1071 } 1072 1073 bool DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp) { 1074 CallArgs args = CallArgsFromVp(argc, vp); 1075 return CallNonGenericMethod<IsDataView, byteLengthGetterImpl>(cx, args); 1076 } 1077 1078 bool DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args) { 1079 auto* thisView = &args.thisv().toObject().as<DataViewObject>(); 1080 1081 // Step 6. 1082 auto byteOffset = thisView->byteOffset(); 1083 if (MOZ_UNLIKELY(!byteOffset)) { 1084 ReportOutOfBounds(cx, thisView); 1085 return false; 1086 } 1087 1088 // Step 7. 1089 args.rval().set(NumberValue(*byteOffset)); 1090 return true; 1091 } 1092 1093 bool DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp) { 1094 CallArgs args = CallArgsFromVp(argc, vp); 1095 return CallNonGenericMethod<IsDataView, byteOffsetGetterImpl>(cx, args); 1096 } 1097 1098 static const JSClassOps DataViewObjectClassOps = { 1099 nullptr, // addProperty 1100 nullptr, // delProperty 1101 nullptr, // enumerate 1102 nullptr, // newEnumerate 1103 nullptr, // resolve 1104 nullptr, // mayResolve 1105 nullptr, // finalize 1106 nullptr, // call 1107 nullptr, // construct 1108 ArrayBufferViewObject::trace, // trace 1109 }; 1110 1111 static JSObject* CreateDataViewPrototype(JSContext* cx, JSProtoKey key) { 1112 return GlobalObject::createBlankPrototype(cx, cx->global(), 1113 &DataViewObject::protoClass_); 1114 } 1115 1116 const ClassSpec DataViewObject::classSpec_ = { 1117 GenericCreateConstructor<DataViewObject::construct, 1, 1118 gc::AllocKind::FUNCTION>, 1119 CreateDataViewPrototype, 1120 nullptr, 1121 nullptr, 1122 DataViewObject::methods, 1123 DataViewObject::properties, 1124 }; 1125 1126 const JSClass FixedLengthDataViewObject::class_ = { 1127 "DataView", 1128 JSCLASS_HAS_RESERVED_SLOTS(FixedLengthDataViewObject::RESERVED_SLOTS) | 1129 JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), 1130 &DataViewObjectClassOps, 1131 &DataViewObject::classSpec_, 1132 }; 1133 1134 const JSClass ResizableDataViewObject::class_ = { 1135 "DataView", 1136 JSCLASS_HAS_RESERVED_SLOTS(ResizableDataViewObject::RESERVED_SLOTS) | 1137 JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), 1138 &DataViewObjectClassOps, 1139 &DataViewObject::classSpec_, 1140 }; 1141 1142 const JSClass ImmutableDataViewObject::class_ = { 1143 "DataView", 1144 JSCLASS_HAS_RESERVED_SLOTS(ImmutableDataViewObject::RESERVED_SLOTS) | 1145 JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), 1146 &DataViewObjectClassOps, 1147 &DataViewObject::classSpec_, 1148 }; 1149 1150 const JSClass* const JS::DataView::FixedLengthClassPtr = 1151 &FixedLengthDataViewObject::class_; 1152 const JSClass* const JS::DataView::ResizableClassPtr = 1153 &ResizableDataViewObject::class_; 1154 const JSClass* const JS::DataView::ImmutableClassPtr = 1155 &ImmutableDataViewObject::class_; 1156 1157 const JSClass DataViewObject::protoClass_ = { 1158 "DataView.prototype", 1159 JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), 1160 JS_NULL_CLASS_OPS, 1161 &DataViewObject::classSpec_, 1162 }; 1163 1164 const JSFunctionSpec DataViewObject::methods[] = { 1165 JS_INLINABLE_FN("getInt8", DataViewObject::fun_getInt8, 1, 0, 1166 DataViewGetInt8), 1167 JS_INLINABLE_FN("getUint8", DataViewObject::fun_getUint8, 1, 0, 1168 DataViewGetUint8), 1169 JS_INLINABLE_FN("getInt16", DataViewObject::fun_getInt16, 1, 0, 1170 DataViewGetInt16), 1171 JS_INLINABLE_FN("getUint16", DataViewObject::fun_getUint16, 1, 0, 1172 DataViewGetUint16), 1173 JS_INLINABLE_FN("getInt32", DataViewObject::fun_getInt32, 1, 0, 1174 DataViewGetInt32), 1175 JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0, 1176 DataViewGetUint32), 1177 JS_INLINABLE_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0, 1178 DataViewGetFloat16), 1179 JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0, 1180 DataViewGetFloat32), 1181 JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0, 1182 DataViewGetFloat64), 1183 JS_INLINABLE_FN("getBigInt64", DataViewObject::fun_getBigInt64, 1, 0, 1184 DataViewGetBigInt64), 1185 JS_INLINABLE_FN("getBigUint64", DataViewObject::fun_getBigUint64, 1, 0, 1186 DataViewGetBigUint64), 1187 JS_INLINABLE_FN("setInt8", DataViewObject::fun_setInt8, 2, 0, 1188 DataViewSetInt8), 1189 JS_INLINABLE_FN("setUint8", DataViewObject::fun_setUint8, 2, 0, 1190 DataViewSetUint8), 1191 JS_INLINABLE_FN("setInt16", DataViewObject::fun_setInt16, 2, 0, 1192 DataViewSetInt16), 1193 JS_INLINABLE_FN("setUint16", DataViewObject::fun_setUint16, 2, 0, 1194 DataViewSetUint16), 1195 JS_INLINABLE_FN("setInt32", DataViewObject::fun_setInt32, 2, 0, 1196 DataViewSetInt32), 1197 JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0, 1198 DataViewSetUint32), 1199 JS_INLINABLE_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0, 1200 DataViewSetFloat16), 1201 JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0, 1202 DataViewSetFloat32), 1203 JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0, 1204 DataViewSetFloat64), 1205 JS_INLINABLE_FN("setBigInt64", DataViewObject::fun_setBigInt64, 2, 0, 1206 DataViewSetBigInt64), 1207 JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0, 1208 DataViewSetBigUint64), 1209 JS_FS_END, 1210 }; 1211 1212 const JSPropertySpec DataViewObject::properties[] = { 1213 JS_PSG("buffer", DataViewObject::bufferGetter, 0), 1214 JS_INLINABLE_PSG("byteLength", DataViewObject::byteLengthGetter, 0, 1215 DataViewByteLength), 1216 JS_INLINABLE_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0, 1217 DataViewByteOffset), 1218 JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY), 1219 JS_PS_END, 1220 }; 1221 1222 JS_PUBLIC_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer, 1223 size_t byteOffset, size_t byteLength) { 1224 JSProtoKey key = JSProto_DataView; 1225 RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key)); 1226 if (!constructor) { 1227 return nullptr; 1228 } 1229 1230 FixedConstructArgs<3> cargs(cx); 1231 1232 cargs[0].setObject(*buffer); 1233 cargs[1].setNumber(byteOffset); 1234 cargs[2].setNumber(byteLength); 1235 1236 RootedValue fun(cx, ObjectValue(*constructor)); 1237 RootedObject obj(cx); 1238 if (!Construct(cx, fun, cargs, fun, &obj)) { 1239 return nullptr; 1240 } 1241 return obj; 1242 } 1243 1244 JSObject* js::NewDataView(JSContext* cx, HandleObject buffer, 1245 size_t byteOffset) { 1246 JSProtoKey key = JSProto_DataView; 1247 RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key)); 1248 if (!constructor) { 1249 return nullptr; 1250 } 1251 1252 FixedConstructArgs<2> cargs(cx); 1253 1254 cargs[0].setObject(*buffer); 1255 cargs[1].setNumber(byteOffset); 1256 1257 RootedValue fun(cx, ObjectValue(*constructor)); 1258 RootedObject obj(cx); 1259 if (!Construct(cx, fun, cargs, fun, &obj)) { 1260 return nullptr; 1261 } 1262 return obj; 1263 }