LCOV - code coverage report
Current view: top level - js/src/vm - ArrayBufferObject.h (source / functions) Hit Total Coverage
Test: output.info Lines: 6 119 5.0 %
Date: 2017-07-14 16:53:18 Functions: 3 77 3.9 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13