/src/mozilla-central/dom/base/StructuredCloneHolder.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
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 mozilla_dom_StructuredCloneHolder_h |
8 | | #define mozilla_dom_StructuredCloneHolder_h |
9 | | |
10 | | #include "jsapi.h" |
11 | | #include "js/StructuredClone.h" |
12 | | #include "mozilla/MemoryReporting.h" |
13 | | #include "mozilla/Move.h" |
14 | | #include "mozilla/UniquePtr.h" |
15 | | #include "mozilla/dom/BindingDeclarations.h" |
16 | | #include "nsISupports.h" |
17 | | #include "nsTArray.h" |
18 | | |
19 | | #ifdef DEBUG |
20 | | #include "nsIThread.h" |
21 | | #endif |
22 | | |
23 | | class nsIInputStream; |
24 | | |
25 | | namespace mozilla { |
26 | | class ErrorResult; |
27 | | namespace layers { |
28 | | class Image; |
29 | | } |
30 | | |
31 | | namespace gfx { |
32 | | class DataSourceSurface; |
33 | | } |
34 | | |
35 | | namespace dom { |
36 | | |
37 | | class StructuredCloneHolderBase |
38 | | { |
39 | | public: |
40 | | typedef JS::StructuredCloneScope StructuredCloneScope; |
41 | | |
42 | | StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread); |
43 | | virtual ~StructuredCloneHolderBase(); |
44 | | |
45 | | // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw |
46 | | // this pointer is passed to mBuffer as a callback closure. That must |
47 | | // be fixed if you want to implement a move constructor here. |
48 | | StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete; |
49 | | |
50 | | // These methods should be implemented in order to clone data. |
51 | | // Read more documentation in js/public/StructuredClone.h. |
52 | | |
53 | | virtual JSObject* CustomReadHandler(JSContext* aCx, |
54 | | JSStructuredCloneReader* aReader, |
55 | | uint32_t aTag, |
56 | | uint32_t aIndex) = 0; |
57 | | |
58 | | virtual bool CustomWriteHandler(JSContext* aCx, |
59 | | JSStructuredCloneWriter* aWriter, |
60 | | JS::Handle<JSObject*> aObj) = 0; |
61 | | |
62 | | // This method has to be called when this object is not needed anymore. |
63 | | // It will free memory and the buffer. This has to be called because |
64 | | // otherwise the buffer will be freed in the DTOR of this class and at that |
65 | | // point we cannot use the overridden methods. |
66 | | void Clear(); |
67 | | |
68 | | // If these 3 methods are not implement, transfering objects will not be |
69 | | // allowed. Otherwise only arrayBuffers will be transferred. |
70 | | |
71 | | virtual bool |
72 | | CustomReadTransferHandler(JSContext* aCx, |
73 | | JSStructuredCloneReader* aReader, |
74 | | uint32_t aTag, |
75 | | void* aContent, |
76 | | uint64_t aExtraData, |
77 | | JS::MutableHandleObject aReturnObject); |
78 | | |
79 | | virtual bool |
80 | | CustomWriteTransferHandler(JSContext* aCx, |
81 | | JS::Handle<JSObject*> aObj, |
82 | | // Output: |
83 | | uint32_t* aTag, |
84 | | JS::TransferableOwnership* aOwnership, |
85 | | void** aContent, |
86 | | uint64_t* aExtraData); |
87 | | |
88 | | virtual void |
89 | | CustomFreeTransferHandler(uint32_t aTag, |
90 | | JS::TransferableOwnership aOwnership, |
91 | | void* aContent, |
92 | | uint64_t aExtraData); |
93 | | |
94 | | virtual bool |
95 | | CustomCanTransferHandler(JSContext* aCx, |
96 | | JS::Handle<JSObject*> aObj); |
97 | | |
98 | | // These methods are what you should use to read/write data. |
99 | | |
100 | | // Execute the serialization of aValue using the Structured Clone Algorithm. |
101 | | // The data can read back using Read(). |
102 | | bool Write(JSContext* aCx, |
103 | | JS::Handle<JS::Value> aValue); |
104 | | |
105 | | // Like Write() but it supports the transferring of objects and handling |
106 | | // of cloning policy. |
107 | | bool Write(JSContext* aCx, |
108 | | JS::Handle<JS::Value> aValue, |
109 | | JS::Handle<JS::Value> aTransfer, |
110 | | JS::CloneDataPolicy cloneDataPolicy); |
111 | | |
112 | | // If Write() has been called, this method retrieves data and stores it into |
113 | | // aValue. |
114 | | bool Read(JSContext* aCx, |
115 | | JS::MutableHandle<JS::Value> aValue); |
116 | | |
117 | | bool HasData() const |
118 | 0 | { |
119 | 0 | return !!mBuffer; |
120 | 0 | } |
121 | | |
122 | | JSStructuredCloneData& BufferData() const |
123 | | { |
124 | | MOZ_ASSERT(mBuffer, "Write() has never been called."); |
125 | | return mBuffer->data(); |
126 | | } |
127 | | |
128 | | size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
129 | 0 | { |
130 | 0 | size_t size = 0; |
131 | 0 | if (HasData()) { |
132 | 0 | size += mBuffer->sizeOfIncludingThis(aMallocSizeOf); |
133 | 0 | } |
134 | 0 | return size; |
135 | 0 | } |
136 | | |
137 | | protected: |
138 | | UniquePtr<JSAutoStructuredCloneBuffer> mBuffer; |
139 | | |
140 | | StructuredCloneScope mStructuredCloneScope; |
141 | | |
142 | | #ifdef DEBUG |
143 | | bool mClearCalled; |
144 | | #endif |
145 | | }; |
146 | | |
147 | | class BlobImpl; |
148 | | class MessagePort; |
149 | | class MessagePortIdentifier; |
150 | | |
151 | | class StructuredCloneHolder : public StructuredCloneHolderBase |
152 | | { |
153 | | public: |
154 | | enum CloningSupport |
155 | | { |
156 | | CloningSupported, |
157 | | CloningNotSupported |
158 | | }; |
159 | | |
160 | | enum TransferringSupport |
161 | | { |
162 | | TransferringSupported, |
163 | | TransferringNotSupported |
164 | | }; |
165 | | |
166 | | // If cloning is supported, this object will clone objects such as Blobs, |
167 | | // FileList, ImageData, etc. |
168 | | // If transferring is supported, we will transfer MessagePorts and in the |
169 | | // future other transferrable objects. |
170 | | // The StructuredCloneScope is useful to know where the cloned/transferred |
171 | | // data can be read and written. Additional checks about the nature of the |
172 | | // objects will be done based on this scope value because not all the |
173 | | // objects can be sent between threads or processes. |
174 | | explicit StructuredCloneHolder(CloningSupport aSupportsCloning, |
175 | | TransferringSupport aSupportsTransferring, |
176 | | StructuredCloneScope aStructuredCloneScope); |
177 | | virtual ~StructuredCloneHolder(); |
178 | | |
179 | | StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete; |
180 | | |
181 | | // Normally you should just use Write() and Read(). |
182 | | |
183 | | void Write(JSContext* aCx, |
184 | | JS::Handle<JS::Value> aValue, |
185 | | ErrorResult &aRv); |
186 | | |
187 | | void Write(JSContext* aCx, |
188 | | JS::Handle<JS::Value> aValue, |
189 | | JS::Handle<JS::Value> aTransfer, |
190 | | JS::CloneDataPolicy cloneDataPolicy, |
191 | | ErrorResult &aRv); |
192 | | |
193 | | void Read(nsISupports* aParent, |
194 | | JSContext* aCx, |
195 | | JS::MutableHandle<JS::Value> aValue, |
196 | | ErrorResult &aRv); |
197 | | |
198 | | // Call this method to know if this object is keeping some DOM object alive. |
199 | | bool HasClonedDOMObjects() const |
200 | | { |
201 | | return !mBlobImplArray.IsEmpty() || |
202 | | !mWasmModuleArray.IsEmpty() || |
203 | | !mClonedSurfaces.IsEmpty() || |
204 | | !mInputStreamArray.IsEmpty(); |
205 | | } |
206 | | |
207 | | nsTArray<RefPtr<BlobImpl>>& BlobImpls() |
208 | 0 | { |
209 | 0 | MOZ_ASSERT(mSupportsCloning, "Blobs cannot be taken/set if cloning is not supported."); |
210 | 0 | return mBlobImplArray; |
211 | 0 | } |
212 | | |
213 | | nsTArray<RefPtr<JS::WasmModule>>& WasmModules() |
214 | 0 | { |
215 | 0 | MOZ_ASSERT(mSupportsCloning, "WasmModules cannot be taken/set if cloning is not supported."); |
216 | 0 | return mWasmModuleArray; |
217 | 0 | } |
218 | | |
219 | | nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() |
220 | 0 | { |
221 | 0 | MOZ_ASSERT(mSupportsCloning, "InputStreams cannot be taken/set if cloning is not supported."); |
222 | 0 | return mInputStreamArray; |
223 | 0 | } |
224 | | |
225 | | StructuredCloneScope CloneScope() const |
226 | | { |
227 | | return mStructuredCloneScope; |
228 | | } |
229 | | |
230 | | // The parent object is set internally just during the Read(). This method |
231 | | // can be used by read functions to retrieve it. |
232 | | nsISupports* ParentDuringRead() const |
233 | 0 | { |
234 | 0 | return mParent; |
235 | 0 | } |
236 | | |
237 | | // This must be called if the transferring has ports generated by Read(). |
238 | | // MessagePorts are not thread-safe and they must be retrieved in the thread |
239 | | // where they are created. |
240 | | nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts() |
241 | 0 | { |
242 | 0 | MOZ_ASSERT(mSupportsTransferring); |
243 | 0 | return std::move(mTransferredPorts); |
244 | 0 | } |
245 | | |
246 | | // This method uses TakeTransferredPorts() to populate a sequence of |
247 | | // MessagePorts for WebIDL binding classes. |
248 | | bool |
249 | | TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts); |
250 | | |
251 | | nsTArray<MessagePortIdentifier>& PortIdentifiers() const |
252 | | { |
253 | | MOZ_ASSERT(mSupportsTransferring); |
254 | | return mPortIdentifiers; |
255 | | } |
256 | | |
257 | | nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces() |
258 | 0 | { |
259 | 0 | return mClonedSurfaces; |
260 | 0 | } |
261 | | |
262 | | // Implementations of the virtual methods to allow cloning of objects which |
263 | | // JS engine itself doesn't clone. |
264 | | |
265 | | virtual JSObject* CustomReadHandler(JSContext* aCx, |
266 | | JSStructuredCloneReader* aReader, |
267 | | uint32_t aTag, |
268 | | uint32_t aIndex) override; |
269 | | |
270 | | virtual bool CustomWriteHandler(JSContext* aCx, |
271 | | JSStructuredCloneWriter* aWriter, |
272 | | JS::Handle<JSObject*> aObj) override; |
273 | | |
274 | | virtual bool CustomReadTransferHandler(JSContext* aCx, |
275 | | JSStructuredCloneReader* aReader, |
276 | | uint32_t aTag, |
277 | | void* aContent, |
278 | | uint64_t aExtraData, |
279 | | JS::MutableHandleObject aReturnObject) override; |
280 | | |
281 | | virtual bool CustomWriteTransferHandler(JSContext* aCx, |
282 | | JS::Handle<JSObject*> aObj, |
283 | | uint32_t* aTag, |
284 | | JS::TransferableOwnership* aOwnership, |
285 | | void** aContent, |
286 | | uint64_t* aExtraData) override; |
287 | | |
288 | | virtual void CustomFreeTransferHandler(uint32_t aTag, |
289 | | JS::TransferableOwnership aOwnership, |
290 | | void* aContent, |
291 | | uint64_t aExtraData) override; |
292 | | |
293 | | virtual bool CustomCanTransferHandler(JSContext* aCx, |
294 | | JS::Handle<JSObject*> aObj) override; |
295 | | |
296 | | // These 2 static methods are useful to read/write fully serializable objects. |
297 | | // They can be used by custom StructuredCloneHolderBase classes to |
298 | | // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc. |
299 | | |
300 | | static JSObject* ReadFullySerializableObjects(JSContext* aCx, |
301 | | JSStructuredCloneReader* aReader, |
302 | | uint32_t aTag); |
303 | | |
304 | | static bool WriteFullySerializableObjects(JSContext* aCx, |
305 | | JSStructuredCloneWriter* aWriter, |
306 | | JS::Handle<JSObject*> aObj); |
307 | | |
308 | | static const JSStructuredCloneCallbacks sCallbacks; |
309 | | |
310 | | protected: |
311 | | // If you receive a buffer from IPC, you can use this method to retrieve a |
312 | | // JS::Value. It can happen that you want to pre-populate the array of Blobs |
313 | | // and/or the PortIdentifiers. |
314 | | void ReadFromBuffer(nsISupports* aParent, |
315 | | JSContext* aCx, |
316 | | JSStructuredCloneData& aBuffer, |
317 | | JS::MutableHandle<JS::Value> aValue, |
318 | | ErrorResult &aRv); |
319 | | |
320 | | void ReadFromBuffer(nsISupports* aParent, |
321 | | JSContext* aCx, |
322 | | JSStructuredCloneData& aBuffer, |
323 | | uint32_t aAlgorithmVersion, |
324 | | JS::MutableHandle<JS::Value> aValue, |
325 | | ErrorResult &aRv); |
326 | | |
327 | | bool mSupportsCloning; |
328 | | bool mSupportsTransferring; |
329 | | |
330 | | // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't |
331 | | // account for objects in the following arrays because a) they're not expected |
332 | | // to be stored in long-lived StructuredCloneHolder objects, and b) in the |
333 | | // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters, |
334 | | // and the other types do not hold significant amounts of memory alive. |
335 | | |
336 | | // Used for cloning blobs in the structured cloning algorithm. |
337 | | nsTArray<RefPtr<BlobImpl>> mBlobImplArray; |
338 | | |
339 | | // Used for cloning JS::WasmModules in the structured cloning algorithm. |
340 | | nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray; |
341 | | |
342 | | // Used for cloning InputStream in the structured cloning algorithm. |
343 | | nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray; |
344 | | |
345 | | // This is used for sharing the backend of ImageBitmaps. |
346 | | // The DataSourceSurface object must be thread-safely reference-counted. |
347 | | // The DataSourceSurface object will not be written ever via any ImageBitmap |
348 | | // instance, so no race condition will occur. |
349 | | nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces; |
350 | | |
351 | | // This raw pointer is only set within ::Read() and is unset by the end. |
352 | | nsISupports* MOZ_NON_OWNING_REF mParent; |
353 | | |
354 | | // This array contains the ports once we've finished the reading. It's |
355 | | // generated from the mPortIdentifiers array. |
356 | | nsTArray<RefPtr<MessagePort>> mTransferredPorts; |
357 | | |
358 | | // This array contains the identifiers of the MessagePorts. Based on these we |
359 | | // are able to reconnect the new transferred ports with the other |
360 | | // MessageChannel ports. |
361 | | mutable nsTArray<MessagePortIdentifier> mPortIdentifiers; |
362 | | |
363 | | #ifdef DEBUG |
364 | | nsCOMPtr<nsIEventTarget> mCreationEventTarget; |
365 | | #endif |
366 | | }; |
367 | | |
368 | | } // dom namespace |
369 | | } // mozilla namespace |
370 | | |
371 | | #endif // mozilla_dom_StructuredCloneHolder_h |