LCOV - code coverage report
Current view: top level - js/src/vm - TypedArrayObject.h (source / functions) Hit Total Coverage
Test: output.info Lines: 8 132 6.1 %
Date: 2017-07-14 16:53:18 Functions: 3 37 8.1 %
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_TypedArrayObject_h
       8             : #define vm_TypedArrayObject_h
       9             : 
      10             : #include "mozilla/Attributes.h"
      11             : 
      12             : #include "jsobj.h"
      13             : 
      14             : #include "gc/Barrier.h"
      15             : #include "gc/Zone.h"
      16             : #include "js/Class.h"
      17             : #include "vm/ArrayBufferObject.h"
      18             : #include "vm/SharedArrayObject.h"
      19             : 
      20             : #define JS_FOR_EACH_TYPED_ARRAY(macro) \
      21             :     macro(int8_t, Int8) \
      22             :     macro(uint8_t, Uint8) \
      23             :     macro(int16_t, Int16) \
      24             :     macro(uint16_t, Uint16) \
      25             :     macro(int32_t, Int32) \
      26             :     macro(uint32_t, Uint32) \
      27             :     macro(float, Float32) \
      28             :     macro(double, Float64) \
      29             :     macro(uint8_clamped, Uint8Clamped)
      30             : 
      31             : typedef struct JSProperty JSProperty;
      32             : 
      33             : namespace js {
      34             : 
      35             : enum class TypedArrayLength { Fixed, Dynamic };
      36             : 
      37             : /*
      38             :  * TypedArrayObject
      39             :  *
      40             :  * The non-templated base class for the specific typed implementations.
      41             :  * This class holds all the member variables that are used by
      42             :  * the subclasses.
      43             :  */
      44             : 
      45             : class TypedArrayObject : public NativeObject
      46             : {
      47             :   public:
      48             :     // Underlying (Shared)ArrayBufferObject.
      49             :     static const size_t BUFFER_SLOT = 0;
      50             :     static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
      51             :                   "self-hosted code with burned-in constants must get the "
      52             :                   "right buffer slot");
      53             : 
      54             :     // Slot containing length of the view in number of typed elements.
      55             :     static const size_t LENGTH_SLOT = 1;
      56             :     static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
      57             :                   "self-hosted code with burned-in constants must get the "
      58             :                   "right length slot");
      59             : 
      60             :     // Offset of view within underlying (Shared)ArrayBufferObject.
      61             :     static const size_t BYTEOFFSET_SLOT = 2;
      62             :     static_assert(BYTEOFFSET_SLOT == JS_TYPEDARRAYLAYOUT_BYTEOFFSET_SLOT,
      63             :                   "self-hosted code with burned-in constants must get the "
      64             :                   "right byteOffset slot");
      65             : 
      66             :     static const size_t RESERVED_SLOTS = 3;
      67             : 
      68             : #ifdef DEBUG
      69             :     static const uint8_t ZeroLengthArrayData = 0x4A;
      70             : #endif
      71             : 
      72             :     static int lengthOffset();
      73             :     static int dataOffset();
      74             : 
      75             :     // The raw pointer to the buffer memory, the "private" value.
      76             :     //
      77             :     // This offset is exposed for performance reasons - so that it
      78             :     // need not be looked up on accesses.
      79             :     static const size_t DATA_SLOT = 3;
      80             : 
      81             :     static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
      82             :                   "bad inlined constant in jsfriendapi.h");
      83             : 
      84           0 :     static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
      85             :         // Inline buffers.
      86           0 :         if (!a->hasBuffer() || !b->hasBuffer())
      87           0 :             return a.get() == b.get();
      88             : 
      89             :         // Shared buffers.
      90           0 :         if (a->isSharedMemory() && b->isSharedMemory()) {
      91           0 :             return (a->bufferObject()->as<SharedArrayBufferObject>().globalID() ==
      92           0 :                     b->bufferObject()->as<SharedArrayBufferObject>().globalID());
      93             :         }
      94             : 
      95           0 :         return a->bufferObject() == b->bufferObject();
      96             :     }
      97             : 
      98             :     static const Class classes[Scalar::MaxTypedArrayViewType];
      99             :     static const Class protoClasses[Scalar::MaxTypedArrayViewType];
     100             :     static const Class sharedTypedArrayPrototypeClass;
     101             : 
     102           0 :     static const Class* classForType(Scalar::Type type) {
     103           0 :         MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
     104           0 :         return &classes[type];
     105             :     }
     106             : 
     107          60 :     static const Class* protoClassForType(Scalar::Type type) {
     108          60 :         MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
     109          60 :         return &protoClasses[type];
     110             :     }
     111             : 
     112             :     static const size_t FIXED_DATA_START = DATA_SLOT + 1;
     113             : 
     114             :     // For typed arrays which can store their data inline, the array buffer
     115             :     // object is created lazily.
     116             :     static const uint32_t INLINE_BUFFER_LIMIT =
     117             :         (NativeObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
     118             : 
     119             :     static gc::AllocKind
     120           0 :     AllocKindForLazyBuffer(size_t nbytes)
     121             :     {
     122           0 :         MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
     123           0 :         if (nbytes == 0)
     124           0 :             nbytes += sizeof(uint8_t);
     125           0 :         size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
     126           0 :         MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
     127           0 :         return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
     128             :     }
     129             : 
     130             :     inline Scalar::Type type() const;
     131             :     inline size_t bytesPerElement() const;
     132             : 
     133           0 :     static Value bufferValue(TypedArrayObject* tarr) {
     134           0 :         return tarr->getFixedSlot(BUFFER_SLOT);
     135             :     }
     136           0 :     static Value byteOffsetValue(TypedArrayObject* tarr) {
     137           0 :         Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
     138           0 :         MOZ_ASSERT(v.toInt32() >= 0);
     139           0 :         return v;
     140             :     }
     141           0 :     static Value byteLengthValue(TypedArrayObject* tarr) {
     142           0 :         return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
     143             :     }
     144           0 :     static Value lengthValue(TypedArrayObject* tarr) {
     145           0 :         return tarr->getFixedSlot(LENGTH_SLOT);
     146             :     }
     147             : 
     148             :     static bool
     149             :     ensureHasBuffer(JSContext* cx, Handle<TypedArrayObject*> tarray);
     150             : 
     151           0 :     bool hasBuffer() const {
     152           0 :         return bufferValue(const_cast<TypedArrayObject*>(this)).isObject();
     153             :     }
     154           0 :     JSObject* bufferObject() const {
     155           0 :         return bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
     156             :     }
     157           0 :     uint32_t byteOffset() const {
     158           0 :         return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
     159             :     }
     160           0 :     uint32_t byteLength() const {
     161           0 :         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     162             :     }
     163           0 :     uint32_t length() const {
     164           0 :         return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     165             :     }
     166             : 
     167             :     bool hasInlineElements() const;
     168             :     void setInlineElements();
     169           0 :     uint8_t* elementsRaw() const {
     170           0 :         return *(uint8_t **)((((char *)this) + this->dataOffset()));
     171             :     }
     172           0 :     uint8_t* elements() const {
     173           0 :         assertZeroLengthArrayData();
     174           0 :         return elementsRaw();
     175             :     }
     176             : 
     177             : #ifdef DEBUG
     178             :     void assertZeroLengthArrayData() const;
     179             : #else
     180             :     void assertZeroLengthArrayData() const {};
     181             : #endif
     182             : 
     183             :     Value getElement(uint32_t index);
     184             :     static void setElement(TypedArrayObject& obj, uint32_t index, double d);
     185             : 
     186             :     void notifyBufferDetached(JSContext* cx, void* newData);
     187             : 
     188             :     static bool
     189             :     GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
     190             :                                MutableHandleObject res);
     191             : 
     192             :     /*
     193             :      * Byte length above which created typed arrays and data views will have
     194             :      * singleton types regardless of the context in which they are created.
     195             :      */
     196             :     static const uint32_t SINGLETON_BYTE_LENGTH = 1024 * 1024 * 10;
     197             : 
     198             :     static bool isOriginalLengthGetter(Native native);
     199             : 
     200           0 :     ArrayBufferObject* bufferUnshared() const {
     201           0 :         MOZ_ASSERT(!isSharedMemory());
     202           0 :         JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
     203           0 :         if (!obj)
     204           0 :             return nullptr;
     205           0 :         return &obj->as<ArrayBufferObject>();
     206             :     }
     207           0 :     SharedArrayBufferObject* bufferShared() const {
     208           0 :         MOZ_ASSERT(isSharedMemory());
     209           0 :         JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
     210           0 :         if (!obj)
     211           0 :             return nullptr;
     212           0 :         return &obj->as<SharedArrayBufferObject>();
     213             :     }
     214           0 :     ArrayBufferObjectMaybeShared* bufferEither() const {
     215           0 :         JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
     216           0 :         if (!obj)
     217           0 :             return nullptr;
     218           0 :         if (isSharedMemory())
     219           0 :             return &obj->as<SharedArrayBufferObject>();
     220           0 :         return &obj->as<ArrayBufferObject>();
     221             :     }
     222             : 
     223           0 :     SharedMem<void*> viewDataShared() const {
     224           0 :         return SharedMem<void*>::shared(viewDataEither_());
     225             :     }
     226           0 :     SharedMem<void*> viewDataEither() const {
     227           0 :         if (isSharedMemory())
     228           0 :             return SharedMem<void*>::shared(viewDataEither_());
     229           0 :         return SharedMem<void*>::unshared(viewDataEither_());
     230             :     }
     231           0 :     void initViewData(SharedMem<uint8_t*> viewData) {
     232             :         // Install a pointer to the buffer location that corresponds
     233             :         // to offset zero within the typed array.
     234             :         //
     235             :         // The following unwrap is safe because the DATA_SLOT is
     236             :         // accessed only from jitted code and from the
     237             :         // viewDataEither_() accessor below; in neither case does the
     238             :         // raw pointer escape untagged into C++ code.
     239           0 :         initPrivate(viewData.unwrap(/*safe - see above*/));
     240           0 :     }
     241           0 :     void* viewDataUnshared() const {
     242           0 :         MOZ_ASSERT(!isSharedMemory());
     243           0 :         return viewDataEither_();
     244             :     }
     245             : 
     246           0 :     bool hasDetachedBuffer() const {
     247             :         // Shared buffers can't be detached.
     248           0 :         if (isSharedMemory())
     249           0 :             return false;
     250             : 
     251             :         // A typed array with a null buffer has never had its buffer exposed to
     252             :         // become detached.
     253           0 :         ArrayBufferObject* buffer = bufferUnshared();
     254           0 :         if (!buffer)
     255           0 :             return false;
     256             : 
     257           0 :         return buffer->isDetached();
     258             :     }
     259             : 
     260             :   private:
     261           0 :     void* viewDataEither_() const {
     262             :         // Note, do not check whether shared or not
     263             :         // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
     264           0 :         return static_cast<void*>(getPrivate(DATA_SLOT));
     265             :     }
     266             : 
     267             :   public:
     268             :     static void trace(JSTracer* trc, JSObject* obj);
     269             :     static void finalize(FreeOp* fop, JSObject* obj);
     270             :     static void objectMoved(JSObject* obj, const JSObject* old);
     271             :     static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
     272             :                                            gc::AllocKind allocKind);
     273             : 
     274             :     /* Initialization bits */
     275             : 
     276             :     template<Value ValueGetter(TypedArrayObject* tarr)>
     277             :     static bool
     278           0 :     GetterImpl(JSContext* cx, const CallArgs& args)
     279             :     {
     280           0 :         MOZ_ASSERT(is(args.thisv()));
     281           0 :         args.rval().set(ValueGetter(&args.thisv().toObject().as<TypedArrayObject>()));
     282           0 :         return true;
     283             :     }
     284             : 
     285             :     // ValueGetter is a function that takes an unwrapped typed array object and
     286             :     // returns a Value. Given such a function, Getter<> is a native that
     287             :     // retrieves a given Value, probably from a slot on the object.
     288             :     template<Value ValueGetter(TypedArrayObject* tarr)>
     289             :     static bool
     290           0 :     Getter(JSContext* cx, unsigned argc, Value* vp)
     291             :     {
     292           0 :         CallArgs args = CallArgsFromVp(argc, vp);
     293           0 :         return CallNonGenericMethod<is, GetterImpl<ValueGetter>>(cx, args);
     294             :     }
     295             : 
     296             :     static const JSFunctionSpec protoFunctions[];
     297             :     static const JSPropertySpec protoAccessors[];
     298             :     static const JSFunctionSpec staticFunctions[];
     299             :     static const JSPropertySpec staticProperties[];
     300             : 
     301             :     /* Accessors and functions */
     302             : 
     303             :     static bool is(HandleValue v);
     304             : 
     305             :     static bool set(JSContext* cx, unsigned argc, Value* vp);
     306             : 
     307             :   private:
     308             :     static bool set_impl(JSContext* cx, const CallArgs& args);
     309             : };
     310             : 
     311             : MOZ_MUST_USE bool TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp);
     312             : 
     313             : extern TypedArrayObject*
     314             : TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj, int32_t len);
     315             : 
     316             : inline bool
     317      796148 : IsTypedArrayClass(const Class* clasp)
     318             : {
     319      796148 :     return &TypedArrayObject::classes[0] <= clasp &&
     320      796148 :            clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
     321             : }
     322             : 
     323             : bool
     324             : IsTypedArrayConstructor(HandleValue v, uint32_t type);
     325             : 
     326             : inline Scalar::Type
     327           0 : TypedArrayObject::type() const
     328             : {
     329           0 :     MOZ_ASSERT(IsTypedArrayClass(getClass()));
     330           0 :     return static_cast<Scalar::Type>(getClass() - &classes[0]);
     331             : }
     332             : 
     333             : inline size_t
     334           0 : TypedArrayObject::bytesPerElement() const
     335             : {
     336           0 :     return Scalar::byteSize(type());
     337             : }
     338             : 
     339             : // Return value is whether the string is some integer. If the string is an
     340             : // integer which is not representable as a uint64_t, the return value is true
     341             : // and the resulting index is UINT64_MAX.
     342             : template <typename CharT>
     343             : bool
     344             : StringIsTypedArrayIndex(const CharT* s, size_t length, uint64_t* indexp);
     345             : 
     346             : inline bool
     347           0 : IsTypedArrayIndex(jsid id, uint64_t* indexp)
     348             : {
     349           0 :     if (JSID_IS_INT(id)) {
     350           0 :         int32_t i = JSID_TO_INT(id);
     351           0 :         MOZ_ASSERT(i >= 0);
     352           0 :         *indexp = (double)i;
     353           0 :         return true;
     354             :     }
     355             : 
     356           0 :     if (MOZ_UNLIKELY(!JSID_IS_STRING(id)))
     357           0 :         return false;
     358             : 
     359           0 :     JS::AutoCheckCannotGC nogc;
     360           0 :     JSAtom* atom = JSID_TO_ATOM(id);
     361           0 :     size_t length = atom->length();
     362             : 
     363           0 :     if (atom->hasLatin1Chars()) {
     364           0 :         const Latin1Char* s = atom->latin1Chars(nogc);
     365           0 :         if (!JS7_ISDEC(*s) && *s != '-')
     366           0 :             return false;
     367           0 :         return StringIsTypedArrayIndex(s, length, indexp);
     368             :     }
     369             : 
     370           0 :     const char16_t* s = atom->twoByteChars(nogc);
     371           0 :     if (!JS7_ISDEC(*s) && *s != '-')
     372           0 :         return false;
     373           0 :     return StringIsTypedArrayIndex(s, length, indexp);
     374             : }
     375             : 
     376             : /*
     377             :  * Implements [[DefineOwnProperty]] for TypedArrays when the property
     378             :  * key is a TypedArray index.
     379             :  */
     380             : bool
     381             : DefineTypedArrayElement(JSContext* cx, HandleObject arr, uint64_t index,
     382             :                         Handle<PropertyDescriptor> desc, ObjectOpResult& result);
     383             : 
     384             : static inline unsigned
     385           0 : TypedArrayShift(Scalar::Type viewType)
     386             : {
     387           0 :     switch (viewType) {
     388             :       case Scalar::Int8:
     389             :       case Scalar::Uint8:
     390             :       case Scalar::Uint8Clamped:
     391           0 :         return 0;
     392             :       case Scalar::Int16:
     393             :       case Scalar::Uint16:
     394           0 :         return 1;
     395             :       case Scalar::Int32:
     396             :       case Scalar::Uint32:
     397             :       case Scalar::Float32:
     398           0 :         return 2;
     399             :       case Scalar::Int64:
     400             :       case Scalar::Float64:
     401           0 :         return 3;
     402             :       case Scalar::Float32x4:
     403             :       case Scalar::Int8x16:
     404             :       case Scalar::Int16x8:
     405             :       case Scalar::Int32x4:
     406           0 :         return 4;
     407             :       default:;
     408             :     }
     409           0 :     MOZ_CRASH("Unexpected array type");
     410             : }
     411             : 
     412             : static inline unsigned
     413           0 : TypedArrayElemSize(Scalar::Type viewType)
     414             : {
     415           0 :     return 1u << TypedArrayShift(viewType);
     416             : }
     417             : 
     418             : // Assign
     419             : //
     420             : //   target[targetOffset] = unsafeSrcCrossCompartment[0]
     421             : //   ...
     422             : //   target[targetOffset + unsafeSrcCrossCompartment.length - 1] =
     423             : //       unsafeSrcCrossCompartment[unsafeSrcCrossCompartment.length - 1]
     424             : //
     425             : // where the source element range doesn't overlap the target element range in
     426             : // memory.
     427             : extern void
     428             : SetDisjointTypedElements(TypedArrayObject* target, uint32_t targetOffset,
     429             :                          TypedArrayObject* unsafeSrcCrossCompartment);
     430             : 
     431             : } // namespace js
     432             : 
     433             : template <>
     434             : inline bool
     435      540104 : JSObject::is<js::TypedArrayObject>() const
     436             : {
     437      540104 :     return js::IsTypedArrayClass(getClass());
     438             : }
     439             : 
     440             : #endif /* vm_TypedArrayObject_h */

Generated by: LCOV version 1.13