Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=79: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef mozilla_dom_TypedArray_h |
michael@0 | 8 | #define mozilla_dom_TypedArray_h |
michael@0 | 9 | |
michael@0 | 10 | #include "jsapi.h" |
michael@0 | 11 | #include "jsfriendapi.h" |
michael@0 | 12 | #include "js/RootingAPI.h" |
michael@0 | 13 | #include "js/TracingAPI.h" |
michael@0 | 14 | #include "mozilla/Attributes.h" |
michael@0 | 15 | #include "mozilla/Move.h" |
michael@0 | 16 | #include "mozilla/dom/BindingDeclarations.h" |
michael@0 | 17 | #include "nsWrapperCache.h" |
michael@0 | 18 | |
michael@0 | 19 | namespace mozilla { |
michael@0 | 20 | namespace dom { |
michael@0 | 21 | |
michael@0 | 22 | /* |
michael@0 | 23 | * Class that just handles the JSObject storage and tracing for typed arrays |
michael@0 | 24 | */ |
michael@0 | 25 | struct TypedArrayObjectStorage : AllTypedArraysBase { |
michael@0 | 26 | protected: |
michael@0 | 27 | JSObject* mObj; |
michael@0 | 28 | |
michael@0 | 29 | TypedArrayObjectStorage(JSObject *obj) : mObj(obj) |
michael@0 | 30 | { |
michael@0 | 31 | } |
michael@0 | 32 | |
michael@0 | 33 | explicit TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther) |
michael@0 | 34 | : mObj(aOther.mObj) |
michael@0 | 35 | { |
michael@0 | 36 | aOther.mObj = nullptr; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | public: |
michael@0 | 40 | inline void TraceSelf(JSTracer* trc) |
michael@0 | 41 | { |
michael@0 | 42 | if (mObj) { |
michael@0 | 43 | JS_CallObjectTracer(trc, &mObj, "TypedArray.mObj"); |
michael@0 | 44 | } |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | private: |
michael@0 | 48 | TypedArrayObjectStorage(const TypedArrayObjectStorage&) MOZ_DELETE; |
michael@0 | 49 | }; |
michael@0 | 50 | |
michael@0 | 51 | /* |
michael@0 | 52 | * Various typed array classes for argument conversion. We have a base class |
michael@0 | 53 | * that has a way of initializing a TypedArray from an existing typed array, and |
michael@0 | 54 | * a subclass of the base class that supports creation of a relevant typed array |
michael@0 | 55 | * or array buffer object. |
michael@0 | 56 | */ |
michael@0 | 57 | template<typename T, |
michael@0 | 58 | JSObject* UnwrapArray(JSObject*), |
michael@0 | 59 | void GetLengthAndData(JSObject*, uint32_t*, T**)> |
michael@0 | 60 | struct TypedArray_base : public TypedArrayObjectStorage { |
michael@0 | 61 | typedef T element_type; |
michael@0 | 62 | |
michael@0 | 63 | TypedArray_base(JSObject* obj) |
michael@0 | 64 | : TypedArrayObjectStorage(obj), |
michael@0 | 65 | mData(nullptr), |
michael@0 | 66 | mLength(0), |
michael@0 | 67 | mComputed(false) |
michael@0 | 68 | { |
michael@0 | 69 | MOZ_ASSERT(obj != nullptr); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | TypedArray_base() |
michael@0 | 73 | : TypedArrayObjectStorage(nullptr), |
michael@0 | 74 | mData(nullptr), |
michael@0 | 75 | mLength(0), |
michael@0 | 76 | mComputed(false) |
michael@0 | 77 | { |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | explicit TypedArray_base(TypedArray_base&& aOther) |
michael@0 | 81 | : TypedArrayObjectStorage(Move(aOther)), |
michael@0 | 82 | mData(aOther.mData), |
michael@0 | 83 | mLength(aOther.mLength) |
michael@0 | 84 | { |
michael@0 | 85 | aOther.mData = nullptr; |
michael@0 | 86 | aOther.mLength = 0; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | private: |
michael@0 | 90 | mutable T* mData; |
michael@0 | 91 | mutable uint32_t mLength; |
michael@0 | 92 | mutable bool mComputed; |
michael@0 | 93 | |
michael@0 | 94 | public: |
michael@0 | 95 | inline bool Init(JSObject* obj) |
michael@0 | 96 | { |
michael@0 | 97 | MOZ_ASSERT(!inited()); |
michael@0 | 98 | DoInit(obj); |
michael@0 | 99 | return inited(); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | inline bool inited() const { |
michael@0 | 103 | return !!mObj; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | inline T *Data() const { |
michael@0 | 107 | MOZ_ASSERT(mComputed); |
michael@0 | 108 | return mData; |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | inline uint32_t Length() const { |
michael@0 | 112 | MOZ_ASSERT(mComputed); |
michael@0 | 113 | return mLength; |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | inline JSObject *Obj() const { |
michael@0 | 117 | MOZ_ASSERT(inited()); |
michael@0 | 118 | return mObj; |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | inline bool WrapIntoNewCompartment(JSContext* cx) |
michael@0 | 122 | { |
michael@0 | 123 | return JS_WrapObject(cx, |
michael@0 | 124 | JS::MutableHandle<JSObject*>::fromMarkedLocation(&mObj)); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | inline void ComputeLengthAndData() const |
michael@0 | 128 | { |
michael@0 | 129 | MOZ_ASSERT(inited()); |
michael@0 | 130 | MOZ_ASSERT(!mComputed); |
michael@0 | 131 | GetLengthAndData(mObj, &mLength, &mData); |
michael@0 | 132 | mComputed = true; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | protected: |
michael@0 | 136 | inline void DoInit(JSObject* obj) |
michael@0 | 137 | { |
michael@0 | 138 | mObj = UnwrapArray(obj); |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | inline void ComputeData() const { |
michael@0 | 142 | MOZ_ASSERT(inited()); |
michael@0 | 143 | if (!mComputed) { |
michael@0 | 144 | GetLengthAndData(mObj, &mLength, &mData); |
michael@0 | 145 | mComputed = true; |
michael@0 | 146 | } |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | private: |
michael@0 | 150 | TypedArray_base(const TypedArray_base&) MOZ_DELETE; |
michael@0 | 151 | }; |
michael@0 | 152 | |
michael@0 | 153 | |
michael@0 | 154 | template<typename T, |
michael@0 | 155 | JSObject* UnwrapArray(JSObject*), |
michael@0 | 156 | T* GetData(JSObject*), |
michael@0 | 157 | void GetLengthAndData(JSObject*, uint32_t*, T**), |
michael@0 | 158 | JSObject* CreateNew(JSContext*, uint32_t)> |
michael@0 | 159 | struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> { |
michael@0 | 160 | TypedArray(JSObject* obj) : |
michael@0 | 161 | TypedArray_base<T, UnwrapArray, GetLengthAndData>(obj) |
michael@0 | 162 | {} |
michael@0 | 163 | |
michael@0 | 164 | TypedArray() : |
michael@0 | 165 | TypedArray_base<T, UnwrapArray, GetLengthAndData>() |
michael@0 | 166 | {} |
michael@0 | 167 | |
michael@0 | 168 | explicit TypedArray(TypedArray&& aOther) |
michael@0 | 169 | : TypedArray_base<T, UnwrapArray, GetLengthAndData>(Move(aOther)) |
michael@0 | 170 | { |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | static inline JSObject* |
michael@0 | 174 | Create(JSContext* cx, nsWrapperCache* creator, uint32_t length, |
michael@0 | 175 | const T* data = nullptr) { |
michael@0 | 176 | JS::Rooted<JSObject*> creatorWrapper(cx); |
michael@0 | 177 | Maybe<JSAutoCompartment> ac; |
michael@0 | 178 | if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) { |
michael@0 | 179 | ac.construct(cx, creatorWrapper); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | return CreateCommon(cx, length, data); |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | static inline JSObject* |
michael@0 | 186 | Create(JSContext* cx, uint32_t length, const T* data = nullptr) { |
michael@0 | 187 | return CreateCommon(cx, length, data); |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | private: |
michael@0 | 191 | static inline JSObject* |
michael@0 | 192 | CreateCommon(JSContext* cx, uint32_t length, const T* data) { |
michael@0 | 193 | JSObject* obj = CreateNew(cx, length); |
michael@0 | 194 | if (!obj) { |
michael@0 | 195 | return nullptr; |
michael@0 | 196 | } |
michael@0 | 197 | if (data) { |
michael@0 | 198 | T* buf = static_cast<T*>(GetData(obj)); |
michael@0 | 199 | memcpy(buf, data, length*sizeof(T)); |
michael@0 | 200 | } |
michael@0 | 201 | return obj; |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | TypedArray(const TypedArray&) MOZ_DELETE; |
michael@0 | 205 | }; |
michael@0 | 206 | |
michael@0 | 207 | typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData, |
michael@0 | 208 | js::GetInt8ArrayLengthAndData, JS_NewInt8Array> |
michael@0 | 209 | Int8Array; |
michael@0 | 210 | typedef TypedArray<uint8_t, js::UnwrapUint8Array, JS_GetUint8ArrayData, |
michael@0 | 211 | js::GetUint8ArrayLengthAndData, JS_NewUint8Array> |
michael@0 | 212 | Uint8Array; |
michael@0 | 213 | typedef TypedArray<uint8_t, js::UnwrapUint8ClampedArray, JS_GetUint8ClampedArrayData, |
michael@0 | 214 | js::GetUint8ClampedArrayLengthAndData, JS_NewUint8ClampedArray> |
michael@0 | 215 | Uint8ClampedArray; |
michael@0 | 216 | typedef TypedArray<int16_t, js::UnwrapInt16Array, JS_GetInt16ArrayData, |
michael@0 | 217 | js::GetInt16ArrayLengthAndData, JS_NewInt16Array> |
michael@0 | 218 | Int16Array; |
michael@0 | 219 | typedef TypedArray<uint16_t, js::UnwrapUint16Array, JS_GetUint16ArrayData, |
michael@0 | 220 | js::GetUint16ArrayLengthAndData, JS_NewUint16Array> |
michael@0 | 221 | Uint16Array; |
michael@0 | 222 | typedef TypedArray<int32_t, js::UnwrapInt32Array, JS_GetInt32ArrayData, |
michael@0 | 223 | js::GetInt32ArrayLengthAndData, JS_NewInt32Array> |
michael@0 | 224 | Int32Array; |
michael@0 | 225 | typedef TypedArray<uint32_t, js::UnwrapUint32Array, JS_GetUint32ArrayData, |
michael@0 | 226 | js::GetUint32ArrayLengthAndData, JS_NewUint32Array> |
michael@0 | 227 | Uint32Array; |
michael@0 | 228 | typedef TypedArray<float, js::UnwrapFloat32Array, JS_GetFloat32ArrayData, |
michael@0 | 229 | js::GetFloat32ArrayLengthAndData, JS_NewFloat32Array> |
michael@0 | 230 | Float32Array; |
michael@0 | 231 | typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData, |
michael@0 | 232 | js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array> |
michael@0 | 233 | Float64Array; |
michael@0 | 234 | typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData> |
michael@0 | 235 | ArrayBufferView; |
michael@0 | 236 | typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData, |
michael@0 | 237 | js::GetArrayBufferLengthAndData, JS_NewArrayBuffer> |
michael@0 | 238 | ArrayBuffer; |
michael@0 | 239 | |
michael@0 | 240 | // A class for converting an nsTArray to a TypedArray |
michael@0 | 241 | // Note: A TypedArrayCreator must not outlive the nsTArray it was created from. |
michael@0 | 242 | // So this is best used to pass from things that understand nsTArray to |
michael@0 | 243 | // things that understand TypedArray, as with Promise::ArgumentToJSValue. |
michael@0 | 244 | template<typename TypedArrayType> |
michael@0 | 245 | class TypedArrayCreator |
michael@0 | 246 | { |
michael@0 | 247 | typedef nsTArray<typename TypedArrayType::element_type> ArrayType; |
michael@0 | 248 | |
michael@0 | 249 | public: |
michael@0 | 250 | TypedArrayCreator(const ArrayType& aArray) |
michael@0 | 251 | : mArray(aArray) |
michael@0 | 252 | {} |
michael@0 | 253 | |
michael@0 | 254 | JSObject* Create(JSContext* aCx) const |
michael@0 | 255 | { |
michael@0 | 256 | return TypedArrayType::Create(aCx, mArray.Length(), mArray.Elements()); |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | private: |
michael@0 | 260 | const ArrayType& mArray; |
michael@0 | 261 | }; |
michael@0 | 262 | |
michael@0 | 263 | // A class for rooting an existing TypedArray struct |
michael@0 | 264 | template<typename ArrayType> |
michael@0 | 265 | class MOZ_STACK_CLASS TypedArrayRooter : private JS::CustomAutoRooter |
michael@0 | 266 | { |
michael@0 | 267 | public: |
michael@0 | 268 | TypedArrayRooter(JSContext* cx, |
michael@0 | 269 | ArrayType* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : |
michael@0 | 270 | JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), |
michael@0 | 271 | mArray(aArray) |
michael@0 | 272 | { |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | virtual void trace(JSTracer* trc) MOZ_OVERRIDE |
michael@0 | 276 | { |
michael@0 | 277 | mArray->TraceSelf(trc); |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | private: |
michael@0 | 281 | TypedArrayObjectStorage* const mArray; |
michael@0 | 282 | }; |
michael@0 | 283 | |
michael@0 | 284 | // And a specialization for dealing with nullable typed arrays |
michael@0 | 285 | template<typename Inner> struct Nullable; |
michael@0 | 286 | template<typename ArrayType> |
michael@0 | 287 | class MOZ_STACK_CLASS TypedArrayRooter<Nullable<ArrayType> > : |
michael@0 | 288 | private JS::CustomAutoRooter |
michael@0 | 289 | { |
michael@0 | 290 | public: |
michael@0 | 291 | TypedArrayRooter(JSContext* cx, |
michael@0 | 292 | Nullable<ArrayType>* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : |
michael@0 | 293 | JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), |
michael@0 | 294 | mArray(aArray) |
michael@0 | 295 | { |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | virtual void trace(JSTracer* trc) MOZ_OVERRIDE |
michael@0 | 299 | { |
michael@0 | 300 | if (!mArray->IsNull()) { |
michael@0 | 301 | mArray->Value().TraceSelf(trc); |
michael@0 | 302 | } |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | private: |
michael@0 | 306 | Nullable<ArrayType>* const mArray; |
michael@0 | 307 | }; |
michael@0 | 308 | |
michael@0 | 309 | // Class for easily setting up a rooted typed array object on the stack |
michael@0 | 310 | template<typename ArrayType> |
michael@0 | 311 | class MOZ_STACK_CLASS RootedTypedArray : public ArrayType, |
michael@0 | 312 | private TypedArrayRooter<ArrayType> |
michael@0 | 313 | { |
michael@0 | 314 | public: |
michael@0 | 315 | RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : |
michael@0 | 316 | ArrayType(), |
michael@0 | 317 | TypedArrayRooter<ArrayType>(cx, |
michael@0 | 318 | MOZ_THIS_IN_INITIALIZER_LIST() |
michael@0 | 319 | MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) |
michael@0 | 320 | { |
michael@0 | 321 | } |
michael@0 | 322 | |
michael@0 | 323 | RootedTypedArray(JSContext* cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : |
michael@0 | 324 | ArrayType(obj), |
michael@0 | 325 | TypedArrayRooter<ArrayType>(cx, |
michael@0 | 326 | MOZ_THIS_IN_INITIALIZER_LIST() |
michael@0 | 327 | MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) |
michael@0 | 328 | { |
michael@0 | 329 | } |
michael@0 | 330 | }; |
michael@0 | 331 | |
michael@0 | 332 | } // namespace dom |
michael@0 | 333 | } // namespace mozilla |
michael@0 | 334 | |
michael@0 | 335 | #endif /* mozilla_dom_TypedArray_h */ |