Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 : #ifndef vm_ArrayBufferObject_h
8 : #define vm_ArrayBufferObject_h
9 :
10 : #include "mozilla/Maybe.h"
11 :
12 : #include "jsobj.h"
13 :
14 : #include "builtin/TypedObjectConstants.h"
15 : #include "js/GCHashTable.h"
16 : #include "vm/Runtime.h"
17 : #include "vm/SharedMem.h"
18 :
19 : typedef struct JSProperty JSProperty;
20 :
21 : namespace js {
22 :
23 : class ArrayBufferViewObject;
24 : class WasmArrayRawBuffer;
25 :
26 : // The inheritance hierarchy for the various classes relating to typed arrays
27 : // is as follows.
28 : //
29 : // - NativeObject
30 : // - ArrayBufferObjectMaybeShared
31 : // - ArrayBufferObject
32 : // - SharedArrayBufferObject
33 : // - DataViewObject
34 : // - TypedArrayObject (declared in vm/TypedArrayObject.h)
35 : // - TypedArrayObjectTemplate
36 : // - Int8ArrayObject
37 : // - Uint8ArrayObject
38 : // - ...
39 : // - JSObject
40 : // - ArrayBufferViewObject
41 : // - TypedObject (declared in builtin/TypedObject.h)
42 : //
43 : // Note that |TypedArrayObjectTemplate| is just an implementation
44 : // detail that makes implementing its various subclasses easier.
45 : //
46 : // ArrayBufferObject and SharedArrayBufferObject are unrelated data types:
47 : // the racy memory of the latter cannot substitute for the non-racy memory of
48 : // the former; the non-racy memory of the former cannot be used with the atomics;
49 : // the former can be detached and the latter not. Hence they have been
50 : // separated completely.
51 : //
52 : // Most APIs will only accept ArrayBufferObject. ArrayBufferObjectMaybeShared
53 : // exists as a join point to allow APIs that can take or use either, notably AsmJS.
54 : //
55 : // In contrast with the separation of ArrayBufferObject and
56 : // SharedArrayBufferObject, the TypedArray types can map either.
57 : //
58 : // The possible data ownership and reference relationships with ArrayBuffers
59 : // and related classes are enumerated below. These are the possible locations
60 : // for typed data:
61 : //
62 : // (1) malloc'ed or mmap'ed data owned by an ArrayBufferObject.
63 : // (2) Data allocated inline with an ArrayBufferObject.
64 : // (3) Data allocated inline with a TypedArrayObject.
65 : // (4) Data allocated inline with an InlineTypedObject.
66 : //
67 : // An ArrayBufferObject may point to any of these sources of data, except (3).
68 : // All array buffer views may point to any of these sources of data, except
69 : // that (3) may only be pointed to by the typed array the data is inline with.
70 : //
71 : // During a minor GC, (3) and (4) may move. During a compacting GC, (2), (3),
72 : // and (4) may move.
73 :
74 : class ArrayBufferObjectMaybeShared;
75 :
76 : uint32_t AnyArrayBufferByteLength(const ArrayBufferObjectMaybeShared* buf);
77 : mozilla::Maybe<uint32_t> WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf);
78 : size_t WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf);
79 : bool WasmArrayBufferGrowForWasm(ArrayBufferObjectMaybeShared* buf, uint32_t delta);
80 : bool AnyArrayBufferIsPreparedForAsmJS(const ArrayBufferObjectMaybeShared* buf);
81 : ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val);
82 :
83 : class ArrayBufferObjectMaybeShared : public NativeObject
84 : {
85 : public:
86 0 : uint32_t byteLength() {
87 0 : return AnyArrayBufferByteLength(this);
88 : }
89 :
90 : inline bool isDetached() const;
91 :
92 : inline SharedMem<uint8_t*> dataPointerEither();
93 :
94 : // WebAssembly support:
95 : // Note: the eventual goal is to remove this from ArrayBuffer and have
96 : // (Shared)ArrayBuffers alias memory owned by some wasm::Memory object.
97 :
98 0 : mozilla::Maybe<uint32_t> wasmMaxSize() const {
99 0 : return WasmArrayBufferMaxSize(this);
100 : }
101 0 : size_t wasmMappedSize() const {
102 0 : return WasmArrayBufferMappedSize(this);
103 : }
104 : #ifndef WASM_HUGE_MEMORY
105 : uint32_t wasmBoundsCheckLimit() const;
106 : #endif
107 :
108 0 : bool isPreparedForAsmJS() const {
109 0 : return AnyArrayBufferIsPreparedForAsmJS(this);
110 : }
111 : };
112 :
113 : typedef Rooted<ArrayBufferObjectMaybeShared*> RootedArrayBufferObjectMaybeShared;
114 : typedef Handle<ArrayBufferObjectMaybeShared*> HandleArrayBufferObjectMaybeShared;
115 : typedef MutableHandle<ArrayBufferObjectMaybeShared*> MutableHandleArrayBufferObjectMaybeShared;
116 :
117 : /*
118 : * ArrayBufferObject
119 : *
120 : * This class holds the underlying raw buffer that the various ArrayBufferViews
121 : * (eg DataViewObject, the TypedArrays, TypedObjects) access. It can be created
122 : * explicitly and used to construct an ArrayBufferView, or can be created
123 : * lazily when it is first accessed for a TypedArrayObject or TypedObject that
124 : * doesn't have an explicit buffer.
125 : *
126 : * ArrayBufferObject (or really the underlying memory) /is not racy/: the
127 : * memory is private to a single worker.
128 : */
129 : class ArrayBufferObject : public ArrayBufferObjectMaybeShared
130 : {
131 : static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
132 : static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
133 :
134 : public:
135 : static const uint8_t DATA_SLOT = 0;
136 : static const uint8_t BYTE_LENGTH_SLOT = 1;
137 : static const uint8_t FIRST_VIEW_SLOT = 2;
138 : static const uint8_t FLAGS_SLOT = 3;
139 :
140 : static const uint8_t RESERVED_SLOTS = 4;
141 :
142 : static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
143 :
144 : static_assert(FLAGS_SLOT == JS_ARRAYBUFFER_FLAGS_SLOT,
145 : "self-hosted code with burned-in constants must get the "
146 : "right flags slot");
147 :
148 : public:
149 :
150 : enum OwnsState {
151 : DoesntOwnData = 0,
152 : OwnsData = 1,
153 : };
154 :
155 : enum BufferKind {
156 : PLAIN = 0, // malloced or inline data
157 : WASM = 1,
158 : MAPPED = 2,
159 :
160 : KIND_MASK = 0x3
161 : };
162 :
163 : protected:
164 :
165 : enum ArrayBufferFlags {
166 : // The flags also store the BufferKind
167 : BUFFER_KIND_MASK = BufferKind::KIND_MASK,
168 :
169 : DETACHED = 0x4,
170 :
171 : // The dataPointer() is owned by this buffer and should be released
172 : // when no longer in use. Releasing the pointer may be done by either
173 : // freeing or unmapping it, and how to do this is determined by the
174 : // buffer's other flags.
175 : //
176 : // Array buffers which do not own their data include buffers that
177 : // allocate their data inline, and buffers that are created lazily for
178 : // typed objects with inline storage, in which case the buffer points
179 : // directly to the typed object's storage.
180 : OWNS_DATA = 0x8,
181 :
182 : // This array buffer was created lazily for a typed object with inline
183 : // data. This implies both that the typed object owns the buffer's data
184 : // and that the list of views sharing this buffer's data might be
185 : // incomplete. Any missing views will be typed objects.
186 : FOR_INLINE_TYPED_OBJECT = 0x10,
187 :
188 : // Views of this buffer might include typed objects.
189 : TYPED_OBJECT_VIEWS = 0x20,
190 :
191 : // This PLAIN or WASM buffer has been prepared for asm.js and cannot
192 : // henceforth be transferred/detached.
193 : FOR_ASMJS = 0x40
194 : };
195 :
196 : static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
197 : "self-hosted code with burned-in constants must use the "
198 : "correct DETACHED bit value");
199 : public:
200 :
201 : class BufferContents {
202 : uint8_t* data_;
203 : BufferKind kind_;
204 :
205 : friend class ArrayBufferObject;
206 :
207 0 : BufferContents(uint8_t* data, BufferKind kind) : data_(data), kind_(kind) {
208 0 : MOZ_ASSERT((kind_ & ~KIND_MASK) == 0);
209 0 : }
210 :
211 : public:
212 :
213 : template<BufferKind Kind>
214 0 : static BufferContents create(void* data)
215 : {
216 0 : return BufferContents(static_cast<uint8_t*>(data), Kind);
217 : }
218 :
219 0 : static BufferContents createPlain(void* data)
220 : {
221 0 : return BufferContents(static_cast<uint8_t*>(data), PLAIN);
222 : }
223 :
224 0 : uint8_t* data() const { return data_; }
225 0 : BufferKind kind() const { return kind_; }
226 :
227 0 : explicit operator bool() const { return data_ != nullptr; }
228 : WasmArrayRawBuffer* wasmBuffer() const;
229 : };
230 :
231 : static const Class class_;
232 : static const Class protoClass_;
233 :
234 : static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
235 :
236 : static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
237 :
238 : static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
239 :
240 : static bool fun_species(JSContext* cx, unsigned argc, Value* vp);
241 :
242 : static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
243 :
244 : static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
245 : BufferContents contents,
246 : OwnsState ownsState = OwnsData,
247 : HandleObject proto = nullptr,
248 : NewObjectKind newKind = GenericObject);
249 : static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
250 : HandleObject proto = nullptr,
251 : NewObjectKind newKind = GenericObject);
252 :
253 : // Create an ArrayBufferObject that is safely finalizable and can later be
254 : // initialize()d to become a real, content-visible ArrayBufferObject.
255 : static ArrayBufferObject* createEmpty(JSContext* cx);
256 :
257 : static void copyData(Handle<ArrayBufferObject*> toBuffer, uint32_t toIndex,
258 : Handle<ArrayBufferObject*> fromBuffer, uint32_t fromIndex,
259 : uint32_t count);
260 :
261 : static void trace(JSTracer* trc, JSObject* obj);
262 : static void objectMoved(JSObject* obj, const JSObject* old);
263 :
264 : static BufferContents externalizeContents(JSContext* cx,
265 : Handle<ArrayBufferObject*> buffer,
266 : bool hasStealableContents);
267 : static BufferContents stealContents(JSContext* cx,
268 : Handle<ArrayBufferObject*> buffer,
269 : bool hasStealableContents);
270 :
271 0 : bool hasStealableContents() const {
272 : // Inline elements strictly adhere to the corresponding buffer.
273 0 : return ownsData() && !isPreparedForAsmJS() && !isWasm();
274 : }
275 :
276 : static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
277 : JS::ClassInfo* info);
278 :
279 : // ArrayBufferObjects (strongly) store the first view added to them, while
280 : // later views are (weakly) stored in the compartment's InnerViewTable
281 : // below. Buffers usually only have one view, so this slot optimizes for
282 : // the common case. Avoiding entries in the InnerViewTable saves memory and
283 : // non-incrementalized sweep time.
284 : ArrayBufferViewObject* firstView();
285 :
286 : bool addView(JSContext* cx, JSObject* view);
287 :
288 : void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
289 : void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
290 :
291 : // Detach this buffer from its original memory. (This necessarily makes
292 : // views of this buffer unusable for modifying that original memory.)
293 : static void
294 : detach(JSContext* cx, Handle<ArrayBufferObject*> buffer, BufferContents newContents);
295 :
296 : private:
297 : void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
298 : uint8_t* oldDataPointer, BufferContents newContents);
299 : void setFirstView(ArrayBufferViewObject* view);
300 :
301 : uint8_t* inlineDataPointer() const;
302 :
303 : public:
304 : uint8_t* dataPointer() const;
305 : SharedMem<uint8_t*> dataPointerShared() const;
306 : uint32_t byteLength() const;
307 :
308 0 : BufferContents contents() const {
309 0 : return BufferContents(dataPointer(), bufferKind());
310 : }
311 0 : bool hasInlineData() const {
312 0 : return dataPointer() == inlineDataPointer();
313 : }
314 :
315 : void releaseData(FreeOp* fop);
316 :
317 : /*
318 : * Check if the arrayBuffer contains any data. This will return false for
319 : * ArrayBuffer.prototype and detached ArrayBuffers.
320 : */
321 0 : bool hasData() const {
322 0 : return getClass() == &class_;
323 : }
324 :
325 0 : BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
326 0 : bool isPlain() const { return bufferKind() == PLAIN; }
327 0 : bool isWasm() const { return bufferKind() == WASM; }
328 0 : bool isMapped() const { return bufferKind() == MAPPED; }
329 0 : bool isDetached() const { return flags() & DETACHED; }
330 0 : bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
331 :
332 : // WebAssembly support:
333 : static ArrayBufferObject* createForWasm(JSContext* cx, uint32_t initialSize,
334 : const mozilla::Maybe<uint32_t>& maxSize);
335 : static MOZ_MUST_USE bool prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer,
336 : bool needGuard);
337 : size_t wasmMappedSize() const;
338 : mozilla::Maybe<uint32_t> wasmMaxSize() const;
339 : static MOZ_MUST_USE bool wasmGrowToSizeInPlace(uint32_t newSize,
340 : Handle<ArrayBufferObject*> oldBuf,
341 : MutableHandle<ArrayBufferObject*> newBuf,
342 : JSContext* cx);
343 : #ifndef WASM_HUGE_MEMORY
344 : static MOZ_MUST_USE bool wasmMovingGrowToSize(uint32_t newSize,
345 : Handle<ArrayBufferObject*> oldBuf,
346 : MutableHandle<ArrayBufferObject*> newBuf,
347 : JSContext* cx);
348 : uint32_t wasmBoundsCheckLimit() const;
349 : #endif
350 :
351 : static void finalize(FreeOp* fop, JSObject* obj);
352 :
353 : static BufferContents createMappedContents(int fd, size_t offset, size_t length);
354 :
355 : static size_t offsetOfFlagsSlot() {
356 : return getFixedSlotOffset(FLAGS_SLOT);
357 : }
358 0 : static size_t offsetOfDataSlot() {
359 0 : return getFixedSlotOffset(DATA_SLOT);
360 : }
361 :
362 0 : void setForInlineTypedObject() {
363 0 : setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
364 0 : }
365 0 : void setHasTypedObjectViews() {
366 0 : setFlags(flags() | TYPED_OBJECT_VIEWS);
367 0 : }
368 :
369 0 : bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
370 :
371 : protected:
372 : void setDataPointer(BufferContents contents, OwnsState ownsState);
373 : void setByteLength(uint32_t length);
374 :
375 : uint32_t flags() const;
376 : void setFlags(uint32_t flags);
377 :
378 0 : bool ownsData() const { return flags() & OWNS_DATA; }
379 0 : void setOwnsData(OwnsState owns) {
380 0 : setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
381 0 : }
382 :
383 0 : bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
384 :
385 0 : void setIsDetached() { setFlags(flags() | DETACHED); }
386 0 : void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
387 :
388 0 : void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
389 0 : setByteLength(byteLength);
390 0 : setFlags(0);
391 0 : setFirstView(nullptr);
392 0 : setDataPointer(contents, ownsState);
393 0 : }
394 :
395 : // Note: initialize() may be called after initEmpty(); initEmpty() must
396 : // only initialize the ArrayBufferObject to a safe, finalizable state.
397 0 : void initEmpty() {
398 0 : setByteLength(0);
399 0 : setFlags(0);
400 0 : setFirstView(nullptr);
401 0 : setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
402 0 : }
403 : };
404 :
405 : typedef Rooted<ArrayBufferObject*> RootedArrayBufferObject;
406 : typedef Handle<ArrayBufferObject*> HandleArrayBufferObject;
407 : typedef MutableHandle<ArrayBufferObject*> MutableHandleArrayBufferObject;
408 :
409 : /*
410 : * ArrayBufferViewObject
411 : *
412 : * Common definitions shared by all array buffer views.
413 : */
414 :
415 : class ArrayBufferViewObject : public JSObject
416 : {
417 : public:
418 : static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);
419 :
420 : void notifyBufferDetached(JSContext* cx, void* newData);
421 :
422 : #ifdef DEBUG
423 : bool isSharedMemory();
424 : #endif
425 :
426 : // By construction we only need unshared variants here. See
427 : // comments in ArrayBufferObject.cpp.
428 : uint8_t* dataPointerUnshared(const JS::AutoRequireNoGC&);
429 : void setDataPointerUnshared(uint8_t* data);
430 :
431 : static void trace(JSTracer* trc, JSObject* obj);
432 : };
433 :
434 : bool
435 : ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out);
436 :
437 : /*
438 : * Tests for ArrayBufferObject, like obj->is<ArrayBufferObject>().
439 : */
440 : bool IsArrayBuffer(HandleValue v);
441 : bool IsArrayBuffer(HandleObject obj);
442 : bool IsArrayBuffer(JSObject* obj);
443 : ArrayBufferObject& AsArrayBuffer(HandleObject obj);
444 : ArrayBufferObject& AsArrayBuffer(JSObject* obj);
445 :
446 : /*
447 : * Ditto for ArrayBufferObjectMaybeShared.
448 : */
449 : bool IsArrayBufferMaybeShared(HandleValue v);
450 : bool IsArrayBufferMaybeShared(HandleObject obj);
451 : bool IsArrayBufferMaybeShared(JSObject* obj);
452 : ArrayBufferObjectMaybeShared& AsArrayBufferMaybeShared(HandleObject obj);
453 : ArrayBufferObjectMaybeShared& AsArrayBufferMaybeShared(JSObject* obj);
454 :
455 : extern uint32_t JS_FASTCALL
456 : ClampDoubleToUint8(const double x);
457 :
458 : struct uint8_clamped {
459 : uint8_t val;
460 :
461 0 : uint8_clamped() { }
462 0 : uint8_clamped(const uint8_clamped& other) : val(other.val) { }
463 :
464 : // invoke our assignment helpers for constructor conversion
465 0 : explicit uint8_clamped(uint8_t x) { *this = x; }
466 0 : explicit uint8_clamped(uint16_t x) { *this = x; }
467 0 : explicit uint8_clamped(uint32_t x) { *this = x; }
468 0 : explicit uint8_clamped(int8_t x) { *this = x; }
469 0 : explicit uint8_clamped(int16_t x) { *this = x; }
470 0 : explicit uint8_clamped(int32_t x) { *this = x; }
471 0 : explicit uint8_clamped(double x) { *this = x; }
472 :
473 0 : uint8_clamped& operator=(const uint8_clamped& x) {
474 0 : val = x.val;
475 0 : return *this;
476 : }
477 :
478 0 : uint8_clamped& operator=(uint8_t x) {
479 0 : val = x;
480 0 : return *this;
481 : }
482 :
483 0 : uint8_clamped& operator=(uint16_t x) {
484 0 : val = (x > 255) ? 255 : uint8_t(x);
485 0 : return *this;
486 : }
487 :
488 0 : uint8_clamped& operator=(uint32_t x) {
489 0 : val = (x > 255) ? 255 : uint8_t(x);
490 0 : return *this;
491 : }
492 :
493 0 : uint8_clamped& operator=(int8_t x) {
494 0 : val = (x >= 0) ? uint8_t(x) : 0;
495 0 : return *this;
496 : }
497 :
498 0 : uint8_clamped& operator=(int16_t x) {
499 0 : val = (x >= 0)
500 : ? ((x < 255)
501 : ? uint8_t(x)
502 : : 255)
503 0 : : 0;
504 0 : return *this;
505 : }
506 :
507 0 : uint8_clamped& operator=(int32_t x) {
508 0 : val = (x >= 0)
509 : ? ((x < 255)
510 : ? uint8_t(x)
511 : : 255)
512 0 : : 0;
513 0 : return *this;
514 : }
515 :
516 0 : uint8_clamped& operator=(const double x) {
517 0 : val = uint8_t(ClampDoubleToUint8(x));
518 0 : return *this;
519 : }
520 :
521 0 : operator uint8_t() const {
522 0 : return val;
523 : }
524 :
525 : void staticAsserts() {
526 : static_assert(sizeof(uint8_clamped) == 1,
527 : "uint8_clamped must be layout-compatible with uint8_t");
528 : }
529 : };
530 :
531 : /* Note that we can't use std::numeric_limits here due to uint8_clamped. */
532 0 : template<typename T> inline bool TypeIsFloatingPoint() { return false; }
533 0 : template<> inline bool TypeIsFloatingPoint<float>() { return true; }
534 0 : template<> inline bool TypeIsFloatingPoint<double>() { return true; }
535 :
536 0 : template<typename T> inline bool TypeIsUnsigned() { return false; }
537 0 : template<> inline bool TypeIsUnsigned<uint8_t>() { return true; }
538 0 : template<> inline bool TypeIsUnsigned<uint16_t>() { return true; }
539 0 : template<> inline bool TypeIsUnsigned<uint32_t>() { return true; }
540 :
541 : // Per-compartment table that manages the relationship between array buffers
542 : // and the views that use their storage.
543 0 : class InnerViewTable
544 : {
545 : public:
546 : typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
547 :
548 : friend class ArrayBufferObject;
549 :
550 : private:
551 : struct MapGCPolicy {
552 0 : static bool needsSweep(JSObject** key, ViewVector* value) {
553 0 : return InnerViewTable::sweepEntry(key, *value);
554 : }
555 : };
556 :
557 : // This key is a raw pointer and not a ReadBarriered because the post-
558 : // barrier would hold nursery-allocated entries live unconditionally. It is
559 : // a very common pattern in low-level and performance-oriented JavaScript
560 : // to create hundreds or thousands of very short lived temporary views on a
561 : // larger buffer; having to tenured all of these would be a catastrophic
562 : // performance regression. Thus, it is vital that nursery pointers in this
563 : // map not be held live. Special support is required in the minor GC,
564 : // implemented in sweepAfterMinorGC.
565 : typedef GCHashMap<JSObject*,
566 : ViewVector,
567 : MovableCellHasher<JSObject*>,
568 : SystemAllocPolicy,
569 : MapGCPolicy> Map;
570 :
571 : // For all objects sharing their storage with some other view, this maps
572 : // the object to the list of such views. All entries in this map are weak.
573 : Map map;
574 :
575 : // List of keys from innerViews where either the source or at least one
576 : // target is in the nursery. The raw pointer to a JSObject is allowed here
577 : // because this vector is cleared after every minor collection. Users in
578 : // sweepAfterMinorCollection must be careful to use MaybeForwarded before
579 : // touching these pointers.
580 : Vector<JSObject*, 0, SystemAllocPolicy> nurseryKeys;
581 :
582 : // Whether nurseryKeys is a complete list.
583 : bool nurseryKeysValid;
584 :
585 : // Sweep an entry during GC, returning whether the entry should be removed.
586 : static bool sweepEntry(JSObject** pkey, ViewVector& views);
587 :
588 : bool addView(JSContext* cx, ArrayBufferObject* obj, ArrayBufferViewObject* view);
589 : ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj);
590 : void removeViews(ArrayBufferObject* obj);
591 :
592 : public:
593 315 : InnerViewTable()
594 315 : : nurseryKeysValid(true)
595 315 : {}
596 :
597 : // Remove references to dead objects in the table and update table entries
598 : // to reflect moved objects.
599 : void sweep();
600 : void sweepAfterMinorGC();
601 :
602 0 : bool needsSweep() const {
603 0 : return map.needsSweep();
604 : }
605 :
606 2415 : bool needsSweepAfterMinorGC() const {
607 2415 : return !nurseryKeys.empty() || !nurseryKeysValid;
608 : }
609 :
610 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
611 : };
612 :
613 : template <typename Wrapper>
614 315 : class MutableWrappedPtrOperations<InnerViewTable, Wrapper>
615 : : public WrappedPtrOperations<InnerViewTable, Wrapper>
616 : {
617 0 : InnerViewTable& table() {
618 0 : return static_cast<Wrapper*>(this)->get();
619 : }
620 :
621 : public:
622 0 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
623 0 : return table().sizeOfExcludingThis(mallocSizeOf);
624 : }
625 : };
626 :
627 : } // namespace js
628 :
629 : template <>
630 : bool
631 : JSObject::is<js::ArrayBufferViewObject>() const;
632 :
633 : template <>
634 : bool
635 : JSObject::is<js::ArrayBufferObjectMaybeShared>() const;
636 :
637 : #endif // vm_ArrayBufferObject_h
|