/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ /* vim: set ts=2 sw=2 et tw=79: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_TypedArray_h #define mozilla_dom_TypedArray_h #include "jsapi.h" #include "jsfriendapi.h" #include "js/RootingAPI.h" #include "js/TracingAPI.h" #include "mozilla/Attributes.h" #include "mozilla/Move.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsWrapperCache.h" namespace mozilla { namespace dom { /* * Class that just handles the JSObject storage and tracing for typed arrays */ struct TypedArrayObjectStorage : AllTypedArraysBase { protected: JSObject* mTypedObj; JSObject* mWrappedObj; TypedArrayObjectStorage() : mTypedObj(nullptr), mWrappedObj(nullptr) { } explicit TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther) : mTypedObj(aOther.mTypedObj), mWrappedObj(aOther.mWrappedObj) { aOther.mTypedObj = nullptr; aOther.mWrappedObj = nullptr; } public: inline void TraceSelf(JSTracer* trc) { if (mTypedObj) { JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mTypedObj"); } if (mWrappedObj) { JS_CallUnbarrieredObjectTracer(trc, &mTypedObj, "TypedArray.mWrappedObj"); } } private: TypedArrayObjectStorage(const TypedArrayObjectStorage&) MOZ_DELETE; }; /* * Various typed array classes for argument conversion. We have a base class * that has a way of initializing a TypedArray from an existing typed array, and * a subclass of the base class that supports creation of a relevant typed array * or array buffer object. */ template struct TypedArray_base : public TypedArrayObjectStorage { typedef T element_type; TypedArray_base() : mData(nullptr), mLength(0), mComputed(false) { } explicit TypedArray_base(TypedArray_base&& aOther) : TypedArrayObjectStorage(Move(aOther)), mData(aOther.mData), mLength(aOther.mLength), mComputed(aOther.mComputed) { aOther.mData = nullptr; aOther.mLength = 0; aOther.mComputed = false; } private: mutable T* mData; mutable uint32_t mLength; mutable bool mComputed; public: inline bool Init(JSObject* obj) { MOZ_ASSERT(!inited()); mTypedObj = mWrappedObj = UnwrapArray(obj); return inited(); } inline bool inited() const { return !!mTypedObj; } inline T *Data() const { MOZ_ASSERT(mComputed); return mData; } inline uint32_t Length() const { MOZ_ASSERT(mComputed); return mLength; } inline JSObject *Obj() const { MOZ_ASSERT(inited()); return mWrappedObj; } inline bool WrapIntoNewCompartment(JSContext* cx) { return JS_WrapObject(cx, JS::MutableHandle::fromMarkedLocation(&mWrappedObj)); } inline void ComputeLengthAndData() const { MOZ_ASSERT(inited()); MOZ_ASSERT(!mComputed); GetLengthAndData(mTypedObj, &mLength, &mData); mComputed = true; } private: TypedArray_base(const TypedArray_base&) MOZ_DELETE; }; template struct TypedArray : public TypedArray_base { private: typedef TypedArray_base Base; public: TypedArray() : Base() {} explicit TypedArray(TypedArray&& aOther) : Base(Move(aOther)) { } static inline JSObject* Create(JSContext* cx, nsWrapperCache* creator, uint32_t length, const T* data = nullptr) { JS::Rooted creatorWrapper(cx); Maybe ac; if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) { ac.emplace(cx, creatorWrapper); } return CreateCommon(cx, length, data); } static inline JSObject* Create(JSContext* cx, uint32_t length, const T* data = nullptr) { return CreateCommon(cx, length, data); } private: static inline JSObject* CreateCommon(JSContext* cx, uint32_t length, const T* data) { JSObject* obj = CreateNew(cx, length); if (!obj) { return nullptr; } if (data) { JS::AutoCheckCannotGC nogc; T* buf = static_cast(GetData(obj, nogc)); memcpy(buf, data, length*sizeof(T)); } return obj; } TypedArray(const TypedArray&) MOZ_DELETE; }; typedef TypedArray Int8Array; typedef TypedArray Uint8Array; typedef TypedArray Uint8ClampedArray; typedef TypedArray Int16Array; typedef TypedArray Uint16Array; typedef TypedArray Int32Array; typedef TypedArray Uint32Array; typedef TypedArray Float32Array; typedef TypedArray Float64Array; typedef TypedArray_base ArrayBufferView; typedef TypedArray ArrayBuffer; // A class for converting an nsTArray to a TypedArray // Note: A TypedArrayCreator must not outlive the nsTArray it was created from. // So this is best used to pass from things that understand nsTArray to // things that understand TypedArray, as with Promise::ArgumentToJSValue. template class TypedArrayCreator { typedef nsTArray ArrayType; public: explicit TypedArrayCreator(const ArrayType& aArray) : mArray(aArray) {} JSObject* Create(JSContext* aCx) const { return TypedArrayType::Create(aCx, mArray.Length(), mArray.Elements()); } private: const ArrayType& mArray; }; // A class for rooting an existing TypedArray struct template class MOZ_STACK_CLASS TypedArrayRooter : private JS::CustomAutoRooter { public: TypedArrayRooter(JSContext* cx, ArrayType* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), mArray(aArray) { } virtual void trace(JSTracer* trc) MOZ_OVERRIDE { mArray->TraceSelf(trc); } private: TypedArrayObjectStorage* const mArray; }; // And a specialization for dealing with nullable typed arrays template struct Nullable; template class MOZ_STACK_CLASS TypedArrayRooter > : private JS::CustomAutoRooter { public: TypedArrayRooter(JSContext* cx, Nullable* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), mArray(aArray) { } virtual void trace(JSTracer* trc) MOZ_OVERRIDE { if (!mArray->IsNull()) { mArray->Value().TraceSelf(trc); } } private: Nullable* const mArray; }; // Class for easily setting up a rooted typed array object on the stack template class MOZ_STACK_CLASS RootedTypedArray : public ArrayType, private TypedArrayRooter { public: explicit RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ArrayType(), TypedArrayRooter(cx, MOZ_THIS_IN_INITIALIZER_LIST() MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) { } RootedTypedArray(JSContext* cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ArrayType(obj), TypedArrayRooter(cx, MOZ_THIS_IN_INITIALIZER_LIST() MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) { } }; } // namespace dom } // namespace mozilla #endif /* mozilla_dom_TypedArray_h */