BlobRegistry no longer needs SessionIDs
[WebKit-https.git] / Source / WebCore / bindings / js / SerializedScriptValue.cpp
1 /*
2  * Copyright (C) 2009-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26
27 #include "config.h"
28 #include "SerializedScriptValue.h"
29
30 #include "BlobRegistry.h"
31 #include "CryptoKeyAES.h"
32 #include "CryptoKeyEC.h"
33 #include "CryptoKeyHMAC.h"
34 #include "CryptoKeyRSA.h"
35 #include "CryptoKeyRSAComponents.h"
36 #include "CryptoKeyRaw.h"
37 #include "IDBValue.h"
38 #include "JSBlob.h"
39 #include "JSCryptoKey.h"
40 #include "JSDOMBinding.h"
41 #include "JSDOMConvertBufferSource.h"
42 #include "JSDOMGlobalObject.h"
43 #include "JSDOMMatrix.h"
44 #include "JSDOMPoint.h"
45 #include "JSDOMQuad.h"
46 #include "JSDOMRect.h"
47 #include "JSFile.h"
48 #include "JSFileList.h"
49 #include "JSImageBitmap.h"
50 #include "JSImageData.h"
51 #include "JSMessagePort.h"
52 #include "JSNavigator.h"
53 #include "JSRTCCertificate.h"
54 #include "ScriptExecutionContext.h"
55 #include "ScriptState.h"
56 #include "SharedBuffer.h"
57 #include "WebCoreJSClientData.h"
58 #include <JavaScriptCore/APICast.h>
59 #include <JavaScriptCore/BooleanObject.h>
60 #include <JavaScriptCore/CatchScope.h>
61 #include <JavaScriptCore/DateInstance.h>
62 #include <JavaScriptCore/Error.h>
63 #include <JavaScriptCore/Exception.h>
64 #include <JavaScriptCore/ExceptionHelpers.h>
65 #include <JavaScriptCore/IterationKind.h>
66 #include <JavaScriptCore/JSArrayBuffer.h>
67 #include <JavaScriptCore/JSArrayBufferView.h>
68 #include <JavaScriptCore/JSCInlines.h>
69 #include <JavaScriptCore/JSDataView.h>
70 #include <JavaScriptCore/JSMap.h>
71 #include <JavaScriptCore/JSMapIterator.h>
72 #include <JavaScriptCore/JSSet.h>
73 #include <JavaScriptCore/JSSetIterator.h>
74 #include <JavaScriptCore/JSTypedArrays.h>
75 #include <JavaScriptCore/JSWebAssemblyModule.h>
76 #include <JavaScriptCore/ObjectConstructor.h>
77 #include <JavaScriptCore/PropertyNameArray.h>
78 #include <JavaScriptCore/RegExp.h>
79 #include <JavaScriptCore/RegExpObject.h>
80 #include <JavaScriptCore/TypedArrayInlines.h>
81 #include <JavaScriptCore/TypedArrays.h>
82 #include <JavaScriptCore/WasmModule.h>
83 #include <JavaScriptCore/YarrFlags.h>
84 #include <limits>
85 #include <wtf/CompletionHandler.h>
86 #include <wtf/MainThread.h>
87 #include <wtf/RunLoop.h>
88 #include <wtf/Vector.h>
89
90 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
91 #define ASSUME_LITTLE_ENDIAN 0
92 #else
93 #define ASSUME_LITTLE_ENDIAN 1
94 #endif
95
96 namespace WebCore {
97 using namespace JSC;
98
99 static const unsigned maximumFilterRecursion = 40000;
100
101 enum class SerializationReturnCode {
102     SuccessfullyCompleted,
103     StackOverflowError,
104     InterruptedExecutionError,
105     ValidationError,
106     ExistingExceptionError,
107     DataCloneError,
108     UnspecifiedError
109 };
110
111 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
112     ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
113     MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue,
114     SetDataStartVisitEntry, SetDataEndVisitKey };
115
116 // These can't be reordered, and any new types must be added to the end of the list
117 // When making changes to these lists please cover your new type(s) in the API test "IndexedDB.StructuredCloneBackwardCompatibility"
118 enum SerializationTag {
119     ArrayTag = 1,
120     ObjectTag = 2,
121     UndefinedTag = 3,
122     NullTag = 4,
123     IntTag = 5,
124     ZeroTag = 6,
125     OneTag = 7,
126     FalseTag = 8,
127     TrueTag = 9,
128     DoubleTag = 10,
129     DateTag = 11,
130     FileTag = 12,
131     FileListTag = 13,
132     ImageDataTag = 14,
133     BlobTag = 15,
134     StringTag = 16,
135     EmptyStringTag = 17,
136     RegExpTag = 18,
137     ObjectReferenceTag = 19,
138     MessagePortReferenceTag = 20,
139     ArrayBufferTag = 21,
140     ArrayBufferViewTag = 22,
141     ArrayBufferTransferTag = 23,
142     TrueObjectTag = 24,
143     FalseObjectTag = 25,
144     StringObjectTag = 26,
145     EmptyStringObjectTag = 27,
146     NumberObjectTag = 28,
147     SetObjectTag = 29,
148     MapObjectTag = 30,
149     NonMapPropertiesTag = 31,
150     NonSetPropertiesTag = 32,
151 #if ENABLE(WEB_CRYPTO)
152     CryptoKeyTag = 33,
153 #endif
154     SharedArrayBufferTag = 34,
155 #if ENABLE(WEBASSEMBLY)
156     WasmModuleTag = 35,
157 #endif
158     DOMPointReadOnlyTag = 36,
159     DOMPointTag = 37,
160     DOMRectReadOnlyTag = 38,
161     DOMRectTag = 39,
162     DOMMatrixReadOnlyTag = 40,
163     DOMMatrixTag = 41,
164     DOMQuadTag = 42,
165     ImageBitmapTransferTag = 43,
166 #if ENABLE(WEB_RTC)
167     RTCCertificateTag = 44,
168 #endif
169     ErrorTag = 255
170 };
171
172 enum ArrayBufferViewSubtag {
173     DataViewTag = 0,
174     Int8ArrayTag = 1,
175     Uint8ArrayTag = 2,
176     Uint8ClampedArrayTag = 3,
177     Int16ArrayTag = 4,
178     Uint16ArrayTag = 5,
179     Int32ArrayTag = 6,
180     Uint32ArrayTag = 7,
181     Float32ArrayTag = 8,
182     Float64ArrayTag = 9
183 };
184
185 static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
186 {
187     switch (tag) {
188     case DataViewTag:
189     case Int8ArrayTag:
190     case Uint8ArrayTag:
191     case Uint8ClampedArrayTag:
192         return 1;
193     case Int16ArrayTag:
194     case Uint16ArrayTag:
195         return 2;
196     case Int32ArrayTag:
197     case Uint32ArrayTag:
198     case Float32ArrayTag:
199         return 4;
200     case Float64ArrayTag:
201         return 8;
202     default:
203         return 0;
204     }
205
206 }
207
208 #if ENABLE(WEB_CRYPTO)
209
210 const uint32_t currentKeyFormatVersion = 1;
211
212 enum class CryptoKeyClassSubtag {
213     HMAC = 0,
214     AES = 1,
215     RSA = 2,
216     EC = 3,
217     Raw = 4,
218 };
219 const uint8_t cryptoKeyClassSubtagMaximumValue = 4;
220
221 enum class CryptoKeyAsymmetricTypeSubtag {
222     Public = 0,
223     Private = 1
224 };
225 const uint8_t cryptoKeyAsymmetricTypeSubtagMaximumValue = 1;
226
227 enum class CryptoKeyUsageTag {
228     Encrypt = 0,
229     Decrypt = 1,
230     Sign = 2,
231     Verify = 3,
232     DeriveKey = 4,
233     DeriveBits = 5,
234     WrapKey = 6,
235     UnwrapKey = 7
236 };
237 const uint8_t cryptoKeyUsageTagMaximumValue = 7;
238
239 enum class CryptoAlgorithmIdentifierTag {
240     RSAES_PKCS1_v1_5 = 0,
241     RSASSA_PKCS1_v1_5 = 1,
242     RSA_PSS = 2,
243     RSA_OAEP = 3,
244     ECDSA = 4,
245     ECDH = 5,
246     AES_CTR = 6,
247     AES_CBC = 7,
248     AES_GCM = 9,
249     AES_CFB = 10,
250     AES_KW = 11,
251     HMAC = 12,
252     SHA_1 = 14,
253     SHA_224 = 15,
254     SHA_256 = 16,
255     SHA_384 = 17,
256     SHA_512 = 18,
257     HKDF = 20,
258     PBKDF2 = 21,
259 };
260 const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21;
261
262 static unsigned countUsages(CryptoKeyUsageBitmap usages)
263 {
264     // Fast bit count algorithm for sparse bit maps.
265     unsigned count = 0;
266     while (usages) {
267         usages = usages & (usages - 1);
268         ++count;
269     }
270     return count;
271 }
272
273 #endif
274
275 /* CurrentVersion tracks the serialization version so that persistent stores
276  * are able to correctly bail out in the case of encountering newer formats.
277  *
278  * Initial version was 1.
279  * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
280  * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
281  * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
282  * Version 4. added support for serializing non-index properties of arrays.
283  * Version 5. added support for Map and Set types.
284  * Version 6. added support for 8-bit strings.
285  * Version 7. added support for File's lastModified attribute.
286  */
287 static const unsigned CurrentVersion = 7;
288 static const unsigned TerminatorTag = 0xFFFFFFFF;
289 static const unsigned StringPoolTag = 0xFFFFFFFE;
290 static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
291
292 // The high bit of a StringData's length determines the character size.
293 static const unsigned StringDataIs8BitFlag = 0x80000000;
294
295 /*
296  * Object serialization is performed according to the following grammar, all tags
297  * are recorded as a single uint8_t.
298  *
299  * IndexType (used for the object pool and StringData's constant pool) is the
300  * minimum sized unsigned integer type required to represent the maximum index
301  * in the constant pool.
302  *
303  * SerializedValue :- <CurrentVersion:uint32_t> Value
304  * Value :- Array | Object | Map | Set | Terminal
305  *
306  * Array :-
307  *     ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
308  *
309  * Object :-
310  *     ObjectTag (<name:StringData><value:Value>)* TerminatorTag
311  *
312  * Map :- MapObjectTag MapData
313  *
314  * Set :- SetObjectTag SetData
315  *
316  * MapData :- (<key:Value><value:Value>)* NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
317  * SetData :- (<key:Value>)* NonSetPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
318  *
319  * Terminal :-
320  *      UndefinedTag
321  *    | NullTag
322  *    | IntTag <value:int32_t>
323  *    | ZeroTag
324  *    | OneTag
325  *    | FalseTag
326  *    | TrueTag
327  *    | FalseObjectTag
328  *    | TrueObjectTag
329  *    | DoubleTag <value:double>
330  *    | NumberObjectTag <value:double>
331  *    | DateTag <value:double>
332  *    | String
333  *    | EmptyStringTag
334  *    | EmptyStringObjectTag
335  *    | File
336  *    | FileList
337  *    | ImageData
338  *    | Blob
339  *    | ObjectReference
340  *    | MessagePortReferenceTag <value:uint32_t>
341  *    | ArrayBuffer
342  *    | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference)
343  *    | ArrayBufferTransferTag <value:uint32_t>
344  *    | CryptoKeyTag <wrappedKeyLength:uint32_t> <factor:byte{wrappedKeyLength}>
345  *    | DOMPoint
346  *    | DOMRect
347  *    | DOMMatrix
348  *    | DOMQuad
349  *    | ImageBitmapTransferTag <value:uint32_t>
350  *    | RTCCertificateTag
351  *
352  * Inside certificate, data is serialized in this format as per spec:
353  *
354  * <expires:double> <certificate:StringData> <origin:StringData> <keyingMaterial:StringData>
355  * We also add fingerprints to make sure we expose to JavaScript the same information.
356  *
357  * Inside wrapped crypto key, data is serialized in this format:
358  *
359  * <keyFormatVersion:uint32_t> <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA)
360  *
361  * String :-
362  *      EmptyStringTag
363  *      StringTag StringData
364  *
365  * StringObject:
366  *      EmptyStringObjectTag
367  *      StringObjectTag StringData
368  *
369  * StringData :-
370  *      StringPoolTag <cpIndex:IndexType>
371  *      (not (TerminatorTag | StringPoolTag))<is8Bit:uint32_t:1><length:uint32_t:31><characters:CharType{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
372  *
373  * File :-
374  *    FileTag FileData
375  *
376  * FileData :-
377  *    <path:StringData> <url:StringData> <type:StringData> <name:StringData> <lastModified:double>
378  *
379  * FileList :-
380  *    FileListTag <length:uint32_t>(<file:FileData>){length}
381  *
382  * ImageData :-
383  *    ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
384  *
385  * Blob :-
386  *    BlobTag <url:StringData><type:StringData><size:long long>
387  *
388  * RegExp :-
389  *    RegExpTag <pattern:StringData><flags:StringData>
390  *
391  * ObjectReference :-
392  *    ObjectReferenceTag <opIndex:IndexType>
393  *
394  * ArrayBuffer :-
395  *    ArrayBufferTag <length:uint32_t> <contents:byte{length}>
396  *
397  * CryptoKeyHMAC :-
398  *    <keySize:uint32_t> <keyData:byte{keySize}> CryptoAlgorithmIdentifierTag // Algorithm tag inner hash function.
399  *
400  * CryptoKeyAES :-
401  *    CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
402  *
403  * CryptoKeyRSA :-
404  *    CryptoAlgorithmIdentifierTag <isRestrictedToHash:int32_t> CryptoAlgorithmIdentifierTag? CryptoKeyAsymmetricTypeSubtag CryptoKeyRSAPublicComponents CryptoKeyRSAPrivateComponents?
405  *
406  * CryptoKeyRSAPublicComponents :-
407  *    <modulusSize:uint32_t> <modulus:byte{modulusSize}> <exponentSize:uint32_t> <exponent:byte{exponentSize}>
408  *
409  * CryptoKeyRSAPrivateComponents :-
410  *    <privateExponentSize:uint32_t> <privateExponent:byte{privateExponentSize}> <primeCount:uint32_t> FirstPrimeInfo? PrimeInfo{primeCount - 1}
411  *
412  * // CRT data could be computed from prime factors. It is only serialized to reuse a code path that's needed for JWK.
413  * FirstPrimeInfo :-
414  *    <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}>
415  *
416  * PrimeInfo :-
417  *    <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}>
418  *
419  * CryptoKeyEC :-
420  *    CryptoAlgorithmIdentifierTag <namedCurve:StringData> CryptoKeyAsymmetricTypeSubtag <keySize:uint32_t> <keyData:byte{keySize}>
421  *
422  * CryptoKeyRaw :-
423  *    CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
424  *
425  * DOMPoint :-
426  *        DOMPointReadOnlyTag DOMPointData
427  *      | DOMPointTag DOMPointData
428  *
429  * DOMPointData :-
430  *      <x:double> <y:double> <z:double> <w:double>
431  *
432  * DOMRect :-
433  *        DOMRectReadOnlyTag DOMRectData
434  *      | DOMRectTag DOMRectData
435  *
436  * DOMRectData :-
437  *      <x:double> <y:double> <width:double> <height:double>
438  *
439  * DOMMatrix :-
440  *        DOMMatrixReadOnlyTag DOMMatrixData
441  *      | DOMMatrixTag DOMMatrixData
442  *
443  * DOMMatrixData :-
444  *        <is2D:uint8_t:true> <m11:double> <m12:double> <m21:double> <m22:double> <m41:double> <m42:double>
445  *      | <is2D:uint8_t:false> <m11:double> <m12:double> <m13:double> <m14:double> <m21:double> <m22:double> <m23:double> <m24:double> <m31:double> <m32:double> <m33:double> <m34:double> <m41:double> <m42:double> <m43:double> <m44:double>
446  *
447  * DOMQuad :-
448  *      DOMQuadTag DOMQuadData
449  *
450  * DOMQuadData :-
451  *      <p1:DOMPointData> <p2:DOMPointData> <p3:DOMPointData> <p4:DOMPointData>
452  *
453  */
454
455 using DeserializationResult = std::pair<JSC::JSValue, SerializationReturnCode>;
456
457 class CloneBase {
458 protected:
459     CloneBase(ExecState* exec)
460         : m_exec(exec)
461         , m_failed(false)
462     {
463     }
464
465     bool shouldTerminate()
466     {
467         VM& vm = m_exec->vm();
468         auto scope = DECLARE_THROW_SCOPE(vm);
469         return scope.exception();
470     }
471
472     void fail()
473     {
474         m_failed = true;
475     }
476
477     ExecState* m_exec;
478     bool m_failed;
479     MarkedArgumentBuffer m_gcBuffer;
480 };
481
482 #if ENABLE(WEB_CRYPTO)
483 static bool wrapCryptoKey(ExecState* exec, const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey)
484 {
485     ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
486     if (!scriptExecutionContext)
487         return false;
488     return scriptExecutionContext->wrapCryptoKey(key, wrappedKey);
489 }
490
491 static bool unwrapCryptoKey(ExecState* exec, const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key)
492 {
493     ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
494     if (!scriptExecutionContext)
495         return false;
496     return scriptExecutionContext->unwrapCryptoKey(wrappedKey, key);
497 }
498 #endif
499
500 #if ASSUME_LITTLE_ENDIAN
501 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
502 {
503     buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
504 }
505 #else
506 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
507 {
508     for (unsigned i = 0; i < sizeof(T); i++) {
509         buffer.append(value & 0xFF);
510         value >>= 8;
511     }
512 }
513 #endif
514
515 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
516 {
517     buffer.append(value);
518 }
519
520 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
521 {
522     if (length > std::numeric_limits<uint32_t>::max() / sizeof(T))
523         return false;
524
525 #if ASSUME_LITTLE_ENDIAN
526     buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
527 #else
528     for (unsigned i = 0; i < length; i++) {
529         T value = values[i];
530         for (unsigned j = 0; j < sizeof(T); j++) {
531             buffer.append(static_cast<uint8_t>(value & 0xFF));
532             value >>= 8;
533         }
534     }
535 #endif
536     return true;
537 }
538
539 template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8_t* values, uint32_t length)
540 {
541     buffer.append(values, length);
542     return true;
543 }
544
545 class CloneSerializer : CloneBase {
546 public:
547     static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, const Vector<RefPtr<ImageBitmap>>& imageBitmaps,
548 #if ENABLE(WEBASSEMBLY)
549             WasmModuleArray& wasmModules,
550 #endif
551         Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
552     {
553         CloneSerializer serializer(exec, messagePorts, arrayBuffers, imageBitmaps,
554 #if ENABLE(WEBASSEMBLY)
555             wasmModules,
556 #endif
557             blobURLs, out, context, sharedBuffers);
558         return serializer.serialize(value);
559     }
560
561     static bool serialize(StringView string, Vector<uint8_t>& out)
562     {
563         writeLittleEndian(out, CurrentVersion);
564         if (string.isEmpty()) {
565             writeLittleEndian<uint8_t>(out, EmptyStringTag);
566             return true;
567         }
568         writeLittleEndian<uint8_t>(out, StringTag);
569         if (string.is8Bit()) {
570             writeLittleEndian(out, string.length() | StringDataIs8BitFlag);
571             return writeLittleEndian(out, string.characters8(), string.length());
572         }
573         writeLittleEndian(out, string.length());
574         return writeLittleEndian(out, string.characters16(), string.length());
575     }
576
577 private:
578     typedef HashMap<JSObject*, uint32_t> ObjectPool;
579
580     CloneSerializer(ExecState* exec, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, const Vector<RefPtr<ImageBitmap>>& imageBitmaps,
581 #if ENABLE(WEBASSEMBLY)
582             WasmModuleArray& wasmModules,
583 #endif
584         Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
585         : CloneBase(exec)
586         , m_buffer(out)
587         , m_blobURLs(blobURLs)
588         , m_emptyIdentifier(Identifier::fromString(exec->vm(), emptyString()))
589         , m_context(context)
590         , m_sharedBuffers(sharedBuffers)
591 #if ENABLE(WEBASSEMBLY)
592         , m_wasmModules(wasmModules)
593 #endif
594     {
595         write(CurrentVersion);
596         fillTransferMap(messagePorts, m_transferredMessagePorts);
597         fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
598         fillTransferMap(imageBitmaps, m_transferredImageBitmaps);
599     }
600
601     template <class T>
602     void fillTransferMap(const Vector<RefPtr<T>>& input, ObjectPool& result)
603     {
604         if (input.isEmpty())
605             return;
606         JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
607         for (size_t i = 0; i < input.size(); i++) {
608             JSC::JSValue value = toJS(m_exec, globalObject, input[i].get());
609             JSC::JSObject* obj = value.getObject();
610             if (obj && !result.contains(obj))
611                 result.add(obj, i);
612         }
613     }
614
615     SerializationReturnCode serialize(JSValue in);
616
617     bool isArray(VM& vm, JSValue value)
618     {
619         if (!value.isObject())
620             return false;
621         JSObject* object = asObject(value);
622         return object->inherits<JSArray>(vm);
623     }
624
625     bool isMap(VM& vm, JSValue value)
626     {
627         if (!value.isObject())
628             return false;
629         JSObject* object = asObject(value);
630         return object->inherits<JSMap>(vm);
631     }
632     bool isSet(VM& vm, JSValue value)
633     {
634         if (!value.isObject())
635             return false;
636         JSObject* object = asObject(value);
637         return object->inherits<JSSet>(vm);
638     }
639
640     bool checkForDuplicate(JSObject* object)
641     {
642         // Record object for graph reconstruction
643         ObjectPool::const_iterator found = m_objectPool.find(object);
644
645         // Handle duplicate references
646         if (found != m_objectPool.end()) {
647             write(ObjectReferenceTag);
648             ASSERT(found->value < m_objectPool.size());
649             writeObjectIndex(found->value);
650             return true;
651         }
652
653         return false;
654     }
655
656     void recordObject(JSObject* object)
657     {
658         m_objectPool.add(object, m_objectPool.size());
659         m_gcBuffer.appendWithCrashOnOverflow(object);
660     }
661
662     bool startObjectInternal(JSObject* object)
663     {
664         if (checkForDuplicate(object))
665             return false;
666         recordObject(object);
667         return true;
668     }
669
670     bool startObject(JSObject* object)
671     {
672         if (!startObjectInternal(object))
673             return false;
674         write(ObjectTag);
675         return true;
676     }
677
678     bool startArray(JSArray* array)
679     {
680         if (!startObjectInternal(array))
681             return false;
682
683         unsigned length = array->length();
684         write(ArrayTag);
685         write(length);
686         return true;
687     }
688
689     bool startSet(JSSet* set)
690     {
691         if (!startObjectInternal(set))
692             return false;
693
694         write(SetObjectTag);
695         return true;
696     }
697
698     bool startMap(JSMap* map)
699     {
700         if (!startObjectInternal(map))
701             return false;
702
703         write(MapObjectTag);
704         return true;
705     }
706
707     void endObject()
708     {
709         write(TerminatorTag);
710     }
711
712     JSValue getProperty(VM& vm, JSObject* object, const Identifier& propertyName)
713     {
714         PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
715         if (object->methodTable(vm)->getOwnPropertySlot(object, m_exec, propertyName, slot))
716             return slot.getValue(m_exec, propertyName);
717         return JSValue();
718     }
719
720     void dumpImmediate(JSValue value)
721     {
722         if (value.isNull())
723             write(NullTag);
724         else if (value.isUndefined())
725             write(UndefinedTag);
726         else if (value.isNumber()) {
727             if (value.isInt32()) {
728                 if (!value.asInt32())
729                     write(ZeroTag);
730                 else if (value.asInt32() == 1)
731                     write(OneTag);
732                 else {
733                     write(IntTag);
734                     write(static_cast<uint32_t>(value.asInt32()));
735                 }
736             } else {
737                 write(DoubleTag);
738                 write(value.asDouble());
739             }
740         } else if (value.isBoolean()) {
741             if (value.isTrue())
742                 write(TrueTag);
743             else
744                 write(FalseTag);
745         }
746     }
747
748     void dumpString(const String& string)
749     {
750         if (string.isEmpty())
751             write(EmptyStringTag);
752         else {
753             write(StringTag);
754             write(string);
755         }
756     }
757
758     void dumpStringObject(const String& string)
759     {
760         if (string.isEmpty())
761             write(EmptyStringObjectTag);
762         else {
763             write(StringObjectTag);
764             write(string);
765         }
766     }
767
768     JSC::JSValue toJSArrayBuffer(ArrayBuffer& arrayBuffer)
769     {
770         auto& vm = m_exec->vm();
771         auto* globalObject = m_exec->lexicalGlobalObject();
772         if (globalObject->inherits<JSDOMGlobalObject>(vm))
773             return toJS(m_exec, jsCast<JSDOMGlobalObject*>(globalObject), &arrayBuffer);
774
775         if (auto* buffer = arrayBuffer.m_wrapper.get())
776             return buffer;
777
778         return JSC::JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(arrayBuffer.sharingMode()), &arrayBuffer);
779     }
780
781     bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
782     {
783         VM& vm = m_exec->vm();
784         write(ArrayBufferViewTag);
785         if (obj->inherits<JSDataView>(vm))
786             write(DataViewTag);
787         else if (obj->inherits<JSUint8ClampedArray>(vm))
788             write(Uint8ClampedArrayTag);
789         else if (obj->inherits<JSInt8Array>(vm))
790             write(Int8ArrayTag);
791         else if (obj->inherits<JSUint8Array>(vm))
792             write(Uint8ArrayTag);
793         else if (obj->inherits<JSInt16Array>(vm))
794             write(Int16ArrayTag);
795         else if (obj->inherits<JSUint16Array>(vm))
796             write(Uint16ArrayTag);
797         else if (obj->inherits<JSInt32Array>(vm))
798             write(Int32ArrayTag);
799         else if (obj->inherits<JSUint32Array>(vm))
800             write(Uint32ArrayTag);
801         else if (obj->inherits<JSFloat32Array>(vm))
802             write(Float32ArrayTag);
803         else if (obj->inherits<JSFloat64Array>(vm))
804             write(Float64ArrayTag);
805         else
806             return false;
807
808         RefPtr<ArrayBufferView> arrayBufferView = toPossiblySharedArrayBufferView(vm, obj);
809         write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
810         write(static_cast<uint32_t>(arrayBufferView->byteLength()));
811         RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->possiblySharedBuffer();
812         if (!arrayBuffer) {
813             code = SerializationReturnCode::ValidationError;
814             return true;
815         }
816
817         return dumpIfTerminal(toJSArrayBuffer(*arrayBuffer), code);
818     }
819
820     void dumpDOMPoint(const DOMPointReadOnly& point)
821     {
822         write(point.x());
823         write(point.y());
824         write(point.z());
825         write(point.w());
826     }
827
828     void dumpDOMPoint(JSObject* obj)
829     {
830         VM& vm = m_exec->vm();
831         if (obj->inherits<JSDOMPoint>(vm))
832             write(DOMPointTag);
833         else
834             write(DOMPointReadOnlyTag);
835
836         dumpDOMPoint(jsCast<JSDOMPointReadOnly*>(obj)->wrapped());
837     }
838
839     void dumpDOMRect(JSObject* obj)
840     {
841         VM& vm = m_exec->vm();
842         if (obj->inherits<JSDOMRect>(vm))
843             write(DOMRectTag);
844         else
845             write(DOMRectReadOnlyTag);
846
847         auto& rect = jsCast<JSDOMRectReadOnly*>(obj)->wrapped();
848         write(rect.x());
849         write(rect.y());
850         write(rect.width());
851         write(rect.height());
852     }
853
854     void dumpDOMMatrix(JSObject* obj)
855     {
856         VM& vm = m_exec->vm();
857         if (obj->inherits<JSDOMMatrix>(vm))
858             write(DOMMatrixTag);
859         else
860             write(DOMMatrixReadOnlyTag);
861
862         auto& matrix = jsCast<JSDOMMatrixReadOnly*>(obj)->wrapped();
863         bool is2D = matrix.is2D();
864         write(static_cast<uint8_t>(is2D));
865         if (is2D) {
866             write(matrix.m11());
867             write(matrix.m12());
868             write(matrix.m21());
869             write(matrix.m22());
870             write(matrix.m41());
871             write(matrix.m42());
872         } else {
873             write(matrix.m11());
874             write(matrix.m12());
875             write(matrix.m13());
876             write(matrix.m14());
877             write(matrix.m21());
878             write(matrix.m22());
879             write(matrix.m23());
880             write(matrix.m24());
881             write(matrix.m31());
882             write(matrix.m32());
883             write(matrix.m33());
884             write(matrix.m34());
885             write(matrix.m41());
886             write(matrix.m42());
887             write(matrix.m43());
888             write(matrix.m44());
889         }
890     }
891
892     void dumpDOMQuad(JSObject* obj)
893     {
894         write(DOMQuadTag);
895
896         auto& quad = jsCast<JSDOMQuad*>(obj)->wrapped();
897         dumpDOMPoint(quad.p1());
898         dumpDOMPoint(quad.p2());
899         dumpDOMPoint(quad.p3());
900         dumpDOMPoint(quad.p4());
901     }
902
903     void dumpImageBitmap(JSObject* obj, SerializationReturnCode& code)
904     {
905         auto index = m_transferredImageBitmaps.find(obj);
906         if (index != m_transferredImageBitmaps.end()) {
907             write(ImageBitmapTransferTag);
908             write(index->value);
909             return;
910         }
911
912         // Copying ImageBitmaps is not yet supported.
913         code = SerializationReturnCode::ValidationError;
914     }
915
916     bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
917     {
918         if (!value.isCell()) {
919             dumpImmediate(value);
920             return true;
921         }
922         ASSERT(value.isCell());
923
924         if (value.isString()) {
925             dumpString(asString(value)->value(m_exec));
926             return true;
927         }
928
929         if (value.isSymbol()) {
930             code = SerializationReturnCode::DataCloneError;
931             return true;
932         }
933
934         VM& vm = m_exec->vm();
935         if (isArray(vm, value))
936             return false;
937
938         if (value.isObject()) {
939             auto* obj = asObject(value);
940             if (auto* dateObject = jsDynamicCast<DateInstance*>(vm, obj)) {
941                 write(DateTag);
942                 write(dateObject->internalNumber());
943                 return true;
944             }
945             if (auto* booleanObject = jsDynamicCast<BooleanObject*>(vm, obj)) {
946                 if (!startObjectInternal(booleanObject)) // handle duplicates
947                     return true;
948                 write(booleanObject->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
949                 return true;
950             }
951             if (auto* stringObject = jsDynamicCast<StringObject*>(vm, obj)) {
952                 if (!startObjectInternal(stringObject)) // handle duplicates
953                     return true;
954                 String str = asString(stringObject->internalValue())->value(m_exec);
955                 dumpStringObject(str);
956                 return true;
957             }
958             if (auto* numberObject = jsDynamicCast<NumberObject*>(vm, obj)) {
959                 if (!startObjectInternal(numberObject)) // handle duplicates
960                     return true;
961                 write(NumberObjectTag);
962                 write(numberObject->internalValue().asNumber());
963                 return true;
964             }
965             if (auto* file = JSFile::toWrapped(vm, obj)) {
966                 write(FileTag);
967                 write(*file);
968                 return true;
969             }
970             if (auto* list = JSFileList::toWrapped(vm, obj)) {
971                 write(FileListTag);
972                 write(list->length());
973                 for (auto& file : list->files())
974                     write(file.get());
975                 return true;
976             }
977             if (auto* blob = JSBlob::toWrapped(vm, obj)) {
978                 write(BlobTag);
979                 m_blobURLs.append(blob->url());
980                 write(blob->url());
981                 write(blob->type());
982                 write(blob->size());
983                 return true;
984             }
985             if (auto* data = JSImageData::toWrapped(vm, obj)) {
986                 write(ImageDataTag);
987                 write(data->width());
988                 write(data->height());
989                 write(data->data()->length());
990                 write(data->data()->data(), data->data()->length());
991                 return true;
992             }
993             if (auto* regExp = jsDynamicCast<RegExpObject*>(vm, obj)) {
994                 char flags[3];
995                 int flagCount = 0;
996                 if (regExp->regExp()->global())
997                     flags[flagCount++] = 'g';
998                 if (regExp->regExp()->ignoreCase())
999                     flags[flagCount++] = 'i';
1000                 if (regExp->regExp()->multiline())
1001                     flags[flagCount++] = 'm';
1002                 write(RegExpTag);
1003                 write(regExp->regExp()->pattern());
1004                 write(String(flags, flagCount));
1005                 return true;
1006             }
1007             if (obj->inherits<JSMessagePort>(vm)) {
1008                 auto index = m_transferredMessagePorts.find(obj);
1009                 if (index != m_transferredMessagePorts.end()) {
1010                     write(MessagePortReferenceTag);
1011                     write(index->value);
1012                     return true;
1013                 }
1014                 // MessagePort object could not be found in transferred message ports
1015                 code = SerializationReturnCode::ValidationError;
1016                 return true;
1017             }
1018             if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
1019                 if (arrayBuffer->isNeutered()) {
1020                     code = SerializationReturnCode::ValidationError;
1021                     return true;
1022                 }
1023                 auto index = m_transferredArrayBuffers.find(obj);
1024                 if (index != m_transferredArrayBuffers.end()) {
1025                     write(ArrayBufferTransferTag);
1026                     write(index->value);
1027                     return true;
1028                 }
1029                 if (!startObjectInternal(obj)) // handle duplicates
1030                     return true;
1031                 
1032                 if (arrayBuffer->isShared() && m_context == SerializationContext::WorkerPostMessage) {
1033                     uint32_t index = m_sharedBuffers.size();
1034                     ArrayBufferContents contents;
1035                     if (arrayBuffer->shareWith(contents)) {
1036                         write(SharedArrayBufferTag);
1037                         m_sharedBuffers.append(WTFMove(contents));
1038                         write(index);
1039                         return true;
1040                     }
1041                 }
1042                 
1043                 write(ArrayBufferTag);
1044                 write(arrayBuffer->byteLength());
1045                 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
1046                 return true;
1047             }
1048             if (obj->inherits<JSArrayBufferView>(vm)) {
1049                 if (checkForDuplicate(obj))
1050                     return true;
1051                 bool success = dumpArrayBufferView(obj, code);
1052                 recordObject(obj);
1053                 return success;
1054             }
1055 #if ENABLE(WEB_CRYPTO)
1056             if (auto* key = JSCryptoKey::toWrapped(vm, obj)) {
1057                 write(CryptoKeyTag);
1058                 Vector<uint8_t> serializedKey;
1059                 Vector<String> dummyBlobURLs;
1060                 Vector<RefPtr<MessagePort>> dummyMessagePorts;
1061                 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
1062 #if ENABLE(WEBASSEMBLY)
1063                 WasmModuleArray dummyModules;
1064 #endif
1065                 ArrayBufferContentsArray dummySharedBuffers;
1066                 CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, { },
1067 #if ENABLE(WEBASSEMBLY)
1068                     dummyModules,
1069 #endif
1070                     dummyBlobURLs, serializedKey, SerializationContext::Default, dummySharedBuffers);
1071                 rawKeySerializer.write(key);
1072                 Vector<uint8_t> wrappedKey;
1073                 if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey))
1074                     return false;
1075                 write(wrappedKey);
1076                 return true;
1077             }
1078 #endif
1079 #if ENABLE(WEB_RTC)
1080             if (auto* rtcCertificate = JSRTCCertificate::toWrapped(vm, obj)) {
1081                 write(RTCCertificateTag);
1082                 write(rtcCertificate->expires());
1083                 write(rtcCertificate->pemCertificate());
1084                 write(rtcCertificate->origin().toString());
1085                 write(rtcCertificate->pemPrivateKey());
1086                 write(static_cast<unsigned>(rtcCertificate->getFingerprints().size()));
1087                 for (const auto& fingerprint : rtcCertificate->getFingerprints()) {
1088                     write(fingerprint.algorithm);
1089                     write(fingerprint.value);
1090                 }
1091                 return true;
1092             }
1093 #endif
1094 #if ENABLE(WEBASSEMBLY)
1095             if (JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, obj)) {
1096                 if (m_context != SerializationContext::WorkerPostMessage && m_context != SerializationContext::WindowPostMessage)
1097                     return false;
1098
1099                 uint32_t index = m_wasmModules.size(); 
1100                 m_wasmModules.append(makeRef(module->module()));
1101                 write(WasmModuleTag);
1102                 write(index);
1103                 return true;
1104             }
1105 #endif
1106             if (obj->inherits<JSDOMPointReadOnly>(vm)) {
1107                 dumpDOMPoint(obj);
1108                 return true;
1109             }
1110             if (obj->inherits<JSDOMRectReadOnly>(vm)) {
1111                 dumpDOMRect(obj);
1112                 return true;
1113             }
1114             if (obj->inherits<JSDOMMatrixReadOnly>(vm)) {
1115                 dumpDOMMatrix(obj);
1116                 return true;
1117             }
1118             if (obj->inherits<JSDOMQuad>(vm)) {
1119                 dumpDOMQuad(obj);
1120                 return true;
1121             }
1122             if (obj->inherits(vm, JSImageBitmap::info())) {
1123                 dumpImageBitmap(obj, code);
1124                 return true;
1125             }
1126             return false;
1127         }
1128         // Any other types are expected to serialize as null.
1129         write(NullTag);
1130         return true;
1131     }
1132
1133     void write(SerializationTag tag)
1134     {
1135         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1136     }
1137
1138     void write(ArrayBufferViewSubtag tag)
1139     {
1140         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1141     }
1142
1143 #if ENABLE(WEB_CRYPTO)
1144     void write(CryptoKeyClassSubtag tag)
1145     {
1146         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1147     }
1148
1149     void write(CryptoKeyAsymmetricTypeSubtag tag)
1150     {
1151         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1152     }
1153
1154     void write(CryptoKeyUsageTag tag)
1155     {
1156         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1157     }
1158
1159     void write(CryptoAlgorithmIdentifierTag tag)
1160     {
1161         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1162     }
1163 #endif
1164
1165     void write(uint8_t c)
1166     {
1167         writeLittleEndian(m_buffer, c);
1168     }
1169
1170     void write(uint32_t i)
1171     {
1172         writeLittleEndian(m_buffer, i);
1173     }
1174
1175     void write(double d)
1176     {
1177         union {
1178             double d;
1179             int64_t i;
1180         } u;
1181         u.d = d;
1182         writeLittleEndian(m_buffer, u.i);
1183     }
1184
1185     void write(int32_t i)
1186     {
1187         writeLittleEndian(m_buffer, i);
1188     }
1189
1190     void write(unsigned long long i)
1191     {
1192         writeLittleEndian(m_buffer, i);
1193     }
1194     
1195     void write(uint16_t ch)
1196     {
1197         writeLittleEndian(m_buffer, ch);
1198     }
1199
1200     void writeStringIndex(unsigned i)
1201     {
1202         writeConstantPoolIndex(m_constantPool, i);
1203     }
1204     
1205     void writeObjectIndex(unsigned i)
1206     {
1207         writeConstantPoolIndex(m_objectPool, i);
1208     }
1209
1210     template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
1211     {
1212         ASSERT(i < constantPool.size());
1213         if (constantPool.size() <= 0xFF)
1214             write(static_cast<uint8_t>(i));
1215         else if (constantPool.size() <= 0xFFFF)
1216             write(static_cast<uint16_t>(i));
1217         else
1218             write(static_cast<uint32_t>(i));
1219     }
1220
1221     void write(const Identifier& ident)
1222     {
1223         const String& str = ident.string();
1224         StringConstantPool::AddResult addResult = m_constantPool.add(ident.impl(), m_constantPool.size());
1225         if (!addResult.isNewEntry) {
1226             write(StringPoolTag);
1227             writeStringIndex(addResult.iterator->value);
1228             return;
1229         }
1230
1231         unsigned length = str.length();
1232
1233         // Guard against overflow
1234         if (length > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
1235             fail();
1236             return;
1237         }
1238
1239         if (str.is8Bit())
1240             writeLittleEndian<uint32_t>(m_buffer, length | StringDataIs8BitFlag);
1241         else
1242             writeLittleEndian<uint32_t>(m_buffer, length);
1243
1244         if (!length)
1245             return;
1246         if (str.is8Bit()) {
1247             if (!writeLittleEndian(m_buffer, str.characters8(), length))
1248                 fail();
1249             return;
1250         }
1251         if (!writeLittleEndian(m_buffer, str.characters16(), length))
1252             fail();
1253     }
1254
1255     void write(const String& str)
1256     {
1257         if (str.isNull())
1258             write(m_emptyIdentifier);
1259         else
1260             write(Identifier::fromString(m_exec->vm(), str));
1261     }
1262
1263     void write(const Vector<uint8_t>& vector)
1264     {
1265         uint32_t size = vector.size();
1266         write(size);
1267         writeLittleEndian(m_buffer, vector.data(), size);
1268     }
1269
1270     void write(const File& file)
1271     {
1272         m_blobURLs.append(file.url());
1273         write(file.path());
1274         write(file.url());
1275         write(file.type());
1276         write(file.name());
1277         write(static_cast<double>(file.lastModifiedOverride().valueOr(-1)));
1278     }
1279
1280 #if ENABLE(WEB_CRYPTO)
1281     void write(CryptoAlgorithmIdentifier algorithm)
1282     {
1283         switch (algorithm) {
1284         case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
1285             write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
1286             break;
1287         case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
1288             write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
1289             break;
1290         case CryptoAlgorithmIdentifier::RSA_PSS:
1291             write(CryptoAlgorithmIdentifierTag::RSA_PSS);
1292             break;
1293         case CryptoAlgorithmIdentifier::RSA_OAEP:
1294             write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
1295             break;
1296         case CryptoAlgorithmIdentifier::ECDSA:
1297             write(CryptoAlgorithmIdentifierTag::ECDSA);
1298             break;
1299         case CryptoAlgorithmIdentifier::ECDH:
1300             write(CryptoAlgorithmIdentifierTag::ECDH);
1301             break;
1302         case CryptoAlgorithmIdentifier::AES_CTR:
1303             write(CryptoAlgorithmIdentifierTag::AES_CTR);
1304             break;
1305         case CryptoAlgorithmIdentifier::AES_CBC:
1306             write(CryptoAlgorithmIdentifierTag::AES_CBC);
1307             break;
1308         case CryptoAlgorithmIdentifier::AES_GCM:
1309             write(CryptoAlgorithmIdentifierTag::AES_GCM);
1310             break;
1311         case CryptoAlgorithmIdentifier::AES_CFB:
1312             write(CryptoAlgorithmIdentifierTag::AES_CFB);
1313             break;
1314         case CryptoAlgorithmIdentifier::AES_KW:
1315             write(CryptoAlgorithmIdentifierTag::AES_KW);
1316             break;
1317         case CryptoAlgorithmIdentifier::HMAC:
1318             write(CryptoAlgorithmIdentifierTag::HMAC);
1319             break;
1320         case CryptoAlgorithmIdentifier::SHA_1:
1321             write(CryptoAlgorithmIdentifierTag::SHA_1);
1322             break;
1323         case CryptoAlgorithmIdentifier::SHA_224:
1324             write(CryptoAlgorithmIdentifierTag::SHA_224);
1325             break;
1326         case CryptoAlgorithmIdentifier::SHA_256:
1327             write(CryptoAlgorithmIdentifierTag::SHA_256);
1328             break;
1329         case CryptoAlgorithmIdentifier::SHA_384:
1330             write(CryptoAlgorithmIdentifierTag::SHA_384);
1331             break;
1332         case CryptoAlgorithmIdentifier::SHA_512:
1333             write(CryptoAlgorithmIdentifierTag::SHA_512);
1334             break;
1335         case CryptoAlgorithmIdentifier::HKDF:
1336             write(CryptoAlgorithmIdentifierTag::HKDF);
1337             break;
1338         case CryptoAlgorithmIdentifier::PBKDF2:
1339             write(CryptoAlgorithmIdentifierTag::PBKDF2);
1340             break;
1341         }
1342     }
1343
1344     void write(CryptoKeyRSAComponents::Type type)
1345     {
1346         switch (type) {
1347         case CryptoKeyRSAComponents::Type::Public:
1348             write(CryptoKeyAsymmetricTypeSubtag::Public);
1349             return;
1350         case CryptoKeyRSAComponents::Type::Private:
1351             write(CryptoKeyAsymmetricTypeSubtag::Private);
1352             return;
1353         }
1354     }
1355
1356     void write(const CryptoKeyRSAComponents& key)
1357     {
1358         write(key.type());
1359         write(key.modulus());
1360         write(key.exponent());
1361         if (key.type() == CryptoKeyRSAComponents::Type::Public)
1362             return;
1363
1364         write(key.privateExponent());
1365
1366         unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
1367         write(primeCount);
1368         if (!primeCount)
1369             return;
1370
1371         write(key.firstPrimeInfo().primeFactor);
1372         write(key.firstPrimeInfo().factorCRTExponent);
1373         write(key.secondPrimeInfo().primeFactor);
1374         write(key.secondPrimeInfo().factorCRTExponent);
1375         write(key.secondPrimeInfo().factorCRTCoefficient);
1376         for (unsigned i = 2; i < primeCount; ++i) {
1377             write(key.otherPrimeInfos()[i].primeFactor);
1378             write(key.otherPrimeInfos()[i].factorCRTExponent);
1379             write(key.otherPrimeInfos()[i].factorCRTCoefficient);
1380         }
1381     }
1382
1383     void write(const CryptoKey* key)
1384     {
1385         write(currentKeyFormatVersion);
1386
1387         write(key->extractable());
1388
1389         CryptoKeyUsageBitmap usages = key->usagesBitmap();
1390         write(countUsages(usages));
1391         if (usages & CryptoKeyUsageEncrypt)
1392             write(CryptoKeyUsageTag::Encrypt);
1393         if (usages & CryptoKeyUsageDecrypt)
1394             write(CryptoKeyUsageTag::Decrypt);
1395         if (usages & CryptoKeyUsageSign)
1396             write(CryptoKeyUsageTag::Sign);
1397         if (usages & CryptoKeyUsageVerify)
1398             write(CryptoKeyUsageTag::Verify);
1399         if (usages & CryptoKeyUsageDeriveKey)
1400             write(CryptoKeyUsageTag::DeriveKey);
1401         if (usages & CryptoKeyUsageDeriveBits)
1402             write(CryptoKeyUsageTag::DeriveBits);
1403         if (usages & CryptoKeyUsageWrapKey)
1404             write(CryptoKeyUsageTag::WrapKey);
1405         if (usages & CryptoKeyUsageUnwrapKey)
1406             write(CryptoKeyUsageTag::UnwrapKey);
1407
1408         switch (key->keyClass()) {
1409         case CryptoKeyClass::HMAC:
1410             write(CryptoKeyClassSubtag::HMAC);
1411             write(downcast<CryptoKeyHMAC>(*key).key());
1412             write(downcast<CryptoKeyHMAC>(*key).hashAlgorithmIdentifier());
1413             break;
1414         case CryptoKeyClass::AES:
1415             write(CryptoKeyClassSubtag::AES);
1416             write(key->algorithmIdentifier());
1417             write(downcast<CryptoKeyAES>(*key).key());
1418             break;
1419         case CryptoKeyClass::EC:
1420             write(CryptoKeyClassSubtag::EC);
1421             write(key->algorithmIdentifier());
1422             write(downcast<CryptoKeyEC>(*key).namedCurveString());
1423             switch (key->type()) {
1424             case CryptoKey::Type::Public: {
1425                 write(CryptoKeyAsymmetricTypeSubtag::Public);
1426                 auto result = downcast<CryptoKeyEC>(*key).exportRaw();
1427                 ASSERT(!result.hasException());
1428                 write(result.releaseReturnValue());
1429                 break;
1430             }
1431             case CryptoKey::Type::Private: {
1432                 write(CryptoKeyAsymmetricTypeSubtag::Private);
1433                 // Use the standard complied method is not very efficient, but simple/reliable.
1434                 auto result = downcast<CryptoKeyEC>(*key).exportPkcs8();
1435                 ASSERT(!result.hasException());
1436                 write(result.releaseReturnValue());
1437                 break;
1438             }
1439             default:
1440                 ASSERT_NOT_REACHED();
1441             }
1442             break;
1443         case CryptoKeyClass::Raw:
1444             write(CryptoKeyClassSubtag::Raw);
1445             write(key->algorithmIdentifier());
1446             write(downcast<CryptoKeyRaw>(*key).key());
1447             break;
1448         case CryptoKeyClass::RSA:
1449             write(CryptoKeyClassSubtag::RSA);
1450             write(key->algorithmIdentifier());
1451             CryptoAlgorithmIdentifier hash;
1452             bool isRestrictedToHash = downcast<CryptoKeyRSA>(*key).isRestrictedToHash(hash);
1453             write(isRestrictedToHash);
1454             if (isRestrictedToHash)
1455                 write(hash);
1456             write(*downcast<CryptoKeyRSA>(*key).exportData());
1457             break;
1458         }
1459     }
1460 #endif
1461
1462     void write(const uint8_t* data, unsigned length)
1463     {
1464         m_buffer.append(data, length);
1465     }
1466
1467     Vector<uint8_t>& m_buffer;
1468     Vector<String>& m_blobURLs;
1469     ObjectPool m_objectPool;
1470     ObjectPool m_transferredMessagePorts;
1471     ObjectPool m_transferredArrayBuffers;
1472     ObjectPool m_transferredImageBitmaps;
1473     typedef HashMap<RefPtr<UniquedStringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
1474     StringConstantPool m_constantPool;
1475     Identifier m_emptyIdentifier;
1476     SerializationContext m_context;
1477     ArrayBufferContentsArray& m_sharedBuffers;
1478 #if ENABLE(WEBASSEMBLY)
1479     WasmModuleArray& m_wasmModules;
1480 #endif
1481 };
1482
1483 SerializationReturnCode CloneSerializer::serialize(JSValue in)
1484 {
1485     VM& vm = m_exec->vm();
1486     Vector<uint32_t, 16> indexStack;
1487     Vector<uint32_t, 16> lengthStack;
1488     Vector<PropertyNameArray, 16> propertyStack;
1489     Vector<JSObject*, 32> inputObjectStack;
1490     Vector<JSMapIterator*, 4> mapIteratorStack;
1491     Vector<JSSetIterator*, 4> setIteratorStack;
1492     Vector<JSValue, 4> mapIteratorValueStack;
1493     Vector<WalkerState, 16> stateStack;
1494     WalkerState state = StateUnknown;
1495     JSValue inValue = in;
1496     while (1) {
1497         switch (state) {
1498             arrayStartState:
1499             case ArrayStartState: {
1500                 ASSERT(isArray(vm, inValue));
1501                 if (inputObjectStack.size() > maximumFilterRecursion)
1502                     return SerializationReturnCode::StackOverflowError;
1503
1504                 JSArray* inArray = asArray(inValue);
1505                 unsigned length = inArray->length();
1506                 if (!startArray(inArray))
1507                     break;
1508                 inputObjectStack.append(inArray);
1509                 indexStack.append(0);
1510                 lengthStack.append(length);
1511             }
1512             arrayStartVisitMember:
1513             FALLTHROUGH;
1514             case ArrayStartVisitMember: {
1515                 JSObject* array = inputObjectStack.last();
1516                 uint32_t index = indexStack.last();
1517                 if (index == lengthStack.last()) {
1518                     indexStack.removeLast();
1519                     lengthStack.removeLast();
1520
1521                     propertyStack.append(PropertyNameArray(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1522                     array->methodTable(vm)->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), EnumerationMode());
1523                     if (propertyStack.last().size()) {
1524                         write(NonIndexPropertiesTag);
1525                         indexStack.append(0);
1526                         goto objectStartVisitMember;
1527                     }
1528                     propertyStack.removeLast();
1529
1530                     endObject();
1531                     inputObjectStack.removeLast();
1532                     break;
1533                 }
1534                 inValue = array->getDirectIndex(m_exec, index);
1535                 if (!inValue) {
1536                     indexStack.last()++;
1537                     goto arrayStartVisitMember;
1538                 }
1539
1540                 write(index);
1541                 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1542                 if (dumpIfTerminal(inValue, terminalCode)) {
1543                     if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1544                         return terminalCode;
1545                     indexStack.last()++;
1546                     goto arrayStartVisitMember;
1547                 }
1548                 stateStack.append(ArrayEndVisitMember);
1549                 goto stateUnknown;
1550             }
1551             case ArrayEndVisitMember: {
1552                 indexStack.last()++;
1553                 goto arrayStartVisitMember;
1554             }
1555             objectStartState:
1556             case ObjectStartState: {
1557                 ASSERT(inValue.isObject());
1558                 if (inputObjectStack.size() > maximumFilterRecursion)
1559                     return SerializationReturnCode::StackOverflowError;
1560                 JSObject* inObject = asObject(inValue);
1561                 if (!startObject(inObject))
1562                     break;
1563                 // At this point, all supported objects other than Object
1564                 // objects have been handled. If we reach this point and
1565                 // the input is not an Object object then we should throw
1566                 // a DataCloneError.
1567                 if (inObject->classInfo(vm) != JSFinalObject::info())
1568                     return SerializationReturnCode::DataCloneError;
1569                 inputObjectStack.append(inObject);
1570                 indexStack.append(0);
1571                 propertyStack.append(PropertyNameArray(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1572                 inObject->methodTable(vm)->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), EnumerationMode());
1573             }
1574             objectStartVisitMember:
1575             FALLTHROUGH;
1576             case ObjectStartVisitMember: {
1577                 JSObject* object = inputObjectStack.last();
1578                 uint32_t index = indexStack.last();
1579                 PropertyNameArray& properties = propertyStack.last();
1580                 if (index == properties.size()) {
1581                     endObject();
1582                     inputObjectStack.removeLast();
1583                     indexStack.removeLast();
1584                     propertyStack.removeLast();
1585                     break;
1586                 }
1587                 inValue = getProperty(vm, object, properties[index]);
1588                 if (shouldTerminate())
1589                     return SerializationReturnCode::ExistingExceptionError;
1590
1591                 if (!inValue) {
1592                     // Property was removed during serialisation
1593                     indexStack.last()++;
1594                     goto objectStartVisitMember;
1595                 }
1596                 write(properties[index]);
1597
1598                 if (shouldTerminate())
1599                     return SerializationReturnCode::ExistingExceptionError;
1600
1601                 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1602                 if (!dumpIfTerminal(inValue, terminalCode)) {
1603                     stateStack.append(ObjectEndVisitMember);
1604                     goto stateUnknown;
1605                 }
1606                 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1607                     return terminalCode;
1608                 FALLTHROUGH;
1609             }
1610             case ObjectEndVisitMember: {
1611                 if (shouldTerminate())
1612                     return SerializationReturnCode::ExistingExceptionError;
1613
1614                 indexStack.last()++;
1615                 goto objectStartVisitMember;
1616             }
1617             mapStartState: {
1618                 ASSERT(inValue.isObject());
1619                 if (inputObjectStack.size() > maximumFilterRecursion)
1620                     return SerializationReturnCode::StackOverflowError;
1621                 JSMap* inMap = jsCast<JSMap*>(inValue);
1622                 if (!startMap(inMap))
1623                     break;
1624                 JSMapIterator* iterator = JSMapIterator::create(vm, vm.mapIteratorStructure(), inMap, IterateKeyValue);
1625                 m_gcBuffer.appendWithCrashOnOverflow(inMap);
1626                 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1627                 mapIteratorStack.append(iterator);
1628                 inputObjectStack.append(inMap);
1629                 goto mapDataStartVisitEntry;
1630             }
1631             mapDataStartVisitEntry:
1632             case MapDataStartVisitEntry: {
1633                 JSMapIterator* iterator = mapIteratorStack.last();
1634                 JSValue key, value;
1635                 if (!iterator->nextKeyValue(m_exec, key, value)) {
1636                     mapIteratorStack.removeLast();
1637                     JSObject* object = inputObjectStack.last();
1638                     ASSERT(jsDynamicCast<JSMap*>(vm, object));
1639                     propertyStack.append(PropertyNameArray(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1640                     object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1641                     write(NonMapPropertiesTag);
1642                     indexStack.append(0);
1643                     goto objectStartVisitMember;
1644                 }
1645                 inValue = key;
1646                 m_gcBuffer.appendWithCrashOnOverflow(value);
1647                 mapIteratorValueStack.append(value);
1648                 stateStack.append(MapDataEndVisitKey);
1649                 goto stateUnknown;
1650             }
1651             case MapDataEndVisitKey: {
1652                 inValue = mapIteratorValueStack.last();
1653                 mapIteratorValueStack.removeLast();
1654                 stateStack.append(MapDataEndVisitValue);
1655                 goto stateUnknown;
1656             }
1657             case MapDataEndVisitValue: {
1658                 goto mapDataStartVisitEntry;
1659             }
1660
1661             setStartState: {
1662                 ASSERT(inValue.isObject());
1663                 if (inputObjectStack.size() > maximumFilterRecursion)
1664                     return SerializationReturnCode::StackOverflowError;
1665                 JSSet* inSet = jsCast<JSSet*>(inValue);
1666                 if (!startSet(inSet))
1667                     break;
1668                 JSSetIterator* iterator = JSSetIterator::create(vm, vm.setIteratorStructure(), inSet, IterateKey);
1669                 m_gcBuffer.appendWithCrashOnOverflow(inSet);
1670                 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1671                 setIteratorStack.append(iterator);
1672                 inputObjectStack.append(inSet);
1673                 goto setDataStartVisitEntry;
1674             }
1675             setDataStartVisitEntry:
1676             case SetDataStartVisitEntry: {
1677                 JSSetIterator* iterator = setIteratorStack.last();
1678                 JSValue key;
1679                 if (!iterator->next(m_exec, key)) {
1680                     setIteratorStack.removeLast();
1681                     JSObject* object = inputObjectStack.last();
1682                     ASSERT(jsDynamicCast<JSSet*>(vm, object));
1683                     propertyStack.append(PropertyNameArray(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1684                     object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1685                     write(NonSetPropertiesTag);
1686                     indexStack.append(0);
1687                     goto objectStartVisitMember;
1688                 }
1689                 inValue = key;
1690                 stateStack.append(SetDataEndVisitKey);
1691                 goto stateUnknown;
1692             }
1693             case SetDataEndVisitKey: {
1694                 goto setDataStartVisitEntry;
1695             }
1696
1697             stateUnknown:
1698             case StateUnknown: {
1699                 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1700                 if (dumpIfTerminal(inValue, terminalCode)) {
1701                     if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1702                         return terminalCode;
1703                     break;
1704                 }
1705
1706                 if (isArray(vm, inValue))
1707                     goto arrayStartState;
1708                 if (isMap(vm, inValue))
1709                     goto mapStartState;
1710                 if (isSet(vm, inValue))
1711                     goto setStartState;
1712                 goto objectStartState;
1713             }
1714         }
1715         if (stateStack.isEmpty())
1716             break;
1717
1718         state = stateStack.last();
1719         stateStack.removeLast();
1720     }
1721     if (m_failed)
1722         return SerializationReturnCode::UnspecifiedError;
1723
1724     return SerializationReturnCode::SuccessfullyCompleted;
1725 }
1726
1727 class CloneDeserializer : CloneBase {
1728 public:
1729     static String deserializeString(const Vector<uint8_t>& buffer)
1730     {
1731         if (buffer.isEmpty())
1732             return String();
1733         const uint8_t* ptr = buffer.begin();
1734         const uint8_t* end = buffer.end();
1735         uint32_t version;
1736         if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1737             return String();
1738         uint8_t tag;
1739         if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1740             return String();
1741         uint32_t length;
1742         if (!readLittleEndian(ptr, end, length))
1743             return String();
1744         bool is8Bit = length & StringDataIs8BitFlag;
1745         length &= ~StringDataIs8BitFlag;
1746         String str;
1747         if (!readString(ptr, end, str, length, is8Bit))
1748             return String();
1749         return str;
1750     }
1751
1752     static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
1753 #if ENABLE(WEBASSEMBLY)
1754         , WasmModuleArray* wasmModules
1755 #endif
1756         )
1757     {
1758         if (!buffer.size())
1759             return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
1760         CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths, sharedBuffers, WTFMove(imageBuffers)
1761 #if ENABLE(WEBASSEMBLY)
1762             , wasmModules
1763 #endif
1764             );
1765         if (!deserializer.isValid())
1766             return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
1767         return deserializer.deserialize();
1768     }
1769
1770 private:
1771     struct CachedString {
1772         CachedString(const String& string)
1773             : m_string(string)
1774         {
1775         }
1776
1777         JSValue jsString(ExecState* exec)
1778         {
1779             if (!m_jsString)
1780                 m_jsString = JSC::jsString(exec->vm(), m_string);
1781             return m_jsString;
1782         }
1783         const String& string() { return m_string; }
1784         String takeString() { return WTFMove(m_string); }
1785
1786     private:
1787         String m_string;
1788         JSValue m_jsString;
1789     };
1790
1791     struct CachedStringRef {
1792         CachedStringRef()
1793             : m_base(0)
1794             , m_index(0)
1795         {
1796         }
1797         CachedStringRef(Vector<CachedString>* base, size_t index)
1798             : m_base(base)
1799             , m_index(index)
1800         {
1801         }
1802         
1803         CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1804         
1805     private:
1806         Vector<CachedString>* m_base;
1807         size_t m_index;
1808     };
1809
1810     CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers,
1811 #if ENABLE(WEBASSEMBLY)
1812         WasmModuleArray* wasmModules,
1813 #endif
1814         const Vector<uint8_t>& buffer)
1815         : CloneBase(exec)
1816         , m_globalObject(globalObject)
1817         , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1818         , m_ptr(buffer.data())
1819         , m_end(buffer.data() + buffer.size())
1820         , m_version(0xFFFFFFFF)
1821         , m_messagePorts(messagePorts)
1822         , m_arrayBufferContents(arrayBufferContents)
1823         , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1824         , m_imageBuffers(WTFMove(imageBuffers))
1825         , m_imageBitmaps(m_imageBuffers.size())
1826 #if ENABLE(WEBASSEMBLY)
1827         , m_wasmModules(wasmModules)
1828 #endif
1829     {
1830         if (!read(m_version))
1831             m_version = 0xFFFFFFFF;
1832     }
1833
1834     CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers
1835 #if ENABLE(WEBASSEMBLY)
1836         , WasmModuleArray* wasmModules
1837 #endif
1838         )
1839         : CloneBase(exec)
1840         , m_globalObject(globalObject)
1841         , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1842         , m_ptr(buffer.data())
1843         , m_end(buffer.data() + buffer.size())
1844         , m_version(0xFFFFFFFF)
1845         , m_messagePorts(messagePorts)
1846         , m_arrayBufferContents(arrayBufferContents)
1847         , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1848         , m_blobURLs(blobURLs)
1849         , m_blobFilePaths(blobFilePaths)
1850         , m_sharedBuffers(sharedBuffers)
1851         , m_imageBuffers(WTFMove(imageBuffers))
1852         , m_imageBitmaps(m_imageBuffers.size())
1853 #if ENABLE(WEBASSEMBLY)
1854         , m_wasmModules(wasmModules)
1855 #endif
1856     {
1857         if (!read(m_version))
1858             m_version = 0xFFFFFFFF;
1859     }
1860
1861     DeserializationResult deserialize();
1862
1863     bool isValid() const { return m_version <= CurrentVersion; }
1864
1865     template <typename T> bool readLittleEndian(T& value)
1866     {
1867         if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1868             fail();
1869             return false;
1870         }
1871         return true;
1872     }
1873 #if ASSUME_LITTLE_ENDIAN
1874     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1875     {
1876         if (ptr > end - sizeof(value))
1877             return false;
1878
1879         if (sizeof(T) == 1)
1880             value = *ptr++;
1881         else {
1882             value = *reinterpret_cast<const T*>(ptr);
1883             ptr += sizeof(T);
1884         }
1885         return true;
1886     }
1887 #else
1888     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1889     {
1890         if (ptr > end - sizeof(value))
1891             return false;
1892
1893         if (sizeof(T) == 1)
1894             value = *ptr++;
1895         else {
1896             value = 0;
1897             for (unsigned i = 0; i < sizeof(T); i++)
1898                 value += ((T)*ptr++) << (i * 8);
1899         }
1900         return true;
1901     }
1902 #endif
1903
1904     bool read(uint32_t& i)
1905     {
1906         return readLittleEndian(i);
1907     }
1908
1909     bool read(int32_t& i)
1910     {
1911         return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1912     }
1913
1914     bool read(uint16_t& i)
1915     {
1916         return readLittleEndian(i);
1917     }
1918
1919     bool read(uint8_t& i)
1920     {
1921         return readLittleEndian(i);
1922     }
1923
1924     bool read(double& d)
1925     {
1926         union {
1927             double d;
1928             uint64_t i64;
1929         } u;
1930         if (!readLittleEndian(u.i64))
1931             return false;
1932         d = u.d;
1933         return true;
1934     }
1935
1936     bool read(unsigned long long& i)
1937     {
1938         return readLittleEndian(i);
1939     }
1940
1941     bool readStringIndex(uint32_t& i)
1942     {
1943         return readConstantPoolIndex(m_constantPool, i);
1944     }
1945
1946     template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1947     {
1948         if (constantPool.size() <= 0xFF) {
1949             uint8_t i8;
1950             if (!read(i8))
1951                 return false;
1952             i = i8;
1953             return true;
1954         }
1955         if (constantPool.size() <= 0xFFFF) {
1956             uint16_t i16;
1957             if (!read(i16))
1958                 return false;
1959             i = i16;
1960             return true;
1961         }
1962         return read(i);
1963     }
1964
1965     static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit)
1966     {
1967         if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar))
1968             return false;
1969
1970         if (is8Bit) {
1971             if ((end - ptr) < static_cast<int>(length))
1972                 return false;
1973             str = String(reinterpret_cast<const LChar*>(ptr), length);
1974             ptr += length;
1975             return true;
1976         }
1977
1978         unsigned size = length * sizeof(UChar);
1979         if ((end - ptr) < static_cast<int>(size))
1980             return false;
1981
1982 #if ASSUME_LITTLE_ENDIAN
1983         str = String(reinterpret_cast<const UChar*>(ptr), length);
1984         ptr += length * sizeof(UChar);
1985 #else
1986         Vector<UChar> buffer;
1987         buffer.reserveCapacity(length);
1988         for (unsigned i = 0; i < length; i++) {
1989             uint16_t ch;
1990             readLittleEndian(ptr, end, ch);
1991             buffer.append(ch);
1992         }
1993         str = String::adopt(WTFMove(buffer));
1994 #endif
1995         return true;
1996     }
1997
1998     bool readStringData(CachedStringRef& cachedString)
1999     {
2000         bool scratch;
2001         return readStringData(cachedString, scratch);
2002     }
2003
2004     bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
2005     {
2006         if (m_failed)
2007             return false;
2008         uint32_t length = 0;
2009         if (!read(length))
2010             return false;
2011         if (length == TerminatorTag) {
2012             wasTerminator = true;
2013             return false;
2014         }
2015         if (length == StringPoolTag) {
2016             unsigned index = 0;
2017             if (!readStringIndex(index)) {
2018                 fail();
2019                 return false;
2020             }
2021             if (index >= m_constantPool.size()) {
2022                 fail();
2023                 return false;
2024             }
2025             cachedString = CachedStringRef(&m_constantPool, index);
2026             return true;
2027         }
2028         bool is8Bit = length & StringDataIs8BitFlag;
2029         length &= ~StringDataIs8BitFlag;
2030         String str;
2031         if (!readString(m_ptr, m_end, str, length, is8Bit)) {
2032             fail();
2033             return false;
2034         }
2035         m_constantPool.append(str);
2036         cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
2037         return true;
2038     }
2039
2040     SerializationTag readTag()
2041     {
2042         if (m_ptr >= m_end)
2043             return ErrorTag;
2044         return static_cast<SerializationTag>(*m_ptr++);
2045     }
2046
2047     bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
2048     {
2049         if (m_ptr >= m_end)
2050             return false;
2051         tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
2052         return true;
2053     }
2054
2055     void putProperty(JSObject* object, unsigned index, JSValue value)
2056     {
2057         object->putDirectIndex(m_exec, index, value);
2058     }
2059
2060     void putProperty(JSObject* object, const Identifier& property, JSValue value)
2061     {
2062         object->putDirectMayBeIndex(m_exec, property, value);
2063     }
2064
2065     bool readFile(RefPtr<File>& file)
2066     {
2067         CachedStringRef path;
2068         if (!readStringData(path))
2069             return false;
2070         CachedStringRef url;
2071         if (!readStringData(url))
2072             return false;
2073         CachedStringRef type;
2074         if (!readStringData(type))
2075             return false;
2076         CachedStringRef name;
2077         if (!readStringData(name))
2078             return false;
2079         Optional<int64_t> optionalLastModified;
2080         if (m_version > 6) {
2081             double lastModified;
2082             if (!read(lastModified))
2083                 return false;
2084             if (lastModified >= 0)
2085                 optionalLastModified = lastModified;
2086         }
2087
2088         // If the blob URL for this file has an associated blob file path, prefer that one over the "built-in" path.
2089         String filePath = blobFilePathForBlobURL(url->string());
2090         if (filePath.isEmpty())
2091             filePath = path->string();
2092
2093         if (m_isDOMGlobalObject)
2094             file = File::deserialize(filePath, URL(URL(), url->string()), type->string(), name->string(), optionalLastModified);
2095         return true;
2096     }
2097
2098     bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
2099     {
2100         uint32_t length;
2101         if (!read(length))
2102             return false;
2103         if (m_ptr + length > m_end)
2104             return false;
2105         arrayBuffer = ArrayBuffer::create(m_ptr, length);
2106         m_ptr += length;
2107         return true;
2108     }
2109
2110     bool readArrayBufferView(VM& vm, JSValue& arrayBufferView)
2111     {
2112         ArrayBufferViewSubtag arrayBufferViewSubtag;
2113         if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
2114             return false;
2115         uint32_t byteOffset;
2116         if (!read(byteOffset))
2117             return false;
2118         uint32_t byteLength;
2119         if (!read(byteLength))
2120             return false;
2121         JSObject* arrayBufferObj = asObject(readTerminal());
2122         if (!arrayBufferObj || !arrayBufferObj->inherits<JSArrayBuffer>(vm))
2123             return false;
2124
2125         unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
2126         if (!elementSize)
2127             return false;
2128         unsigned length = byteLength / elementSize;
2129         if (length * elementSize != byteLength)
2130             return false;
2131
2132         RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(vm, arrayBufferObj);
2133         switch (arrayBufferViewSubtag) {
2134         case DataViewTag:
2135             arrayBufferView = toJS(m_exec, m_globalObject, DataView::create(WTFMove(arrayBuffer), byteOffset, length).get());
2136             return true;
2137         case Int8ArrayTag:
2138             arrayBufferView = toJS(m_exec, m_globalObject, Int8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2139             return true;
2140         case Uint8ArrayTag:
2141             arrayBufferView = toJS(m_exec, m_globalObject, Uint8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2142             return true;
2143         case Uint8ClampedArrayTag:
2144             arrayBufferView = toJS(m_exec, m_globalObject, Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2145             return true;
2146         case Int16ArrayTag:
2147             arrayBufferView = toJS(m_exec, m_globalObject, Int16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2148             return true;
2149         case Uint16ArrayTag:
2150             arrayBufferView = toJS(m_exec, m_globalObject, Uint16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2151             return true;
2152         case Int32ArrayTag:
2153             arrayBufferView = toJS(m_exec, m_globalObject, Int32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2154             return true;
2155         case Uint32ArrayTag:
2156             arrayBufferView = toJS(m_exec, m_globalObject, Uint32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2157             return true;
2158         case Float32ArrayTag:
2159             arrayBufferView = toJS(m_exec, m_globalObject, Float32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2160             return true;
2161         case Float64ArrayTag:
2162             arrayBufferView = toJS(m_exec, m_globalObject, Float64Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2163             return true;
2164         default:
2165             return false;
2166         }
2167     }
2168
2169     bool read(Vector<uint8_t>& result)
2170     {
2171         ASSERT(result.isEmpty());
2172         uint32_t size;
2173         if (!read(size))
2174             return false;
2175         if (m_ptr + size > m_end)
2176             return false;
2177         result.append(m_ptr, size);
2178         m_ptr += size;
2179         return true;
2180     }
2181
2182 #if ENABLE(WEB_CRYPTO)
2183     bool read(CryptoAlgorithmIdentifier& result)
2184     {
2185         uint8_t algorithmTag;
2186         if (!read(algorithmTag))
2187             return false;
2188         if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
2189             return false;
2190         switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
2191         case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
2192             result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
2193             break;
2194         case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
2195             result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
2196             break;
2197         case CryptoAlgorithmIdentifierTag::RSA_PSS:
2198             result = CryptoAlgorithmIdentifier::RSA_PSS;
2199             break;
2200         case CryptoAlgorithmIdentifierTag::RSA_OAEP:
2201             result = CryptoAlgorithmIdentifier::RSA_OAEP;
2202             break;
2203         case CryptoAlgorithmIdentifierTag::ECDSA:
2204             result = CryptoAlgorithmIdentifier::ECDSA;
2205             break;
2206         case CryptoAlgorithmIdentifierTag::ECDH:
2207             result = CryptoAlgorithmIdentifier::ECDH;
2208             break;
2209         case CryptoAlgorithmIdentifierTag::AES_CTR:
2210             result = CryptoAlgorithmIdentifier::AES_CTR;
2211             break;
2212         case CryptoAlgorithmIdentifierTag::AES_CBC:
2213             result = CryptoAlgorithmIdentifier::AES_CBC;
2214             break;
2215         case CryptoAlgorithmIdentifierTag::AES_GCM:
2216             result = CryptoAlgorithmIdentifier::AES_GCM;
2217             break;
2218         case CryptoAlgorithmIdentifierTag::AES_CFB:
2219             result = CryptoAlgorithmIdentifier::AES_CFB;
2220             break;
2221         case CryptoAlgorithmIdentifierTag::AES_KW:
2222             result = CryptoAlgorithmIdentifier::AES_KW;
2223             break;
2224         case CryptoAlgorithmIdentifierTag::HMAC:
2225             result = CryptoAlgorithmIdentifier::HMAC;
2226             break;
2227         case CryptoAlgorithmIdentifierTag::SHA_1:
2228             result = CryptoAlgorithmIdentifier::SHA_1;
2229             break;
2230         case CryptoAlgorithmIdentifierTag::SHA_224:
2231             result = CryptoAlgorithmIdentifier::SHA_224;
2232             break;
2233         case CryptoAlgorithmIdentifierTag::SHA_256:
2234             result = CryptoAlgorithmIdentifier::SHA_256;
2235             break;
2236         case CryptoAlgorithmIdentifierTag::SHA_384:
2237             result = CryptoAlgorithmIdentifier::SHA_384;
2238             break;
2239         case CryptoAlgorithmIdentifierTag::SHA_512:
2240             result = CryptoAlgorithmIdentifier::SHA_512;
2241             break;
2242         case CryptoAlgorithmIdentifierTag::HKDF:
2243             result = CryptoAlgorithmIdentifier::HKDF;
2244             break;
2245         case CryptoAlgorithmIdentifierTag::PBKDF2:
2246             result = CryptoAlgorithmIdentifier::PBKDF2;
2247             break;
2248         }
2249         return true;
2250     }
2251
2252     bool read(CryptoKeyClassSubtag& result)
2253     {
2254         uint8_t tag;
2255         if (!read(tag))
2256             return false;
2257         if (tag > cryptoKeyClassSubtagMaximumValue)
2258             return false;
2259         result = static_cast<CryptoKeyClassSubtag>(tag);
2260         return true;
2261     }
2262
2263     bool read(CryptoKeyUsageTag& result)
2264     {
2265         uint8_t tag;
2266         if (!read(tag))
2267             return false;
2268         if (tag > cryptoKeyUsageTagMaximumValue)
2269             return false;
2270         result = static_cast<CryptoKeyUsageTag>(tag);
2271         return true;
2272     }
2273
2274     bool read(CryptoKeyAsymmetricTypeSubtag& result)
2275     {
2276         uint8_t tag;
2277         if (!read(tag))
2278             return false;
2279         if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
2280             return false;
2281         result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
2282         return true;
2283     }
2284
2285     bool readHMACKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2286     {
2287         Vector<uint8_t> keyData;
2288         if (!read(keyData))
2289             return false;
2290         CryptoAlgorithmIdentifier hash;
2291         if (!read(hash))
2292             return false;
2293         result = CryptoKeyHMAC::importRaw(0, hash, WTFMove(keyData), extractable, usages);
2294         return true;
2295     }
2296
2297     bool readAESKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2298     {
2299         CryptoAlgorithmIdentifier algorithm;
2300         if (!read(algorithm))
2301             return false;
2302         if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
2303             return false;
2304         Vector<uint8_t> keyData;
2305         if (!read(keyData))
2306             return false;
2307         result = CryptoKeyAES::importRaw(algorithm, WTFMove(keyData), extractable, usages);
2308         return true;
2309     }
2310
2311     bool readRSAKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2312     {
2313         CryptoAlgorithmIdentifier algorithm;
2314         if (!read(algorithm))
2315             return false;
2316
2317         int32_t isRestrictedToHash;
2318         CryptoAlgorithmIdentifier hash;
2319         if (!read(isRestrictedToHash))
2320             return false;
2321         if (isRestrictedToHash && !read(hash))
2322             return false;
2323
2324         CryptoKeyAsymmetricTypeSubtag type;
2325         if (!read(type))
2326             return false;
2327
2328         Vector<uint8_t> modulus;
2329         if (!read(modulus))
2330             return false;
2331         Vector<uint8_t> exponent;
2332         if (!read(exponent))
2333             return false;
2334
2335         if (type == CryptoKeyAsymmetricTypeSubtag::Public) {
2336             auto keyData = CryptoKeyRSAComponents::createPublic(modulus, exponent);
2337             auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2338             result = WTFMove(key);
2339             return true;
2340         }
2341
2342         Vector<uint8_t> privateExponent;
2343         if (!read(privateExponent))
2344             return false;
2345
2346         uint32_t primeCount;
2347         if (!read(primeCount))
2348             return false;
2349
2350         if (!primeCount) {
2351             auto keyData = CryptoKeyRSAComponents::createPrivate(modulus, exponent, privateExponent);
2352             auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2353             result = WTFMove(key);
2354             return true;
2355         }
2356
2357         if (primeCount < 2)
2358             return false;
2359
2360         CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
2361         CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
2362         Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
2363
2364         if (!read(firstPrimeInfo.primeFactor))
2365             return false;
2366         if (!read(firstPrimeInfo.factorCRTExponent))
2367             return false;
2368         if (!read(secondPrimeInfo.primeFactor))
2369             return false;
2370         if (!read(secondPrimeInfo.factorCRTExponent))
2371             return false;
2372         if (!read(secondPrimeInfo.factorCRTCoefficient))
2373             return false;
2374         for (unsigned i = 2; i < primeCount; ++i) {
2375             if (!read(otherPrimeInfos[i].primeFactor))
2376                 return false;
2377             if (!read(otherPrimeInfos[i].factorCRTExponent))
2378                 return false;
2379             if (!read(otherPrimeInfos[i].factorCRTCoefficient))
2380                 return false;
2381         }
2382
2383         auto keyData = CryptoKeyRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
2384         auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2385         result = WTFMove(key);
2386         return true;
2387     }
2388
2389     bool readECKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2390     {
2391         CryptoAlgorithmIdentifier algorithm;
2392         if (!read(algorithm))
2393             return false;
2394         if (!CryptoKeyEC::isValidECAlgorithm(algorithm))
2395             return false;
2396         CachedStringRef curve;
2397         if (!readStringData(curve))
2398             return false;
2399         CryptoKeyAsymmetricTypeSubtag type;
2400         if (!read(type))
2401             return false;
2402         Vector<uint8_t> keyData;
2403         if (!read(keyData))
2404             return false;
2405
2406         switch (type) {
2407         case CryptoKeyAsymmetricTypeSubtag::Public:
2408             result = CryptoKeyEC::importRaw(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2409             break;
2410         case CryptoKeyAsymmetricTypeSubtag::Private:
2411             result = CryptoKeyEC::importPkcs8(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2412             break;
2413         }
2414
2415         return true;
2416     }
2417
2418     bool readRawKey(CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2419     {
2420         CryptoAlgorithmIdentifier algorithm;
2421         if (!read(algorithm))
2422             return false;
2423         Vector<uint8_t> keyData;
2424         if (!read(keyData))
2425             return false;
2426         result = CryptoKeyRaw::create(algorithm, WTFMove(keyData), usages);
2427         return true;
2428     }
2429
2430     bool readCryptoKey(JSValue& cryptoKey)
2431     {
2432         uint32_t keyFormatVersion;
2433         if (!read(keyFormatVersion) || keyFormatVersion > currentKeyFormatVersion)
2434             return false;
2435
2436         int32_t extractable;
2437         if (!read(extractable))
2438             return false;
2439
2440         uint32_t usagesCount;
2441         if (!read(usagesCount))
2442             return false;
2443
2444         CryptoKeyUsageBitmap usages = 0;
2445         for (uint32_t i = 0; i < usagesCount; ++i) {
2446             CryptoKeyUsageTag usage;
2447             if (!read(usage))
2448                 return false;
2449             switch (usage) {
2450             case CryptoKeyUsageTag::Encrypt:
2451                 usages |= CryptoKeyUsageEncrypt;
2452                 break;
2453             case CryptoKeyUsageTag::Decrypt:
2454                 usages |= CryptoKeyUsageDecrypt;
2455                 break;
2456             case CryptoKeyUsageTag::Sign:
2457                 usages |= CryptoKeyUsageSign;
2458                 break;
2459             case CryptoKeyUsageTag::Verify:
2460                 usages |= CryptoKeyUsageVerify;
2461                 break;
2462             case CryptoKeyUsageTag::DeriveKey:
2463                 usages |= CryptoKeyUsageDeriveKey;
2464                 break;
2465             case CryptoKeyUsageTag::DeriveBits:
2466                 usages |= CryptoKeyUsageDeriveBits;
2467                 break;
2468             case CryptoKeyUsageTag::WrapKey:
2469                 usages |= CryptoKeyUsageWrapKey;
2470                 break;
2471             case CryptoKeyUsageTag::UnwrapKey:
2472                 usages |= CryptoKeyUsageUnwrapKey;
2473                 break;
2474             }
2475         }
2476
2477         CryptoKeyClassSubtag cryptoKeyClass;
2478         if (!read(cryptoKeyClass))
2479             return false;
2480         RefPtr<CryptoKey> result;
2481         switch (cryptoKeyClass) {
2482         case CryptoKeyClassSubtag::HMAC:
2483             if (!readHMACKey(extractable, usages, result))
2484                 return false;
2485             break;
2486         case CryptoKeyClassSubtag::AES:
2487             if (!readAESKey(extractable, usages, result))
2488                 return false;
2489             break;
2490         case CryptoKeyClassSubtag::RSA:
2491             if (!readRSAKey(extractable, usages, result))
2492                 return false;
2493             break;
2494         case CryptoKeyClassSubtag::EC:
2495             if (!readECKey(extractable, usages, result))
2496                 return false;
2497             break;
2498         case CryptoKeyClassSubtag::Raw:
2499             if (!readRawKey(usages, result))
2500                 return false;
2501             break;
2502         }
2503         cryptoKey = getJSValue(result.get());
2504         return true;
2505     }
2506 #endif
2507
2508     template<class T>
2509     JSValue getJSValue(T* nativeObj)
2510     {
2511         return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2512     }
2513
2514     template<class T>
2515     JSValue getJSValue(T& nativeObj)
2516     {
2517         return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2518     }
2519
2520     template<class T>
2521     JSValue readDOMPoint()
2522     {
2523         double x;
2524         if (!read(x))
2525             return { };
2526         double y;
2527         if (!read(y))
2528             return { };
2529         double z;
2530         if (!read(z))
2531             return { };
2532         double w;
2533         if (!read(w))
2534             return { };
2535
2536         return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, z, w));
2537     }
2538
2539     template<class T>
2540     JSValue readDOMMatrix()
2541     {
2542         uint8_t is2D;
2543         if (!read(is2D))
2544             return { };
2545
2546         if (is2D) {
2547             double m11;
2548             if (!read(m11))
2549                 return { };
2550             double m12;
2551             if (!read(m12))
2552                 return { };
2553             double m21;
2554             if (!read(m21))
2555                 return { };
2556             double m22;
2557             if (!read(m22))
2558                 return { };
2559             double m41;
2560             if (!read(m41))
2561                 return { };
2562             double m42;
2563             if (!read(m42))
2564                 return { };
2565
2566             TransformationMatrix matrix(m11, m12, m21, m22, m41, m42);
2567             return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::Yes));
2568         } else {
2569             double m11;
2570             if (!read(m11))
2571                 return { };
2572             double m12;
2573             if (!read(m12))
2574                 return { };
2575             double m13;
2576             if (!read(m13))
2577                 return { };
2578             double m14;
2579             if (!read(m14))
2580                 return { };
2581             double m21;
2582             if (!read(m21))
2583                 return { };
2584             double m22;
2585             if (!read(m22))
2586                 return { };
2587             double m23;
2588             if (!read(m23))
2589                 return { };
2590             double m24;
2591             if (!read(m24))
2592                 return { };
2593             double m31;
2594             if (!read(m31))
2595                 return { };
2596             double m32;
2597             if (!read(m32))
2598                 return { };
2599             double m33;
2600             if (!read(m33))
2601                 return { };
2602             double m34;
2603             if (!read(m34))
2604                 return { };
2605             double m41;
2606             if (!read(m41))
2607                 return { };
2608             double m42;
2609             if (!read(m42))
2610                 return { };
2611             double m43;
2612             if (!read(m43))
2613                 return { };
2614             double m44;
2615             if (!read(m44))
2616                 return { };
2617
2618             TransformationMatrix matrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
2619             return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::No));
2620         }
2621     }
2622
2623     template<class T>
2624     JSValue readDOMRect()
2625     {
2626         double x;
2627         if (!read(x))
2628             return { };
2629         double y;
2630         if (!read(y))
2631             return { };
2632         double width;
2633         if (!read(width))
2634             return { };
2635         double height;
2636         if (!read(height))
2637             return { };
2638
2639         return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, width, height));
2640     }
2641
2642     Optional<DOMPointInit> readDOMPointInit()
2643     {
2644         DOMPointInit point;
2645         if (!read(point.x))
2646             return WTF::nullopt;
2647         if (!read(point.y))
2648             return WTF::nullopt;
2649         if (!read(point.z))
2650             return WTF::nullopt;
2651         if (!read(point.w))
2652             return WTF::nullopt;
2653
2654         return point;
2655     }
2656
2657     JSValue readDOMQuad()
2658     {
2659         auto p1 = readDOMPointInit();
2660         if (!p1)
2661             return JSValue();
2662         auto p2 = readDOMPointInit();
2663         if (!p2)
2664             return JSValue();
2665         auto p3 = readDOMPointInit();
2666         if (!p3)
2667             return JSValue();
2668         auto p4 = readDOMPointInit();
2669         if (!p4)
2670             return JSValue();
2671
2672         return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), DOMQuad::create(p1.value(), p2.value(), p3.value(), p4.value()));
2673     }
2674
2675     JSValue readImageBitmap()
2676     {
2677         uint32_t index;
2678         bool indexSuccessfullyRead = read(index);
2679         if (!indexSuccessfullyRead || index >= m_imageBuffers.size()) {
2680             fail();
2681             return JSValue();
2682         }
2683
2684         if (!m_imageBitmaps[index])
2685             m_imageBitmaps[index] = ImageBitmap::create(WTFMove(m_imageBuffers.at(index)));
2686
2687         auto bitmap = m_imageBitmaps[index].get();
2688         return getJSValue(bitmap);
2689     }
2690
2691 #if ENABLE(WEB_RTC)
2692     JSValue readRTCCertificate()
2693     {
2694         double expires;
2695         if (!read(expires)) {
2696             fail();
2697             return JSValue();
2698         }
2699         CachedStringRef certificate;
2700         if (!readStringData(certificate)) {
2701             fail();
2702             return JSValue();
2703         }
2704         CachedStringRef origin;
2705         if (!readStringData(origin)) {
2706             fail();
2707             return JSValue();
2708         }
2709         CachedStringRef keyedMaterial;
2710         if (!readStringData(keyedMaterial)) {
2711             fail();
2712             return JSValue();
2713         }
2714         unsigned size = 0;
2715         if (!read(size))
2716             return JSValue();
2717
2718         Vector<RTCCertificate::DtlsFingerprint> fingerprints;
2719         fingerprints.reserveInitialCapacity(size);
2720         for (unsigned i = 0; i < size; i++) {
2721             CachedStringRef algorithm;
2722             if (!readStringData(algorithm))
2723                 return JSValue();
2724             CachedStringRef value;
2725             if (!readStringData(value))
2726                 return JSValue();
2727             fingerprints.uncheckedAppend(RTCCertificate::DtlsFingerprint { algorithm->string(), value->string() });
2728         }
2729
2730         if (!m_isDOMGlobalObject)
2731             return constructEmptyObject(m_exec, m_globalObject->objectPrototype());
2732
2733         auto rtcCertificate = RTCCertificate::create(SecurityOrigin::createFromString(origin->string()), expires, WTFMove(fingerprints), certificate->takeString(), keyedMaterial->takeString());
2734         return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), WTFMove(rtcCertificate));
2735     }
2736 #endif
2737
2738     JSValue readTerminal()
2739     {
2740         SerializationTag tag = readTag();
2741         switch (tag) {
2742         case UndefinedTag:
2743             return jsUndefined();
2744         case NullTag:
2745             return jsNull();
2746         case IntTag: {
2747             int32_t i;
2748             if (!read(i))
2749                 return JSValue();
2750             return jsNumber(i);
2751         }
2752         case ZeroTag:
2753             return jsNumber(0);
2754         case OneTag:
2755             return jsNumber(1);
2756         case FalseTag:
2757             return jsBoolean(false);
2758         case TrueTag:
2759             return jsBoolean(true);
2760         case FalseObjectTag: {
2761             BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2762             obj->setInternalValue(m_exec->vm(), jsBoolean(false));
2763             m_gcBuffer.appendWithCrashOnOverflow(obj);
2764             return obj;
2765         }
2766         case TrueObjectTag: {
2767             BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2768             obj->setInternalValue(m_exec->vm(), jsBoolean(true));
2769             m_gcBuffer.appendWithCrashOnOverflow(obj);
2770             return obj;
2771         }
2772         case DoubleTag: {
2773             double d;
2774             if (!read(d))
2775                 return JSValue();
2776             return jsNumber(d);
2777         }
2778         case NumberObjectTag: {
2779             double d;
2780             if (!read(d))
2781                 return JSValue();
2782             NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
2783             m_gcBuffer.appendWithCrashOnOverflow(obj);
2784             return obj;
2785         }
2786         case DateTag: {
2787             double d;
2788             if (!read(d))
2789                 return JSValue();
2790             return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
2791         }
2792         case FileTag: {
2793             RefPtr<File> file;
2794             if (!readFile(file))
2795                 return JSValue();
2796             if (!m_isDOMGlobalObject)
2797                 return jsNull();
2798             return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
2799         }
2800         case FileListTag: {
2801             unsigned length = 0;
2802             if (!read(length))
2803                 return JSValue();
2804             Vector<Ref<File>> files;
2805             for (unsigned i = 0; i < length; i++) {
2806                 RefPtr<File> file;
2807                 if (!readFile(file))
2808                     return JSValue();
2809                 if (m_isDOMGlobalObject)
2810                     files.append(file.releaseNonNull());
2811             }
2812             if (!m_isDOMGlobalObject)
2813                 return jsNull();
2814             return getJSValue(FileList::create(WTFMove(files)).get());
2815         }
2816         case ImageDataTag: {
2817             uint32_t width;
2818             if (!read(width))
2819                 return JSValue();
2820             uint32_t height;
2821             if (!read(height))
2822                 return JSValue();
2823             uint32_t length;
2824             if (!read(length))
2825                 return JSValue();
2826             if (static_cast<uint32_t>(m_end - m_ptr) < length) {
2827                 fail();
2828                 return JSValue();
2829             }
2830             if (!m_isDOMGlobalObject) {
2831                 m_ptr += length;
2832                 return jsNull();
2833             }
2834             IntSize imageSize(width, height);
2835             RELEASE_ASSERT(!length || (imageSize.area() * 4).unsafeGet() <= length);
2836             auto result = ImageData::create(imageSize);
2837             if (!result) {
2838                 fail();
2839                 return JSValue();
2840             }
2841             if (length)
2842                 memcpy(result->data()->data(), m_ptr, length);
2843             else
2844                 result->data()->zeroFill();
2845             m_ptr += length;
2846             return getJSValue(result.get());
2847         }
2848         case BlobTag: {
2849             CachedStringRef url;
2850             if (!readStringData(url))
2851                 return JSValue();
2852             CachedStringRef type;
2853             if (!readStringData(type))
2854                 return JSValue();
2855             unsigned long long size = 0;
2856             if (!read(size))
2857                 return JSValue();
2858             if (!m_isDOMGlobalObject)
2859                 return jsNull();
2860             return getJSValue(Blob::deserialize(URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get());
2861         }
2862         case StringTag: {
2863             CachedStringRef cachedString;
2864             if (!readStringData(cachedString))
2865                 return JSValue();
2866             return cachedString->jsString(m_exec);
2867         }
2868         case EmptyStringTag:
2869             return jsEmptyString(m_exec->vm());
2870         case StringObjectTag: {
2871             CachedStringRef cachedString;
2872             if (!readStringData(cachedString))
2873                 return JSValue();
2874             StringObject* obj = constructString(m_exec->vm(), m_globalObject, cachedString->jsString(m_exec));
2875             m_gcBuffer.appendWithCrashOnOverflow(obj);
2876             return obj;
2877         }
2878         case EmptyStringObjectTag: {
2879             VM& vm = m_exec->vm();
2880             StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(vm));
2881             m_gcBuffer.appendWithCrashOnOverflow(obj);
2882             return obj;
2883         }
2884         case RegExpTag: {
2885             CachedStringRef pattern;
2886             if (!readStringData(pattern))
2887                 return JSValue();
2888             CachedStringRef flags;
2889             if (!readStringData(flags))
2890                 return JSValue();
2891             auto reFlags = Yarr::parseFlags(flags->string());
2892             ASSERT(reFlags.hasValue());
2893             VM& vm = m_exec->vm();
2894             RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
2895             return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
2896         }
2897         case ObjectReferenceTag: {
2898             unsigned index = 0;
2899             if (!readConstantPoolIndex(m_gcBuffer, index)) {
2900                 fail();
2901                 return JSValue();
2902             }
2903             return m_gcBuffer.at(index);
2904         }
2905         case MessagePortReferenceTag: {
2906             uint32_t index;
2907             bool indexSuccessfullyRead = read(index);
2908             if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
2909                 fail();
2910                 return JSValue();
2911             }
2912             return getJSValue(m_messagePorts[index].get());
2913         }
2914 #if ENABLE(WEBASSEMBLY)
2915         case WasmModuleTag: {
2916             uint32_t index;
2917             bool indexSuccessfullyRead = read(index);
2918             if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) {
2919                 fail();
2920                 return JSValue();
2921             }
2922             auto scope = DECLARE_THROW_SCOPE(m_exec->vm());
2923             JSValue result = JSC::JSWebAssemblyModule::createStub(m_exec->vm(), m_exec, m_globalObject->webAssemblyModuleStructure(), m_wasmModules->at(index));
2924             // Since we are cloning a JSWebAssemblyModule, it's impossible for that
2925             // module to not have been a valid module. Therefore, createStub should
2926             // not trow.
2927             scope.releaseAssertNoException();
2928             m_gcBuffer.appendWithCrashOnOverflow(result);
2929             return result;
2930         }
2931 #endif
2932         case ArrayBufferTag: {
2933             RefPtr<ArrayBuffer> arrayBuffer;
2934             if (!readArrayBuffer(arrayBuffer)) {
2935                 fail();
2936                 return JSValue();
2937             }
2938             Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
2939             // A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
2940             // array buffers while the sender is. In that case, we would see a null structure here.
2941             if (!structure) {
2942                 fail();
2943                 return JSValue();
2944             }
2945             JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer));
2946             m_gcBuffer.appendWithCrashOnOverflow(result);
2947             return result;
2948         }
2949         case ArrayBufferTransferTag: {
2950             uint32_t index;
2951             bool indexSuccessfullyRead = read(index);
2952             if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
2953                 fail();
2954                 return JSValue();
2955             }
2956
2957             if (!m_arrayBuffers[index])
2958                 m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
2959
2960             return getJSValue(m_arrayBuffers[index].get());
2961         }
2962         case SharedArrayBufferTag: {
2963             uint32_t index = UINT_MAX;
2964             bool indexSuccessfullyRead = read(index);
2965             if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) {
2966                 fail();
2967                 return JSValue();
2968             }
2969             
2970             RELEASE_ASSERT(m_sharedBuffers->at(index));
2971             auto buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index)));
2972             JSValue result = getJSValue(buffer.get());
2973             m_gcBuffer.appendWithCrashOnOverflow(result);
2974             return result;
2975         }
2976         case ArrayBufferViewTag: {
2977             JSValue arrayBufferView;
2978             if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) {
2979                 fail();
2980                 return JSValue();
2981             }
2982             m_gcBuffer.appendWithCrashOnOverflow(arrayBufferView);
2983             return arrayBufferView;
2984         }
2985 #if ENABLE(WEB_CRYPTO)
2986         case CryptoKeyTag: {
2987             Vector<uint8_t> wrappedKey;
2988             if (!read(wrappedKey)) {
2989                 fail();
2990                 return JSValue();
2991             }
2992             Vector<uint8_t> serializedKey;
2993             if (!unwrapCryptoKey(m_exec, wrappedKey, serializedKey)) {
2994                 fail();
2995                 return JSValue();
2996             }
2997             JSValue cryptoKey;
2998             Vector<RefPtr<MessagePort>> dummyMessagePorts;
2999             CloneDeserializer rawKeyDeserializer(m_exec, m_globalObject, dummyMessagePorts, nullptr, { },
3000 #if ENABLE(WEBASSEMBLY)
3001                 nullptr,
3002 #endif
3003                 serializedKey);
3004             if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
3005                 fail();
3006                 return JSValue();
3007             }
3008             m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
3009             return cryptoKey;
3010         }
3011 #endif
3012         case DOMPointReadOnlyTag:
3013             return readDOMPoint<DOMPointReadOnly>();
3014         case DOMPointTag:
3015             return readDOMPoint<DOMPoint>();
3016         case DOMRectReadOnlyTag:
3017             return readDOMRect<DOMRectReadOnly>();
3018         case DOMRectTag:
3019             return readDOMRect<DOMRect>();
3020         case DOMMatrixReadOnlyTag:
3021             return readDOMMatrix<DOMMatrixReadOnly>();
3022         case DOMMatrixTag:
3023             return readDOMMatrix<DOMMatrix>();
3024         case DOMQuadTag:
3025             return readDOMQuad();
3026         case ImageBitmapTransferTag:
3027             return readImageBitmap();
3028 #if ENABLE(WEB_RTC)
3029         case RTCCertificateTag:
3030             return readRTCCertificate();
3031
3032 #endif
3033         default:
3034             m_ptr--; // Push the tag back
3035             return JSValue();
3036         }
3037     }
3038
3039     template<SerializationTag Tag>
3040     bool consumeCollectionDataTerminationIfPossible()
3041     {
3042         if (readTag() == Tag)
3043             return true;
3044         m_ptr--;
3045         return false;
3046     }
3047
3048     JSGlobalObject* m_globalObject;
3049     bool m_isDOMGlobalObject;
3050     const uint8_t* m_ptr;
3051     const uint8_t* m_end;
3052     unsigned m_version;
3053     Vector<CachedString> m_constantPool;
3054     const Vector<RefPtr<MessagePort>>& m_messagePorts;
3055     ArrayBufferContentsArray* m_arrayBufferContents;
3056     Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers;
3057     Vector<String> m_blobURLs;
3058     Vector<String> m_blobFilePaths;
3059     ArrayBufferContentsArray* m_sharedBuffers;
3060     Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>> m_imageBuffers;
3061     Vector<RefPtr<ImageBitmap>> m_imageBitmaps;
3062 #if ENABLE(WEBASSEMBLY)
3063     WasmModuleArray* m_wasmModules;
3064 #endif
3065
3066     String blobFilePathForBlobURL(const String& blobURL)
3067     {
3068         size_t i = 0;
3069         for (; i < m_blobURLs.size(); ++i) {
3070             if (m_blobURLs[i] == blobURL)
3071                 break;
3072         }
3073
3074         return i < m_blobURLs.size() ? m_blobFilePaths[i] : String();
3075     }
3076 };
3077
3078 DeserializationResult CloneDeserializer::deserialize()
3079 {
3080     VM& vm = m_exec->vm();
3081     auto scope = DECLARE_THROW_SCOPE(vm);
3082
3083     Vector<uint32_t, 16> indexStack;
3084     Vector<Identifier, 16> propertyNameStack;
3085     Vector<JSObject*, 32> outputObjectStack;
3086     Vector<JSValue, 4> mapKeyStack;
3087     Vector<JSMap*, 4> mapStack;
3088     Vector<JSSet*, 4> setStack;
3089     Vector<WalkerState, 16> stateStack;
3090     WalkerState state = StateUnknown;
3091     JSValue outValue;
3092
3093     while (1) {
3094         switch (state) {
3095         arrayStartState:
3096         case ArrayStartState: {
3097             uint32_t length;
3098             if (!read(length)) {
3099                 fail();
3100                 goto error;
3101             }
3102             JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
3103             if (UNLIKELY(scope.exception()))
3104                 goto error;
3105             m_gcBuffer.appendWithCrashOnOverflow(outArray);
3106             outputObjectStack.append(outArray);
3107         }
3108         arrayStartVisitMember:
3109         FALLTHROUGH;
3110         case ArrayStartVisitMember: {
3111             uint32_t index;
3112             if (!read(index)) {
3113                 fail();
3114                 goto error;
3115             }
3116             if (index == TerminatorTag) {
3117                 JSObject* outArray = outputObjectStack.last();
3118                 outValue = outArray;
3119                 outputObjectStack.removeLast();
3120                 break;
3121             } else if (index == NonIndexPropertiesTag) {
3122                 goto objectStartVisitMember;
3123             }
3124
3125             if (JSValue terminal = readTerminal()) {
3126                 putProperty(outputObjectStack.last(), index, terminal);
3127                 goto arrayStartVisitMember;
3128             }
3129             if (m_failed)
3130                 goto error;
3131             indexStack.append(index);
3132             stateStack.append(ArrayEndVisitMember);
3133             goto stateUnknown;
3134         }
3135         case ArrayEndVisitMember: {
3136             JSObject* outArray = outputObjectStack.last();
3137             putProperty(outArray, indexStack.last(), outValue);
3138             indexStack.removeLast();
3139             goto arrayStartVisitMember;
3140         }
3141         objectStartState:
3142         case ObjectStartState: {
3143             if (outputObjectStack.size() > maximumFilterRecursion)
3144                 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3145             JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
3146             m_gcBuffer.appendWithCrashOnOverflow(outObject);
3147             outputObjectStack.append(outObject);
3148         }
3149         objectStartVisitMember:
3150         FALLTHROUGH;
3151         case ObjectStartVisitMember: {
3152             CachedStringRef cachedString;
3153             bool wasTerminator = false;
3154             if (!readStringData(cachedString, wasTerminator)) {
3155                 if (!wasTerminator)
3156                     goto error;
3157
3158                 JSObject* outObject = outputObjectStack.last();
3159                 outValue = outObject;
3160                 outputObjectStack.removeLast();
3161                 break;
3162             }
3163
3164             if (JSValue terminal = readTerminal()) {
3165                 putProperty(outputObjectStack.last(), Identifier::fromString(vm, cachedString->string()), terminal);
3166                 goto objectStartVisitMember;
3167             }
3168             stateStack.append(ObjectEndVisitMember);
3169             propertyNameStack.append(Identifier::fromString(vm, cachedString->string()));
3170             goto stateUnknown;
3171         }
3172         case ObjectEndVisitMember: {
3173             putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
3174             propertyNameStack.removeLast();
3175             goto objectStartVisitMember;
3176         }
3177         mapObjectStartState: {
3178             if (outputObjectStack.size() > maximumFilterRecursion)
3179                 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3180             JSMap* map = JSMap::create(m_exec, m_exec->vm(), m_globalObject->mapStructure());
3181             if (UNLIKELY(scope.exception()))
3182                 goto error;
3183             m_gcBuffer.appendWithCrashOnOverflow(map);
3184             outputObjectStack.append(map);
3185             mapStack.append(map);
3186             goto mapDataStartVisitEntry;
3187         }
3188         mapDataStartVisitEntry:
3189         case MapDataStartVisitEntry: {
3190             if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) {
3191                 mapStack.removeLast();