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