Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / base / StructuredCloneHolder.h
blobd1d7cf78067f5257e45f876addbbe997c672a92b
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/. */
7 #ifndef mozilla_dom_StructuredCloneHolder_h
8 #define mozilla_dom_StructuredCloneHolder_h
10 #include <cstddef>
11 #include <cstdint>
12 #include <utility>
13 #include "js/StructuredClone.h"
14 #include "js/TypeDecls.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/RefPtr.h"
19 #include "mozilla/UniquePtr.h"
20 #include "nsCOMPtr.h"
21 #include "nsString.h"
22 #include "nsTArray.h"
24 class nsIEventTarget;
25 class nsIGlobalObject;
26 class nsIInputStream;
27 struct JSStructuredCloneReader;
28 struct JSStructuredCloneWriter;
30 namespace JS {
31 class Value;
32 struct WasmModule;
33 } // namespace JS
35 namespace mozilla {
36 class ErrorResult;
37 template <class T>
38 class OwningNonNull;
40 namespace layers {
41 class Image;
44 namespace gfx {
45 class DataSourceSurface;
48 namespace dom {
50 class BlobImpl;
51 class MessagePort;
52 class MessagePortIdentifier;
53 template <typename T>
54 class Sequence;
56 class StructuredCloneHolderBase {
57 public:
58 typedef JS::StructuredCloneScope StructuredCloneScope;
60 StructuredCloneHolderBase(
61 StructuredCloneScope aScope = StructuredCloneScope::SameProcess);
62 virtual ~StructuredCloneHolderBase();
64 // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw
65 // this pointer is passed to mBuffer as a callback closure. That must
66 // be fixed if you want to implement a move constructor here.
67 StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete;
69 // These methods should be implemented in order to clone data.
70 // Read more documentation in js/public/StructuredClone.h.
72 virtual JSObject* CustomReadHandler(
73 JSContext* aCx, JSStructuredCloneReader* aReader,
74 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
75 uint32_t aIndex) = 0;
77 virtual bool CustomWriteHandler(JSContext* aCx,
78 JSStructuredCloneWriter* aWriter,
79 JS::Handle<JSObject*> aObj,
80 bool* aSameProcessScopeRequired) = 0;
82 // This method has to be called when this object is not needed anymore.
83 // It will free memory and the buffer. This has to be called because
84 // otherwise the buffer will be freed in the DTOR of this class and at that
85 // point we cannot use the overridden methods.
86 void Clear();
88 // If these 3 methods are not implement, transfering objects will not be
89 // allowed. Otherwise only arrayBuffers will be transferred.
91 virtual bool CustomReadTransferHandler(
92 JSContext* aCx, JSStructuredCloneReader* aReader,
93 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
94 void* aContent, uint64_t aExtraData,
95 JS::MutableHandle<JSObject*> aReturnObject);
97 virtual bool CustomWriteTransferHandler(JSContext* aCx,
98 JS::Handle<JSObject*> aObj,
99 // Output:
100 uint32_t* aTag,
101 JS::TransferableOwnership* aOwnership,
102 void** aContent,
103 uint64_t* aExtraData);
105 virtual void CustomFreeTransferHandler(uint32_t aTag,
106 JS::TransferableOwnership aOwnership,
107 void* aContent, uint64_t aExtraData);
109 virtual bool CustomCanTransferHandler(JSContext* aCx,
110 JS::Handle<JSObject*> aObj,
111 bool* aSameProcessScopeRequired);
113 // These methods are what you should use to read/write data.
115 // Execute the serialization of aValue using the Structured Clone Algorithm.
116 // The data can read back using Read().
117 bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue);
119 // Like Write() but it supports the transferring of objects and handling
120 // of cloning policy.
121 bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
122 JS::Handle<JS::Value> aTransfer,
123 const JS::CloneDataPolicy& aCloneDataPolicy);
125 // If Write() has been called, this method retrieves data and stores it into
126 // aValue.
127 bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue);
129 // Like Read() but it supports handling of clone policy.
130 bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
131 const JS::CloneDataPolicy& aCloneDataPolicy);
133 bool HasData() const { return !!mBuffer; }
135 JSStructuredCloneData& BufferData() const {
136 MOZ_ASSERT(mBuffer, "Write() has never been called.");
137 return mBuffer->data();
140 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
141 size_t size = 0;
142 if (HasData()) {
143 size += mBuffer->sizeOfIncludingThis(aMallocSizeOf);
145 return size;
148 void SetErrorMessage(const char* aErrorMessage) {
149 mErrorMessage.Assign(aErrorMessage);
152 protected:
153 UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
155 StructuredCloneScope mStructuredCloneScope;
157 // Error message when a data clone error is about to throw. It's held while
158 // the error callback is fired and it will be throw with a data clone error
159 // later.
160 nsCString mErrorMessage;
162 #ifdef DEBUG
163 bool mClearCalled;
164 #endif
167 class BlobImpl;
168 class EncodedAudioChunkData;
169 class EncodedVideoChunkData;
170 class MessagePort;
171 class MessagePortIdentifier;
172 struct VideoFrameSerializedData;
173 struct AudioDataSerializedData;
175 class StructuredCloneHolder : public StructuredCloneHolderBase {
176 public:
177 enum CloningSupport { CloningSupported, CloningNotSupported };
179 enum TransferringSupport { TransferringSupported, TransferringNotSupported };
181 // If cloning is supported, this object will clone objects such as Blobs,
182 // FileList, ImageData, etc.
183 // If transferring is supported, we will transfer MessagePorts and in the
184 // future other transferrable objects.
185 // The StructuredCloneScope is useful to know where the cloned/transferred
186 // data can be read and written. Additional checks about the nature of the
187 // objects will be done based on this scope value because not all the
188 // objects can be sent between threads or processes.
189 explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
190 TransferringSupport aSupportsTransferring,
191 StructuredCloneScope aStructuredCloneScope);
192 virtual ~StructuredCloneHolder();
194 StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete;
196 // Normally you should just use Write() and Read().
198 virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
199 ErrorResult& aRv);
201 virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
202 JS::Handle<JS::Value> aTransfer,
203 const JS::CloneDataPolicy& aCloneDataPolicy,
204 ErrorResult& aRv);
206 void Read(nsIGlobalObject* aGlobal, JSContext* aCx,
207 JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv);
209 void Read(nsIGlobalObject* aGlobal, JSContext* aCx,
210 JS::MutableHandle<JS::Value> aValue,
211 const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv);
213 // Call this method to know if this object is keeping some DOM object alive.
214 bool HasClonedDOMObjects() const {
215 return !mBlobImplArray.IsEmpty() || !mWasmModuleArray.IsEmpty() ||
216 !mClonedSurfaces.IsEmpty() || !mInputStreamArray.IsEmpty() ||
217 !mVideoFrames.IsEmpty() || !mEncodedVideoChunks.IsEmpty();
220 nsTArray<RefPtr<BlobImpl>>& BlobImpls() {
221 MOZ_ASSERT(mSupportsCloning,
222 "Blobs cannot be taken/set if cloning is not supported.");
223 return mBlobImplArray;
226 nsTArray<RefPtr<JS::WasmModule>>& WasmModules() {
227 MOZ_ASSERT(mSupportsCloning,
228 "WasmModules cannot be taken/set if cloning is not supported.");
229 return mWasmModuleArray;
232 nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() {
233 MOZ_ASSERT(mSupportsCloning,
234 "InputStreams cannot be taken/set if cloning is not supported.");
235 return mInputStreamArray;
238 // This method returns the final scope. If the final scope is unknown,
239 // DifferentProcess is returned because it's the most restrictive one.
240 StructuredCloneScope CloneScope() const {
241 if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) {
242 return StructuredCloneScope::DifferentProcess;
244 return mStructuredCloneScope;
247 // The global object is set internally just during the Read(). This method
248 // can be used by read functions to retrieve it.
249 nsIGlobalObject* GlobalDuringRead() const { return mGlobal; }
251 // This must be called if the transferring has ports generated by Read().
252 // MessagePorts are not thread-safe and they must be retrieved in the thread
253 // where they are created.
254 nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts() {
255 MOZ_ASSERT(mSupportsTransferring);
256 return std::move(mTransferredPorts);
259 // This method uses TakeTransferredPorts() to populate a sequence of
260 // MessagePorts for WebIDL binding classes.
261 bool TakeTransferredPortsAsSequence(
262 Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
264 nsTArray<MessagePortIdentifier>& PortIdentifiers() const {
265 MOZ_ASSERT(mSupportsTransferring);
266 return mPortIdentifiers;
269 nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces() {
270 return mClonedSurfaces;
273 nsTArray<VideoFrameSerializedData>& VideoFrames() { return mVideoFrames; }
275 nsTArray<AudioDataSerializedData>& AudioData() { return mAudioData; }
277 nsTArray<EncodedVideoChunkData>& EncodedVideoChunks() {
278 return mEncodedVideoChunks;
281 nsTArray<EncodedAudioChunkData>& EncodedAudioChunks() {
282 return mEncodedAudioChunks;
285 // Implementations of the virtual methods to allow cloning of objects which
286 // JS engine itself doesn't clone.
288 virtual JSObject* CustomReadHandler(
289 JSContext* aCx, JSStructuredCloneReader* aReader,
290 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
291 uint32_t aIndex) override;
293 virtual bool CustomWriteHandler(JSContext* aCx,
294 JSStructuredCloneWriter* aWriter,
295 JS::Handle<JSObject*> aObj,
296 bool* aSameProcessScopeRequired) override;
298 virtual bool CustomReadTransferHandler(
299 JSContext* aCx, JSStructuredCloneReader* aReader,
300 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
301 void* aContent, uint64_t aExtraData,
302 JS::MutableHandle<JSObject*> aReturnObject) override;
304 virtual bool CustomWriteTransferHandler(JSContext* aCx,
305 JS::Handle<JSObject*> aObj,
306 uint32_t* aTag,
307 JS::TransferableOwnership* aOwnership,
308 void** aContent,
309 uint64_t* aExtraData) override;
311 virtual void CustomFreeTransferHandler(uint32_t aTag,
312 JS::TransferableOwnership aOwnership,
313 void* aContent,
314 uint64_t aExtraData) override;
316 virtual bool CustomCanTransferHandler(
317 JSContext* aCx, JS::Handle<JSObject*> aObj,
318 bool* aSameProcessScopeRequired) override;
320 // These 2 static methods are useful to read/write fully serializable objects.
321 // They can be used by custom StructuredCloneHolderBase classes to
322 // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
324 static JSObject* ReadFullySerializableObjects(
325 JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
326 bool aIsForIndexedDB);
328 static bool WriteFullySerializableObjects(JSContext* aCx,
329 JSStructuredCloneWriter* aWriter,
330 JS::Handle<JSObject*> aObj);
332 // Helper functions for reading and writing strings.
333 static bool ReadString(JSStructuredCloneReader* aReader, nsString& aString);
334 static bool WriteString(JSStructuredCloneWriter* aWriter,
335 const nsAString& aString);
336 static bool ReadCString(JSStructuredCloneReader* aReader, nsCString& aString);
337 static bool WriteCString(JSStructuredCloneWriter* aWriter,
338 const nsACString& aString);
340 static const JSStructuredCloneCallbacks sCallbacks;
342 protected:
343 // If you receive a buffer from IPC, you can use this method to retrieve a
344 // JS::Value. It can happen that you want to pre-populate the array of Blobs
345 // and/or the PortIdentifiers.
346 void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
347 JSStructuredCloneData& aBuffer,
348 JS::MutableHandle<JS::Value> aValue,
349 const JS::CloneDataPolicy& aCloneDataPolicy,
350 ErrorResult& aRv);
352 void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
353 JSStructuredCloneData& aBuffer,
354 uint32_t aAlgorithmVersion,
355 JS::MutableHandle<JS::Value> aValue,
356 const JS::CloneDataPolicy& aCloneDataPolicy,
357 ErrorResult& aRv);
359 void SameProcessScopeRequired(bool* aSameProcessScopeRequired);
361 already_AddRefed<MessagePort> ReceiveMessagePort(uint64_t aIndex);
363 bool mSupportsCloning;
364 bool mSupportsTransferring;
366 // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
367 // account for objects in the following arrays because a) they're not expected
368 // to be stored in long-lived StructuredCloneHolder objects, and b) in the
369 // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
370 // and the other types do not hold significant amounts of memory alive.
372 // Used for cloning blobs in the structured cloning algorithm.
373 nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
375 // Used for cloning JS::WasmModules in the structured cloning algorithm.
376 nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
378 // Used for cloning InputStream in the structured cloning algorithm.
379 nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
381 // This is used for sharing the backend of ImageBitmaps.
382 // The DataSourceSurface object must be thread-safely reference-counted.
383 // The DataSourceSurface object will not be written ever via any ImageBitmap
384 // instance, so no race condition will occur.
385 nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces;
387 // Used for cloning VideoFrame in the structured cloning algorithm.
388 nsTArray<VideoFrameSerializedData> mVideoFrames;
390 // Used for cloning AudioData in the structured cloning algorithm.
391 nsTArray<AudioDataSerializedData> mAudioData;
393 // Used for cloning EncodedVideoChunk in the structured cloning algorithm.
394 nsTArray<EncodedVideoChunkData> mEncodedVideoChunks;
396 // Used for cloning EncodedAudioChunk in the structured cloning algorithm.
397 nsTArray<EncodedAudioChunkData> mEncodedAudioChunks;
399 // This raw pointer is only set within ::Read() and is unset by the end.
400 nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal;
402 // This array contains the ports once we've finished the reading. It's
403 // generated from the mPortIdentifiers array.
404 nsTArray<RefPtr<MessagePort>> mTransferredPorts;
406 // This array contains the identifiers of the MessagePorts. Based on these we
407 // are able to reconnect the new transferred ports with the other
408 // MessageChannel ports.
409 mutable nsTArray<MessagePortIdentifier> mPortIdentifiers;
411 #ifdef DEBUG
412 nsCOMPtr<nsIEventTarget> mCreationEventTarget;
413 #endif
416 } // namespace dom
417 } // namespace mozilla
419 #endif // mozilla_dom_StructuredCloneHolder_h