Source code

Revision control

Other Tools

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/Alignment.h"
10
#include "mozilla/Casting.h"
11
#include "mozilla/EndianUtils.h"
12
#include "mozilla/WrappingOperations.h"
13
14
#include <algorithm>
15
#include <string.h>
16
#include <type_traits>
17
18
#include "jsapi.h"
19
#include "jsnum.h"
20
21
#include "builtin/Array.h"
22
#include "jit/AtomicOperations.h"
23
#include "js/Conversions.h"
24
#include "js/PropertySpec.h"
25
#include "js/Wrapper.h"
26
#include "util/Windows.h"
27
#include "vm/ArrayBufferObject.h"
28
#include "vm/GlobalObject.h"
29
#include "vm/Interpreter.h"
30
#include "vm/JSContext.h"
31
#include "vm/JSObject.h"
32
#include "vm/SharedMem.h"
33
#include "vm/WrapperObject.h"
34
35
#include "gc/Nursery-inl.h"
36
#include "gc/StoreBuffer-inl.h"
37
#include "vm/ArrayBufferObject-inl.h"
38
#include "vm/NativeObject-inl.h"
39
40
using namespace js;
41
42
using JS::CanonicalizeNaN;
43
using JS::ToInt32;
44
using mozilla::AssertedCast;
45
using mozilla::WrapToSigned;
46
47
DataViewObject* DataViewObject::create(
48
JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
49
Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
50
if (arrayBuffer->isDetached()) {
51
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
52
JSMSG_TYPED_ARRAY_DETACHED);
53
return nullptr;
54
}
55
56
DataViewObject* obj = NewObjectWithClassProto<DataViewObject>(cx, proto);
57
if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength,
58
/* bytesPerElement = */ 1)) {
59
return nullptr;
60
}
61
62
return obj;
63
}
64
65
// ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
66
// 24.3.2.1 DataView (extracted part of the main algorithm)
67
bool DataViewObject::getAndCheckConstructorArgs(JSContext* cx,
68
HandleObject bufobj,
69
const CallArgs& args,
70
uint32_t* byteOffsetPtr,
71
uint32_t* byteLengthPtr) {
72
// Step 3.
73
if (!IsArrayBufferMaybeShared(bufobj)) {
74
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
75
JSMSG_NOT_EXPECTED_TYPE, "DataView",
76
"ArrayBuffer", bufobj->getClass()->name);
77
return false;
78
}
79
Rooted<ArrayBufferObjectMaybeShared*> buffer(
80
cx, &AsArrayBufferMaybeShared(bufobj));
81
82
// Step 4.
83
uint64_t offset;
84
if (!ToIndex(cx, args.get(1), &offset)) {
85
return false;
86
}
87
88
// Step 5.
89
if (buffer->isDetached()) {
90
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
91
JSMSG_TYPED_ARRAY_DETACHED);
92
return false;
93
}
94
95
// Step 6.
96
uint32_t bufferByteLength = buffer->byteLength();
97
98
// Step 7.
99
if (offset > bufferByteLength) {
100
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
101
JSMSG_OFFSET_OUT_OF_BUFFER);
102
return false;
103
}
104
MOZ_ASSERT(offset <= INT32_MAX);
105
106
// Step 8.a
107
uint64_t viewByteLength = bufferByteLength - offset;
108
if (args.hasDefined(2)) {
109
// Step 9.a.
110
if (!ToIndex(cx, args.get(2), &viewByteLength)) {
111
return false;
112
}
113
114
MOZ_ASSERT(offset + viewByteLength >= offset,
115
"can't overflow: both numbers are less than "
116
"DOUBLE_INTEGRAL_PRECISION_LIMIT");
117
118
// Step 9.b.
119
if (offset + viewByteLength > bufferByteLength) {
120
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
121
JSMSG_INVALID_DATA_VIEW_LENGTH);
122
return false;
123
}
124
}
125
MOZ_ASSERT(viewByteLength <= INT32_MAX);
126
127
*byteOffsetPtr = AssertedCast<uint32_t>(offset);
128
*byteLengthPtr = AssertedCast<uint32_t>(viewByteLength);
129
return true;
130
}
131
132
bool DataViewObject::constructSameCompartment(JSContext* cx,
133
HandleObject bufobj,
134
const CallArgs& args) {
135
MOZ_ASSERT(args.isConstructing());
136
cx->check(bufobj);
137
138
uint32_t byteOffset, byteLength;
139
if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength)) {
140
return false;
141
}
142
143
RootedObject proto(cx);
144
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
145
return false;
146
}
147
148
Rooted<ArrayBufferObjectMaybeShared*> buffer(
149
cx, &AsArrayBufferMaybeShared(bufobj));
150
JSObject* obj =
151
DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
152
if (!obj) {
153
return false;
154
}
155
args.rval().setObject(*obj);
156
return true;
157
}
158
159
// Create a DataView object in another compartment.
160
//
161
// ES6 supports creating a DataView in global A (using global A's DataView
162
// constructor) backed by an ArrayBuffer created in global B.
163
//
164
// Our DataViewObject implementation doesn't support a DataView in
165
// compartment A backed by an ArrayBuffer in compartment B. So in this case,
166
// we create the DataView in B (!) and return a cross-compartment wrapper.
167
//
168
// Extra twist: the spec says the new DataView's [[Prototype]] must be
169
// A's DataView.prototype. So even though we're creating the DataView in B,
170
// its [[Prototype]] must be (a cross-compartment wrapper for) the
171
// DataView.prototype in A.
172
bool DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj,
173
const CallArgs& args) {
174
MOZ_ASSERT(args.isConstructing());
175
MOZ_ASSERT(bufobj->is<WrapperObject>());
176
177
RootedObject unwrapped(cx, CheckedUnwrapStatic(bufobj));
178
if (!unwrapped) {
179
ReportAccessDenied(cx);
180
return false;
181
}
182
183
// NB: This entails the IsArrayBuffer check
184
uint32_t byteOffset, byteLength;
185
if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset,
186
&byteLength)) {
187
return false;
188
}
189
190
// Make sure to get the [[Prototype]] for the created view from this
191
// compartment.
192
RootedObject proto(cx);
193
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
194
return false;
195
}
196
197
Rooted<GlobalObject*> global(cx, cx->realm()->maybeGlobal());
198
if (!proto) {
199
proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
200
if (!proto) {
201
return false;
202
}
203
}
204
205
RootedObject dv(cx);
206
{
207
JSAutoRealm ar(cx, unwrapped);
208
209
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
210
buffer = &unwrapped->as<ArrayBufferObjectMaybeShared>();
211
212
RootedObject wrappedProto(cx, proto);
213
if (!cx->compartment()->wrap(cx, &wrappedProto)) {
214
return false;
215
}
216
217
dv = DataViewObject::create(cx, byteOffset, byteLength, buffer,
218
wrappedProto);
219
if (!dv) {
220
return false;
221
}
222
}
223
224
if (!cx->compartment()->wrap(cx, &dv)) {
225
return false;
226
}
227
228
args.rval().setObject(*dv);
229
return true;
230
}
231
232
bool DataViewObject::construct(JSContext* cx, unsigned argc, Value* vp) {
233
CallArgs args = CallArgsFromVp(argc, vp);
234
235
if (!ThrowIfNotConstructing(cx, args, "DataView")) {
236
return false;
237
}
238
239
RootedObject bufobj(cx);
240
if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj)) {
241
return false;
242
}
243
244
if (bufobj->is<WrapperObject>()) {
245
return constructWrapped(cx, bufobj, args);
246
}
247
return constructSameCompartment(cx, bufobj, args);
248
}
249
250
template <typename NativeType>
251
/* static */
252
SharedMem<uint8_t*> DataViewObject::getDataPointer(JSContext* cx,
253
Handle<DataViewObject*> obj,
254
uint64_t offset,
255
bool* isSharedMemory) {
256
const size_t TypeSize = sizeof(NativeType);
257
if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
258
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
259
JSMSG_OFFSET_OUT_OF_DATAVIEW);
260
return SharedMem<uint8_t*>::unshared(nullptr);
261
}
262
263
MOZ_ASSERT(offset < UINT32_MAX);
264
*isSharedMemory = obj->isSharedMemory();
265
return obj->dataPointerEither().cast<uint8_t*>() + uint32_t(offset);
266
}
267
268
static inline bool needToSwapBytes(bool littleEndian) {
269
#if MOZ_LITTLE_ENDIAN
270
return !littleEndian;
271
#else
272
return littleEndian;
273
#endif
274
}
275
276
static inline uint8_t swapBytes(uint8_t x) { return x; }
277
278
static inline uint16_t swapBytes(uint16_t x) {
279
return ((x & 0xff) << 8) | (x >> 8);
280
}
281
282
static inline uint32_t swapBytes(uint32_t x) {
283
return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) |
284
((x & 0xff000000) >> 24);
285
}
286
287
static inline uint64_t swapBytes(uint64_t x) {
288
uint32_t a = x & UINT32_MAX;
289
uint32_t b = x >> 32;
290
return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
291
}
292
293
template <typename DataType>
294
struct DataToRepType {
295
typedef DataType result;
296
};
297
template <>
298
struct DataToRepType<int8_t> {
299
typedef uint8_t result;
300
};
301
template <>
302
struct DataToRepType<uint8_t> {
303
typedef uint8_t result;
304
};
305
template <>
306
struct DataToRepType<int16_t> {
307
typedef uint16_t result;
308
};
309
template <>
310
struct DataToRepType<uint16_t> {
311
typedef uint16_t result;
312
};
313
template <>
314
struct DataToRepType<int32_t> {
315
typedef uint32_t result;
316
};
317
template <>
318
struct DataToRepType<uint32_t> {
319
typedef uint32_t result;
320
};
321
template <>
322
struct DataToRepType<int64_t> {
323
typedef uint64_t result;
324
};
325
template <>
326
struct DataToRepType<uint64_t> {
327
typedef uint64_t result;
328
};
329
template <>
330
struct DataToRepType<float> {
331
typedef uint32_t result;
332
};
333
template <>
334
struct DataToRepType<double> {
335
typedef uint64_t result;
336
};
337
338
static inline void Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes) {
339
memcpy(dest, src, nbytes);
340
}
341
342
static inline void Memcpy(uint8_t* dest, SharedMem<uint8_t*> src,
343
size_t nbytes) {
344
jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
345
}
346
347
static inline void Memcpy(SharedMem<uint8_t*> dest, uint8_t* src,
348
size_t nbytes) {
349
jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
350
}
351
352
template <typename DataType, typename BufferPtrType>
353
struct DataViewIO {
354
typedef typename DataToRepType<DataType>::result ReadWriteType;
355
356
static constexpr auto alignMask =
357
std::min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1;
358
359
static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer,
360
bool wantSwap) {
361
MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & alignMask) == 0);
362
Memcpy((uint8_t*)dest, unalignedBuffer, sizeof(ReadWriteType));
363
if (wantSwap) {
364
ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
365
*rwDest = swapBytes(*rwDest);
366
}
367
}
368
369
static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src,
370
bool wantSwap) {
371
MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & alignMask) == 0);
372
ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
373
if (wantSwap) {
374
temp = swapBytes(temp);
375
}
376
Memcpy(unalignedBuffer, (uint8_t*)&temp, sizeof(ReadWriteType));
377
}
378
};
379
380
template <typename NativeType>
381
/* static */
382
bool DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
383
const CallArgs& args, NativeType* val) {
384
// Steps 1-2. done by the caller
385
// Step 3. unnecessary assert
386
387
// Step 4.
388
uint64_t getIndex;
389
if (!ToIndex(cx, args.get(0), &getIndex)) {
390
return false;
391
}
392
393
// Step 5.
394
bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
395
396
// Steps 6-7.
397
if (obj->hasDetachedBuffer()) {
398
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
399
JSMSG_TYPED_ARRAY_DETACHED);
400
return false;
401
}
402
403
// Steps 8-12.
404
bool isSharedMemory;
405
SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(
406
cx, obj, getIndex, &isSharedMemory);
407
if (!data) {
408
return false;
409
}
410
411
// Step 13.
412
if (isSharedMemory) {
413
DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(
414
val, data, needToSwapBytes(isLittleEndian));
415
} else {
416
DataViewIO<NativeType, uint8_t*>::fromBuffer(
417
val, data.unwrapUnshared(), needToSwapBytes(isLittleEndian));
418
}
419
return true;
420
}
421
422
template <typename T>
423
static inline T WrappingConvert(int32_t value) {
424
if (std::is_unsigned<T>::value) {
425
return static_cast<T>(value);
426
}
427
428
return WrapToSigned(static_cast<typename std::make_unsigned<T>::type>(value));
429
}
430
431
template <typename NativeType>
432
static inline bool WebIDLCast(JSContext* cx, HandleValue value,
433
NativeType* out) {
434
int32_t i;
435
if (!ToInt32(cx, value, &i)) {
436
return false;
437
}
438
439
*out = WrappingConvert<NativeType>(i);
440
return true;
441
}
442
443
template <>
444
inline bool WebIDLCast<int64_t>(JSContext* cx, HandleValue value,
445
int64_t* out) {
446
RootedBigInt bi(cx, ToBigInt(cx, value));
447
if (!bi) {
448
return false;
449
}
450
*out = BigInt::toInt64(bi);
451
return true;
452
}
453
454
template <>
455
inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value,
456
uint64_t* out) {
457
RootedBigInt bi(cx, ToBigInt(cx, value));
458
if (!bi) {
459
return false;
460
}
461
*out = BigInt::toUint64(bi);
462
return true;
463
}
464
465
template <>
466
inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) {
467
double temp;
468
if (!ToNumber(cx, value, &temp)) {
469
return false;
470
}
471
*out = static_cast<float>(temp);
472
return true;
473
}
474
475
template <>
476
inline bool WebIDLCast<double>(JSContext* cx, HandleValue value, double* out) {
477
return ToNumber(cx, value, out);
478
}
479
481
// SetViewValue ( view, requestIndex, isLittleEndian, type, value )
482
template <typename NativeType>
483
/* static */
484
bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
485
const CallArgs& args) {
486
// Steps 1-2. done by the caller
487
// Step 3. unnecessary assert
488
489
// Step 4.
490
uint64_t getIndex;
491
if (!ToIndex(cx, args.get(0), &getIndex)) {
492
return false;
493
}
494
495
// Step 5. Extended by the BigInt proposal to call either ToBigInt or ToNumber
496
NativeType value;
497
if (!WebIDLCast(cx, args.get(1), &value)) {
498
return false;
499
}
500
501
#ifdef JS_MORE_DETERMINISTIC
502
// See the comment in ElementSpecific::doubleToNative.
503
if (TypeIsFloatingPoint<NativeType>()) {
504
value = JS::CanonicalizeNaN(value);
505
}
506
#endif
507
508
// Step 6.
509
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
510
511
// Steps 7-8.
512
if (obj->hasDetachedBuffer()) {
513
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
514
JSMSG_TYPED_ARRAY_DETACHED);
515
return false;
516
}
517
518
// Steps 9-13.
519
bool isSharedMemory;
520
SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(
521
cx, obj, getIndex, &isSharedMemory);
522
if (!data) {
523
return false;
524
}
525
526
// Step 14.
527
if (isSharedMemory) {
528
DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(
529
data, &value, needToSwapBytes(isLittleEndian));
530
} else {
531
DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value,
532
needToSwapBytes(isLittleEndian));
533
}
534
return true;
535
}
536
537
bool DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args) {
538
MOZ_ASSERT(is(args.thisv()));
539
540
Rooted<DataViewObject*> thisView(
541
cx, &args.thisv().toObject().as<DataViewObject>());
542
543
int8_t val;
544
if (!read(cx, thisView, args, &val)) {
545
return false;
546
}
547
args.rval().setInt32(val);
548
return true;
549
}
550
551
bool DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp) {
552
CallArgs args = CallArgsFromVp(argc, vp);
553
return CallNonGenericMethod<is, getInt8Impl>(cx, args);
554
}
555
556
bool DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args) {
557
MOZ_ASSERT(is(args.thisv()));
558
559
Rooted<DataViewObject*> thisView(
560
cx, &args.thisv().toObject().as<DataViewObject>());
561
562
uint8_t val;
563
if (!read(cx, thisView, args, &val)) {
564
return false;
565
}
566
args.rval().setInt32(val);
567
return true;
568
}
569
570
bool DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp) {
571
CallArgs args = CallArgsFromVp(argc, vp);
572
return CallNonGenericMethod<is, getUint8Impl>(cx, args);
573
}
574
575
bool DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args) {
576
MOZ_ASSERT(is(args.thisv()));
577
578
Rooted<DataViewObject*> thisView(
579
cx, &args.thisv().toObject().as<DataViewObject>());
580
581
int16_t val;
582
if (!read(cx, thisView, args, &val)) {
583
return false;
584
}
585
args.rval().setInt32(val);
586
return true;
587
}
588
589
bool DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp) {
590
CallArgs args = CallArgsFromVp(argc, vp);
591
return CallNonGenericMethod<is, getInt16Impl>(cx, args);
592
}
593
594
bool DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args) {
595
MOZ_ASSERT(is(args.thisv()));
596
597
Rooted<DataViewObject*> thisView(
598
cx, &args.thisv().toObject().as<DataViewObject>());
599
600
uint16_t val;
601
if (!read(cx, thisView, args, &val)) {
602
return false;
603
}
604
args.rval().setInt32(val);
605
return true;
606
}
607
608
bool DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp) {
609
CallArgs args = CallArgsFromVp(argc, vp);
610
return CallNonGenericMethod<is, getUint16Impl>(cx, args);
611
}
612
613
bool DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args) {
614
MOZ_ASSERT(is(args.thisv()));
615
616
Rooted<DataViewObject*> thisView(
617
cx, &args.thisv().toObject().as<DataViewObject>());
618
619
int32_t val;
620
if (!read(cx, thisView, args, &val)) {
621
return false;
622
}
623
args.rval().setInt32(val);
624
return true;
625
}
626
627
bool DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp) {
628
CallArgs args = CallArgsFromVp(argc, vp);
629
return CallNonGenericMethod<is, getInt32Impl>(cx, args);
630
}
631
632
bool DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args) {
633
MOZ_ASSERT(is(args.thisv()));
634
635
Rooted<DataViewObject*> thisView(
636
cx, &args.thisv().toObject().as<DataViewObject>());
637
638
uint32_t val;
639
if (!read(cx, thisView, args, &val)) {
640
return false;
641
}
642
args.rval().setNumber(val);
643
return true;
644
}
645
646
bool DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp) {
647
CallArgs args = CallArgsFromVp(argc, vp);
648
return CallNonGenericMethod<is, getUint32Impl>(cx, args);
649
}
650
651
// BigInt proposal 7.26
652
// DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] )
653
bool DataViewObject::getBigInt64Impl(JSContext* cx, const CallArgs& args) {
654
MOZ_ASSERT(is(args.thisv()));
655
656
Rooted<DataViewObject*> thisView(
657
cx, &args.thisv().toObject().as<DataViewObject>());
658
659
int64_t val;
660
if (!read(cx, thisView, args, &val)) {
661
return false;
662
}
663
664
BigInt* bi = BigInt::createFromInt64(cx, val);
665
if (!bi) {
666
return false;
667
}
668
args.rval().setBigInt(bi);
669
return true;
670
}
671
672
bool DataViewObject::fun_getBigInt64(JSContext* cx, unsigned argc, Value* vp) {
673
CallArgs args = CallArgsFromVp(argc, vp);
674
return CallNonGenericMethod<is, getBigInt64Impl>(cx, args);
675
}
676
677
// BigInt proposal 7.27
678
// DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )
679
bool DataViewObject::getBigUint64Impl(JSContext* cx, const CallArgs& args) {
680
MOZ_ASSERT(is(args.thisv()));
681
682
Rooted<DataViewObject*> thisView(
683
cx, &args.thisv().toObject().as<DataViewObject>());
684
685
int64_t val;
686
if (!read(cx, thisView, args, &val)) {
687
return false;
688
}
689
690
BigInt* bi = BigInt::createFromUint64(cx, val);
691
if (!bi) {
692
return false;
693
}
694
args.rval().setBigInt(bi);
695
return true;
696
}
697
698
bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) {
699
CallArgs args = CallArgsFromVp(argc, vp);
700
return CallNonGenericMethod<is, getBigUint64Impl>(cx, args);
701
}
702
703
bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
704
MOZ_ASSERT(is(args.thisv()));
705
706
Rooted<DataViewObject*> thisView(
707
cx, &args.thisv().toObject().as<DataViewObject>());
708
709
float val;
710
if (!read(cx, thisView, args, &val)) {
711
return false;
712
}
713
714
args.rval().setDouble(CanonicalizeNaN(val));
715
return true;
716
}
717
718
bool DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp) {
719
CallArgs args = CallArgsFromVp(argc, vp);
720
return CallNonGenericMethod<is, getFloat32Impl>(cx, args);
721
}
722
723
bool DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args) {
724
MOZ_ASSERT(is(args.thisv()));
725
726
Rooted<DataViewObject*> thisView(
727
cx, &args.thisv().toObject().as<DataViewObject>());
728
729
double val;
730
if (!read(cx, thisView, args, &val)) {
731
return false;
732
}
733
734
args.rval().setDouble(CanonicalizeNaN(val));
735
return true;
736
}
737
738
bool DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp) {
739
CallArgs args = CallArgsFromVp(argc, vp);
740
return CallNonGenericMethod<is, getFloat64Impl>(cx, args);
741
}
742
743
bool DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args) {
744
MOZ_ASSERT(is(args.thisv()));
745
746
Rooted<DataViewObject*> thisView(
747
cx, &args.thisv().toObject().as<DataViewObject>());
748
749
if (!write<int8_t>(cx, thisView, args)) {
750
return false;
751
}
752
args.rval().setUndefined();
753
return true;
754
}
755
756
bool DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp) {
757
CallArgs args = CallArgsFromVp(argc, vp);
758
return CallNonGenericMethod<is, setInt8Impl>(cx, args);
759
}
760
761
bool DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args) {
762
MOZ_ASSERT(is(args.thisv()));
763
764
Rooted<DataViewObject*> thisView(
765
cx, &args.thisv().toObject().as<DataViewObject>());
766
767
if (!write<uint8_t>(cx, thisView, args)) {
768
return false;
769
}
770
args.rval().setUndefined();
771
return true;
772
}
773
774
bool DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp) {
775
CallArgs args = CallArgsFromVp(argc, vp);
776
return CallNonGenericMethod<is, setUint8Impl>(cx, args);
777
}
778
779
bool DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args) {
780
MOZ_ASSERT(is(args.thisv()));
781
782
Rooted<DataViewObject*> thisView(
783
cx, &args.thisv().toObject().as<DataViewObject>());
784
785
if (!write<int16_t>(cx, thisView, args)) {
786
return false;
787
}
788
args.rval().setUndefined();
789
return true;
790
}
791
792
bool DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp) {
793
CallArgs args = CallArgsFromVp(argc, vp);
794
return CallNonGenericMethod<is, setInt16Impl>(cx, args);
795
}
796
797
bool DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args) {
798
MOZ_ASSERT(is(args.thisv()));
799
800
Rooted<DataViewObject*> thisView(
801
cx, &args.thisv().toObject().as<DataViewObject>());
802
803
if (!write<uint16_t>(cx, thisView, args)) {
804
return false;
805
}
806
args.rval().setUndefined();
807
return true;
808
}
809
810
bool DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp) {
811
CallArgs args = CallArgsFromVp(argc, vp);
812
return CallNonGenericMethod<is, setUint16Impl>(cx, args);
813
}
814
815
bool DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args) {
816
MOZ_ASSERT(is(args.thisv()));
817
818
Rooted<DataViewObject*> thisView(
819
cx, &args.thisv().toObject().as<DataViewObject>());
820
821
if (!write<int32_t>(cx, thisView, args)) {
822
return false;
823
}
824
args.rval().setUndefined();
825
return true;
826
}
827
828
bool DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp) {
829
CallArgs args = CallArgsFromVp(argc, vp);
830
return CallNonGenericMethod<is, setInt32Impl>(cx, args);
831
}
832
833
bool DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args) {
834
MOZ_ASSERT(is(args.thisv()));
835
836
Rooted<DataViewObject*> thisView(
837
cx, &args.thisv().toObject().as<DataViewObject>());
838
839
if (!write<uint32_t>(cx, thisView, args)) {
840
return false;
841
}
842
args.rval().setUndefined();
843
return true;
844
}
845
846
bool DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp) {
847
CallArgs args = CallArgsFromVp(argc, vp);
848
return CallNonGenericMethod<is, setUint32Impl>(cx, args);
849
}
850
851
// BigInt proposal 7.28
852
// DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] )
853
bool DataViewObject::setBigInt64Impl(JSContext* cx, const CallArgs& args) {
854
MOZ_ASSERT(is(args.thisv()));
855
856
Rooted<DataViewObject*> thisView(
857
cx, &args.thisv().toObject().as<DataViewObject>());
858
859
if (!write<int64_t>(cx, thisView, args)) {
860
return false;
861
}
862
args.rval().setUndefined();
863
return true;
864
}
865
866
bool DataViewObject::fun_setBigInt64(JSContext* cx, unsigned argc, Value* vp) {
867
CallArgs args = CallArgsFromVp(argc, vp);
868
return CallNonGenericMethod<is, setBigInt64Impl>(cx, args);
869
}
870
871
// BigInt proposal 7.29
872
// DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] )
873
bool DataViewObject::setBigUint64Impl(JSContext* cx, const CallArgs& args) {
874
MOZ_ASSERT(is(args.thisv()));
875
876
Rooted<DataViewObject*> thisView(
877
cx, &args.thisv().toObject().as<DataViewObject>());
878
879
if (!write<uint64_t>(cx, thisView, args)) {
880
return false;
881
}
882
args.rval().setUndefined();
883
return true;
884
}
885
886
bool DataViewObject::fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp) {
887
CallArgs args = CallArgsFromVp(argc, vp);
888
return CallNonGenericMethod<is, setBigUint64Impl>(cx, args);
889
}
890
891
bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
892
MOZ_ASSERT(is(args.thisv()));
893
894
Rooted<DataViewObject*> thisView(
895
cx, &args.thisv().toObject().as<DataViewObject>());
896
897
if (!write<float>(cx, thisView, args)) {
898
return false;
899
}
900
args.rval().setUndefined();
901
return true;
902
}
903
904
bool DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp) {
905
CallArgs args = CallArgsFromVp(argc, vp);
906
return CallNonGenericMethod<is, setFloat32Impl>(cx, args);
907
}
908
909
bool DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args) {
910
MOZ_ASSERT(is(args.thisv()));
911
912
Rooted<DataViewObject*> thisView(
913
cx, &args.thisv().toObject().as<DataViewObject>());
914
915
if (!write<double>(cx, thisView, args)) {
916
return false;
917
}
918
args.rval().setUndefined();
919
return true;
920
}
921
922
bool DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp) {
923
CallArgs args = CallArgsFromVp(argc, vp);
924
return CallNonGenericMethod<is, setFloat64Impl>(cx, args);
925
}
926
927
bool DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args) {
928
Rooted<DataViewObject*> thisView(
929
cx, &args.thisv().toObject().as<DataViewObject>());
930
args.rval().set(DataViewObject::bufferValue(thisView));
931
return true;
932
}
933
934
bool DataViewObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp) {
935
CallArgs args = CallArgsFromVp(argc, vp);
936
return CallNonGenericMethod<is, bufferGetterImpl>(cx, args);
937
}
938
939
bool DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args) {
940
Rooted<DataViewObject*> thisView(
941
cx, &args.thisv().toObject().as<DataViewObject>());
942
943
// Step 6.
944
if (thisView->hasDetachedBuffer()) {
945
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
946
JSMSG_TYPED_ARRAY_DETACHED);
947
return false;
948
}
949
950
// Step 7.
951
args.rval().set(DataViewObject::byteLengthValue(thisView));
952
return true;
953
}
954
955
bool DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp) {
956
CallArgs args = CallArgsFromVp(argc, vp);
957
return CallNonGenericMethod<is, byteLengthGetterImpl>(cx, args);
958
}
959
960
bool DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args) {
961
Rooted<DataViewObject*> thisView(
962
cx, &args.thisv().toObject().as<DataViewObject>());
963
964
// Step 6.
965
if (thisView->hasDetachedBuffer()) {
966
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
967
JSMSG_TYPED_ARRAY_DETACHED);
968
return false;
969
}
970
971
// Step 7.
972
args.rval().set(DataViewObject::byteOffsetValue(thisView));
973
return true;
974
}
975
976
bool DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp) {
977
CallArgs args = CallArgsFromVp(argc, vp);
978
return CallNonGenericMethod<is, byteOffsetGetterImpl>(cx, args);
979
}
980
981
JSObject* DataViewObject::CreatePrototype(JSContext* cx, JSProtoKey key) {
982
return GlobalObject::createBlankPrototype(cx, cx->global(),
983
&DataViewObject::protoClass_);
984
}
985
986
static const JSClassOps DataViewObjectClassOps = {nullptr, /* addProperty */
987
nullptr, /* delProperty */
988
nullptr, /* enumerate */
989
nullptr, /* newEnumerate */
990
nullptr, /* resolve */
991
nullptr, /* mayResolve */
992
nullptr, /* finalize */
993
nullptr, /* call */
994
nullptr, /* hasInstance */
995
nullptr, /* construct */
996
ArrayBufferViewObject::trace};
997
998
const ClassSpec DataViewObject::classSpec_ = {
999
GenericCreateConstructor<DataViewObject::construct, 1,
1000
gc::AllocKind::FUNCTION>,
1001
GenericCreatePrototype<DataViewObject>,
1002
nullptr,
1003
nullptr,
1004
DataViewObject::methods,
1005
DataViewObject::properties};
1006
1007
const JSClass DataViewObject::class_ = {
1008
"DataView",
1009
JSCLASS_HAS_PRIVATE |
1010
JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
1011
JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
1012
&DataViewObjectClassOps, &DataViewObject::classSpec_};
1013
1014
const JSClass DataViewObject::protoClass_ = {
1015
js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
1016
JS_NULL_CLASS_OPS, &DataViewObject::classSpec_};
1017
1018
const JSFunctionSpec DataViewObject::methods[] = {
1019
JS_FN("getInt8", DataViewObject::fun_getInt8, 1, 0),
1020
JS_FN("getUint8", DataViewObject::fun_getUint8, 1, 0),
1021
JS_FN("getInt16", DataViewObject::fun_getInt16, 1, 0),
1022
JS_FN("getUint16", DataViewObject::fun_getUint16, 1, 0),
1023
JS_FN("getInt32", DataViewObject::fun_getInt32, 1, 0),
1024
JS_FN("getUint32", DataViewObject::fun_getUint32, 1, 0),
1025
JS_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0),
1026
JS_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0),
1027
JS_FN("getBigInt64", DataViewObject::fun_getBigInt64, 1, 0),
1028
JS_FN("getBigUint64", DataViewObject::fun_getBigUint64, 1, 0),
1029
JS_FN("setInt8", DataViewObject::fun_setInt8, 2, 0),
1030
JS_FN("setUint8", DataViewObject::fun_setUint8, 2, 0),
1031
JS_FN("setInt16", DataViewObject::fun_setInt16, 2, 0),
1032
JS_FN("setUint16", DataViewObject::fun_setUint16, 2, 0),
1033
JS_FN("setInt32", DataViewObject::fun_setInt32, 2, 0),
1034
JS_FN("setUint32", DataViewObject::fun_setUint32, 2, 0),
1035
JS_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0),
1036
JS_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0),
1037
JS_FN("setBigInt64", DataViewObject::fun_setBigInt64, 2, 0),
1038
JS_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0),
1039
JS_FS_END};
1040
1041
const JSPropertySpec DataViewObject::properties[] = {
1042
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
1043
JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
1044
JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
1045
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY), JS_PS_END};
1046
1047
JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
1048
uint32_t byteOffset,
1049
int32_t byteLength) {
1050
JSProtoKey key = JSProto_DataView;
1051
RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
1052
if (!constructor) {
1053
return nullptr;
1054
}
1055
1056
FixedConstructArgs<3> cargs(cx);
1057
1058
cargs[0].setObject(*buffer);
1059
cargs[1].setNumber(byteOffset);
1060
cargs[2].setInt32(byteLength);
1061
1062
RootedValue fun(cx, ObjectValue(*constructor));
1063
RootedObject obj(cx);
1064
if (!Construct(cx, fun, cargs, fun, &obj)) {
1065
return nullptr;
1066
}
1067
return obj;
1068
}