2 * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "SerializedScriptValue.h"
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"
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"
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>
85 #include <wtf/CompletionHandler.h>
86 #include <wtf/MainThread.h>
87 #include <wtf/RunLoop.h>
88 #include <wtf/Vector.h>
90 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
91 #define ASSUME_LITTLE_ENDIAN 0
93 #define ASSUME_LITTLE_ENDIAN 1
99 static const unsigned maximumFilterRecursion = 40000;
101 enum class SerializationReturnCode {
102 SuccessfullyCompleted,
104 InterruptedExecutionError,
106 ExistingExceptionError,
111 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
112 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
113 MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue,
114 SetDataStartVisitEntry, SetDataEndVisitKey };
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 {
137 ObjectReferenceTag = 19,
138 MessagePortReferenceTag = 20,
140 ArrayBufferViewTag = 22,
141 ArrayBufferTransferTag = 23,
144 StringObjectTag = 26,
145 EmptyStringObjectTag = 27,
146 NumberObjectTag = 28,
149 NonMapPropertiesTag = 31,
150 NonSetPropertiesTag = 32,
151 #if ENABLE(WEB_CRYPTO)
154 SharedArrayBufferTag = 34,
155 #if ENABLE(WEBASSEMBLY)
158 DOMPointReadOnlyTag = 36,
160 DOMRectReadOnlyTag = 38,
162 DOMMatrixReadOnlyTag = 40,
165 ImageBitmapTransferTag = 43,
167 RTCCertificateTag = 44,
172 enum ArrayBufferViewSubtag {
176 Uint8ClampedArrayTag = 3,
185 static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
191 case Uint8ClampedArrayTag:
198 case Float32ArrayTag:
200 case Float64ArrayTag:
208 #if ENABLE(WEB_CRYPTO)
210 const uint32_t currentKeyFormatVersion = 1;
212 enum class CryptoKeyClassSubtag {
219 const uint8_t cryptoKeyClassSubtagMaximumValue = 4;
221 enum class CryptoKeyAsymmetricTypeSubtag {
225 const uint8_t cryptoKeyAsymmetricTypeSubtagMaximumValue = 1;
227 enum class CryptoKeyUsageTag {
237 const uint8_t cryptoKeyUsageTagMaximumValue = 7;
239 enum class CryptoAlgorithmIdentifierTag {
240 RSAES_PKCS1_v1_5 = 0,
241 RSASSA_PKCS1_v1_5 = 1,
260 const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21;
262 static unsigned countUsages(CryptoKeyUsageBitmap usages)
264 // Fast bit count algorithm for sparse bit maps.
267 usages = usages & (usages - 1);
275 /* CurrentVersion tracks the serialization version so that persistent stores
276 * are able to correctly bail out in the case of encountering newer formats.
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.
287 static const unsigned CurrentVersion = 7;
288 static const unsigned TerminatorTag = 0xFFFFFFFF;
289 static const unsigned StringPoolTag = 0xFFFFFFFE;
290 static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
292 // The high bit of a StringData's length determines the character size.
293 static const unsigned StringDataIs8BitFlag = 0x80000000;
296 * Object serialization is performed according to the following grammar, all tags
297 * are recorded as a single uint8_t.
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.
303 * SerializedValue :- <CurrentVersion:uint32_t> Value
304 * Value :- Array | Object | Map | Set | Terminal
307 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
310 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
312 * Map :- MapObjectTag MapData
314 * Set :- SetObjectTag SetData
316 * MapData :- (<key:Value><value:Value>)* NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
317 * SetData :- (<key:Value>)* NonSetPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
322 * | IntTag <value:int32_t>
329 * | DoubleTag <value:double>
330 * | NumberObjectTag <value:double>
331 * | DateTag <value:double>
334 * | EmptyStringObjectTag
340 * | MessagePortReferenceTag <value:uint32_t>
342 * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference)
343 * | ArrayBufferTransferTag <value:uint32_t>
344 * | CryptoKeyTag <wrappedKeyLength:uint32_t> <factor:byte{wrappedKeyLength}>
349 * | ImageBitmapTransferTag <value:uint32_t>
350 * | RTCCertificateTag
352 * Inside certificate, data is serialized in this format as per spec:
354 * <expires:double> <certificate:StringData> <origin:StringData> <keyingMaterial:StringData>
355 * We also add fingerprints to make sure we expose to JavaScript the same information.
357 * Inside wrapped crypto key, data is serialized in this format:
359 * <keyFormatVersion:uint32_t> <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA)
363 * StringTag StringData
366 * EmptyStringObjectTag
367 * StringObjectTag 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
377 * <path:StringData> <url:StringData> <type:StringData> <name:StringData> <lastModified:double>
380 * FileListTag <length:uint32_t>(<file:FileData>){length}
383 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
386 * BlobTag <url:StringData><type:StringData><size:long long>
389 * RegExpTag <pattern:StringData><flags:StringData>
392 * ObjectReferenceTag <opIndex:IndexType>
395 * ArrayBufferTag <length:uint32_t> <contents:byte{length}>
398 * <keySize:uint32_t> <keyData:byte{keySize}> CryptoAlgorithmIdentifierTag // Algorithm tag inner hash function.
401 * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
404 * CryptoAlgorithmIdentifierTag <isRestrictedToHash:int32_t> CryptoAlgorithmIdentifierTag? CryptoKeyAsymmetricTypeSubtag CryptoKeyRSAPublicComponents CryptoKeyRSAPrivateComponents?
406 * CryptoKeyRSAPublicComponents :-
407 * <modulusSize:uint32_t> <modulus:byte{modulusSize}> <exponentSize:uint32_t> <exponent:byte{exponentSize}>
409 * CryptoKeyRSAPrivateComponents :-
410 * <privateExponentSize:uint32_t> <privateExponent:byte{privateExponentSize}> <primeCount:uint32_t> FirstPrimeInfo? PrimeInfo{primeCount - 1}
412 * // CRT data could be computed from prime factors. It is only serialized to reuse a code path that's needed for JWK.
414 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}>
417 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}>
420 * CryptoAlgorithmIdentifierTag <namedCurve:StringData> CryptoKeyAsymmetricTypeSubtag <keySize:uint32_t> <keyData:byte{keySize}>
423 * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
426 * DOMPointReadOnlyTag DOMPointData
427 * | DOMPointTag DOMPointData
430 * <x:double> <y:double> <z:double> <w:double>
433 * DOMRectReadOnlyTag DOMRectData
434 * | DOMRectTag DOMRectData
437 * <x:double> <y:double> <width:double> <height:double>
440 * DOMMatrixReadOnlyTag DOMMatrixData
441 * | DOMMatrixTag 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>
448 * DOMQuadTag DOMQuadData
451 * <p1:DOMPointData> <p2:DOMPointData> <p3:DOMPointData> <p4:DOMPointData>
455 using DeserializationResult = std::pair<JSC::JSValue, SerializationReturnCode>;
459 CloneBase(ExecState* exec)
465 bool shouldTerminate()
467 VM& vm = m_exec->vm();
468 auto scope = DECLARE_THROW_SCOPE(vm);
469 return scope.exception();
479 MarkedArgumentBuffer m_gcBuffer;
482 #if ENABLE(WEB_CRYPTO)
483 static bool wrapCryptoKey(ExecState* exec, const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey)
485 ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
486 if (!scriptExecutionContext)
488 return scriptExecutionContext->wrapCryptoKey(key, wrappedKey);
491 static bool unwrapCryptoKey(ExecState* exec, const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key)
493 ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec);
494 if (!scriptExecutionContext)
496 return scriptExecutionContext->unwrapCryptoKey(wrappedKey, key);
500 #if ASSUME_LITTLE_ENDIAN
501 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
503 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
506 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
508 for (unsigned i = 0; i < sizeof(T); i++) {
509 buffer.append(value & 0xFF);
515 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
517 buffer.append(value);
520 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
522 if (length > std::numeric_limits<uint32_t>::max() / sizeof(T))
525 #if ASSUME_LITTLE_ENDIAN
526 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
528 for (unsigned i = 0; i < length; i++) {
530 for (unsigned j = 0; j < sizeof(T); j++) {
531 buffer.append(static_cast<uint8_t>(value & 0xFF));
539 template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8_t* values, uint32_t length)
541 buffer.append(values, length);
545 class CloneSerializer : CloneBase {
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,
551 Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
553 CloneSerializer serializer(exec, messagePorts, arrayBuffers, imageBitmaps,
554 #if ENABLE(WEBASSEMBLY)
557 blobURLs, out, context, sharedBuffers);
558 return serializer.serialize(value);
561 static bool serialize(StringView string, Vector<uint8_t>& out)
563 writeLittleEndian(out, CurrentVersion);
564 if (string.isEmpty()) {
565 writeLittleEndian<uint8_t>(out, EmptyStringTag);
568 writeLittleEndian<uint8_t>(out, StringTag);
569 if (string.is8Bit()) {
570 writeLittleEndian(out, string.length() | StringDataIs8BitFlag);
571 return writeLittleEndian(out, string.characters8(), string.length());
573 writeLittleEndian(out, string.length());
574 return writeLittleEndian(out, string.characters16(), string.length());
578 typedef HashMap<JSObject*, uint32_t> ObjectPool;
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,
584 Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
587 , m_blobURLs(blobURLs)
588 , m_emptyIdentifier(Identifier::fromString(exec, emptyString()))
590 , m_sharedBuffers(sharedBuffers)
591 #if ENABLE(WEBASSEMBLY)
592 , m_wasmModules(wasmModules)
595 write(CurrentVersion);
596 fillTransferMap(messagePorts, m_transferredMessagePorts);
597 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
598 fillTransferMap(imageBitmaps, m_transferredImageBitmaps);
602 void fillTransferMap(const Vector<RefPtr<T>>& input, ObjectPool& result)
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))
615 SerializationReturnCode serialize(JSValue in);
617 bool isArray(VM& vm, JSValue value)
619 if (!value.isObject())
621 JSObject* object = asObject(value);
622 return object->inherits<JSArray>(vm);
625 bool isMap(VM& vm, JSValue value)
627 if (!value.isObject())
629 JSObject* object = asObject(value);
630 return object->inherits<JSMap>(vm);
632 bool isSet(VM& vm, JSValue value)
634 if (!value.isObject())
636 JSObject* object = asObject(value);
637 return object->inherits<JSSet>(vm);
640 bool checkForDuplicate(JSObject* object)
642 // Record object for graph reconstruction
643 ObjectPool::const_iterator found = m_objectPool.find(object);
645 // Handle duplicate references
646 if (found != m_objectPool.end()) {
647 write(ObjectReferenceTag);
648 ASSERT(found->value < m_objectPool.size());
649 writeObjectIndex(found->value);
656 void recordObject(JSObject* object)
658 m_objectPool.add(object, m_objectPool.size());
659 m_gcBuffer.appendWithCrashOnOverflow(object);
662 bool startObjectInternal(JSObject* object)
664 if (checkForDuplicate(object))
666 recordObject(object);
670 bool startObject(JSObject* object)
672 if (!startObjectInternal(object))
678 bool startArray(JSArray* array)
680 if (!startObjectInternal(array))
683 unsigned length = array->length();
689 bool startSet(JSSet* set)
691 if (!startObjectInternal(set))
698 bool startMap(JSMap* map)
700 if (!startObjectInternal(map))
709 write(TerminatorTag);
712 JSValue getProperty(VM& vm, JSObject* object, const Identifier& propertyName)
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);
720 void dumpImmediate(JSValue value)
724 else if (value.isUndefined())
726 else if (value.isNumber()) {
727 if (value.isInt32()) {
728 if (!value.asInt32())
730 else if (value.asInt32() == 1)
734 write(static_cast<uint32_t>(value.asInt32()));
738 write(value.asDouble());
740 } else if (value.isBoolean()) {
748 void dumpString(const String& string)
750 if (string.isEmpty())
751 write(EmptyStringTag);
758 void dumpStringObject(const String& string)
760 if (string.isEmpty())
761 write(EmptyStringObjectTag);
763 write(StringObjectTag);
768 JSC::JSValue toJSArrayBuffer(ArrayBuffer& arrayBuffer)
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);
775 if (auto* buffer = arrayBuffer.m_wrapper.get())
778 return JSC::JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(arrayBuffer.sharingMode()), &arrayBuffer);
781 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
783 VM& vm = m_exec->vm();
784 write(ArrayBufferViewTag);
785 if (obj->inherits<JSDataView>(vm))
787 else if (obj->inherits<JSUint8ClampedArray>(vm))
788 write(Uint8ClampedArrayTag);
789 else if (obj->inherits<JSInt8Array>(vm))
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);
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();
813 code = SerializationReturnCode::ValidationError;
817 return dumpIfTerminal(toJSArrayBuffer(*arrayBuffer), code);
820 void dumpDOMPoint(const DOMPointReadOnly& point)
828 void dumpDOMPoint(JSObject* obj)
830 VM& vm = m_exec->vm();
831 if (obj->inherits<JSDOMPoint>(vm))
834 write(DOMPointReadOnlyTag);
836 dumpDOMPoint(jsCast<JSDOMPointReadOnly*>(obj)->wrapped());
839 void dumpDOMRect(JSObject* obj)
841 VM& vm = m_exec->vm();
842 if (obj->inherits<JSDOMRect>(vm))
845 write(DOMRectReadOnlyTag);
847 auto& rect = jsCast<JSDOMRectReadOnly*>(obj)->wrapped();
851 write(rect.height());
854 void dumpDOMMatrix(JSObject* obj)
856 VM& vm = m_exec->vm();
857 if (obj->inherits<JSDOMMatrix>(vm))
860 write(DOMMatrixReadOnlyTag);
862 auto& matrix = jsCast<JSDOMMatrixReadOnly*>(obj)->wrapped();
863 bool is2D = matrix.is2D();
864 write(static_cast<uint8_t>(is2D));
892 void dumpDOMQuad(JSObject* obj)
896 auto& quad = jsCast<JSDOMQuad*>(obj)->wrapped();
897 dumpDOMPoint(quad.p1());
898 dumpDOMPoint(quad.p2());
899 dumpDOMPoint(quad.p3());
900 dumpDOMPoint(quad.p4());
903 void dumpImageBitmap(JSObject* obj, SerializationReturnCode& code)
905 auto index = m_transferredImageBitmaps.find(obj);
906 if (index != m_transferredImageBitmaps.end()) {
907 write(ImageBitmapTransferTag);
912 // Copying ImageBitmaps is not yet supported.
913 code = SerializationReturnCode::ValidationError;
916 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
918 if (!value.isCell()) {
919 dumpImmediate(value);
922 ASSERT(value.isCell());
924 if (value.isString()) {
925 dumpString(asString(value)->value(m_exec));
929 if (value.isSymbol()) {
930 code = SerializationReturnCode::DataCloneError;
934 VM& vm = m_exec->vm();
935 if (isArray(vm, value))
938 if (value.isObject()) {
939 auto* obj = asObject(value);
940 if (auto* dateObject = jsDynamicCast<DateInstance*>(vm, obj)) {
942 write(dateObject->internalNumber());
945 if (auto* booleanObject = jsDynamicCast<BooleanObject*>(vm, obj)) {
946 if (!startObjectInternal(booleanObject)) // handle duplicates
948 write(booleanObject->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
951 if (auto* stringObject = jsDynamicCast<StringObject*>(vm, obj)) {
952 if (!startObjectInternal(stringObject)) // handle duplicates
954 String str = asString(stringObject->internalValue())->value(m_exec);
955 dumpStringObject(str);
958 if (auto* numberObject = jsDynamicCast<NumberObject*>(vm, obj)) {
959 if (!startObjectInternal(numberObject)) // handle duplicates
961 write(NumberObjectTag);
962 write(numberObject->internalValue().asNumber());
965 if (auto* file = JSFile::toWrapped(vm, obj)) {
970 if (auto* list = JSFileList::toWrapped(vm, obj)) {
972 write(list->length());
973 for (auto& file : list->files())
977 if (auto* blob = JSBlob::toWrapped(vm, obj)) {
979 m_blobURLs.append(blob->url());
985 if (auto* data = JSImageData::toWrapped(vm, obj)) {
987 write(data->width());
988 write(data->height());
989 write(data->data()->length());
990 write(data->data()->data(), data->data()->length());
993 if (auto* regExp = jsDynamicCast<RegExpObject*>(vm, obj)) {
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';
1003 write(regExp->regExp()->pattern());
1004 write(String(flags, flagCount));
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);
1014 // MessagePort object could not be found in transferred message ports
1015 code = SerializationReturnCode::ValidationError;
1018 if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
1019 if (arrayBuffer->isNeutered()) {
1020 code = SerializationReturnCode::ValidationError;
1023 auto index = m_transferredArrayBuffers.find(obj);
1024 if (index != m_transferredArrayBuffers.end()) {
1025 write(ArrayBufferTransferTag);
1026 write(index->value);
1029 if (!startObjectInternal(obj)) // handle duplicates
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));
1043 write(ArrayBufferTag);
1044 write(arrayBuffer->byteLength());
1045 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
1048 if (obj->inherits<JSArrayBufferView>(vm)) {
1049 if (checkForDuplicate(obj))
1051 bool success = dumpArrayBufferView(obj, code);
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;
1065 ArrayBufferContentsArray dummySharedBuffers;
1066 CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, { },
1067 #if ENABLE(WEBASSEMBLY)
1070 dummyBlobURLs, serializedKey, SerializationContext::Default, dummySharedBuffers);
1071 rawKeySerializer.write(key);
1072 Vector<uint8_t> wrappedKey;
1073 if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey))
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);
1094 #if ENABLE(WEBASSEMBLY)
1095 if (JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, obj)) {
1096 if (m_context != SerializationContext::WorkerPostMessage && m_context != SerializationContext::WindowPostMessage)
1099 uint32_t index = m_wasmModules.size();
1100 m_wasmModules.append(makeRef(module->module()));
1101 write(WasmModuleTag);
1106 if (obj->inherits<JSDOMPointReadOnly>(vm)) {
1110 if (obj->inherits<JSDOMRectReadOnly>(vm)) {
1114 if (obj->inherits<JSDOMMatrixReadOnly>(vm)) {
1118 if (obj->inherits<JSDOMQuad>(vm)) {
1122 if (obj->inherits(vm, JSImageBitmap::info())) {
1123 dumpImageBitmap(obj, code);
1128 // Any other types are expected to serialize as null.
1133 void write(SerializationTag tag)
1135 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1138 void write(ArrayBufferViewSubtag tag)
1140 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1143 #if ENABLE(WEB_CRYPTO)
1144 void write(CryptoKeyClassSubtag tag)
1146 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1149 void write(CryptoKeyAsymmetricTypeSubtag tag)
1151 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1154 void write(CryptoKeyUsageTag tag)
1156 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1159 void write(CryptoAlgorithmIdentifierTag tag)
1161 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1165 void write(uint8_t c)
1167 writeLittleEndian(m_buffer, c);
1170 void write(uint32_t i)
1172 writeLittleEndian(m_buffer, i);
1175 void write(double d)
1182 writeLittleEndian(m_buffer, u.i);
1185 void write(int32_t i)
1187 writeLittleEndian(m_buffer, i);
1190 void write(unsigned long long i)
1192 writeLittleEndian(m_buffer, i);
1195 void write(uint16_t ch)
1197 writeLittleEndian(m_buffer, ch);
1200 void writeStringIndex(unsigned i)
1202 writeConstantPoolIndex(m_constantPool, i);
1205 void writeObjectIndex(unsigned i)
1207 writeConstantPoolIndex(m_objectPool, i);
1210 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
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));
1218 write(static_cast<uint32_t>(i));
1221 void write(const Identifier& ident)
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);
1231 unsigned length = str.length();
1233 // Guard against overflow
1234 if (length > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
1240 writeLittleEndian<uint32_t>(m_buffer, length | StringDataIs8BitFlag);
1242 writeLittleEndian<uint32_t>(m_buffer, length);
1247 if (!writeLittleEndian(m_buffer, str.characters8(), length))
1251 if (!writeLittleEndian(m_buffer, str.characters16(), length))
1255 void write(const String& str)
1258 write(m_emptyIdentifier);
1260 write(Identifier::fromString(m_exec, str));
1263 void write(const Vector<uint8_t>& vector)
1265 uint32_t size = vector.size();
1267 writeLittleEndian(m_buffer, vector.data(), size);
1270 void write(const File& file)
1272 m_blobURLs.append(file.url());
1277 write(static_cast<double>(file.lastModifiedOverride().valueOr(-1)));
1280 #if ENABLE(WEB_CRYPTO)
1281 void write(CryptoAlgorithmIdentifier algorithm)
1283 switch (algorithm) {
1284 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
1285 write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
1287 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
1288 write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
1290 case CryptoAlgorithmIdentifier::RSA_PSS:
1291 write(CryptoAlgorithmIdentifierTag::RSA_PSS);
1293 case CryptoAlgorithmIdentifier::RSA_OAEP:
1294 write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
1296 case CryptoAlgorithmIdentifier::ECDSA:
1297 write(CryptoAlgorithmIdentifierTag::ECDSA);
1299 case CryptoAlgorithmIdentifier::ECDH:
1300 write(CryptoAlgorithmIdentifierTag::ECDH);
1302 case CryptoAlgorithmIdentifier::AES_CTR:
1303 write(CryptoAlgorithmIdentifierTag::AES_CTR);
1305 case CryptoAlgorithmIdentifier::AES_CBC:
1306 write(CryptoAlgorithmIdentifierTag::AES_CBC);
1308 case CryptoAlgorithmIdentifier::AES_GCM:
1309 write(CryptoAlgorithmIdentifierTag::AES_GCM);
1311 case CryptoAlgorithmIdentifier::AES_CFB:
1312 write(CryptoAlgorithmIdentifierTag::AES_CFB);
1314 case CryptoAlgorithmIdentifier::AES_KW:
1315 write(CryptoAlgorithmIdentifierTag::AES_KW);
1317 case CryptoAlgorithmIdentifier::HMAC:
1318 write(CryptoAlgorithmIdentifierTag::HMAC);
1320 case CryptoAlgorithmIdentifier::SHA_1:
1321 write(CryptoAlgorithmIdentifierTag::SHA_1);
1323 case CryptoAlgorithmIdentifier::SHA_224:
1324 write(CryptoAlgorithmIdentifierTag::SHA_224);
1326 case CryptoAlgorithmIdentifier::SHA_256:
1327 write(CryptoAlgorithmIdentifierTag::SHA_256);
1329 case CryptoAlgorithmIdentifier::SHA_384:
1330 write(CryptoAlgorithmIdentifierTag::SHA_384);
1332 case CryptoAlgorithmIdentifier::SHA_512:
1333 write(CryptoAlgorithmIdentifierTag::SHA_512);
1335 case CryptoAlgorithmIdentifier::HKDF:
1336 write(CryptoAlgorithmIdentifierTag::HKDF);
1338 case CryptoAlgorithmIdentifier::PBKDF2:
1339 write(CryptoAlgorithmIdentifierTag::PBKDF2);
1344 void write(CryptoKeyRSAComponents::Type type)
1347 case CryptoKeyRSAComponents::Type::Public:
1348 write(CryptoKeyAsymmetricTypeSubtag::Public);
1350 case CryptoKeyRSAComponents::Type::Private:
1351 write(CryptoKeyAsymmetricTypeSubtag::Private);
1356 void write(const CryptoKeyRSAComponents& key)
1359 write(key.modulus());
1360 write(key.exponent());
1361 if (key.type() == CryptoKeyRSAComponents::Type::Public)
1364 write(key.privateExponent());
1366 unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
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);
1383 void write(const CryptoKey* key)
1385 write(currentKeyFormatVersion);
1387 write(key->extractable());
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);
1408 switch (key->keyClass()) {
1409 case CryptoKeyClass::HMAC:
1410 write(CryptoKeyClassSubtag::HMAC);
1411 write(downcast<CryptoKeyHMAC>(*key).key());
1412 write(downcast<CryptoKeyHMAC>(*key).hashAlgorithmIdentifier());
1414 case CryptoKeyClass::AES:
1415 write(CryptoKeyClassSubtag::AES);
1416 write(key->algorithmIdentifier());
1417 write(downcast<CryptoKeyAES>(*key).key());
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());
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());
1440 ASSERT_NOT_REACHED();
1443 case CryptoKeyClass::Raw:
1444 write(CryptoKeyClassSubtag::Raw);
1445 write(key->algorithmIdentifier());
1446 write(downcast<CryptoKeyRaw>(*key).key());
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)
1456 write(*downcast<CryptoKeyRSA>(*key).exportData());
1462 void write(const uint8_t* data, unsigned length)
1464 m_buffer.append(data, length);
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;
1483 SerializationReturnCode CloneSerializer::serialize(JSValue in)
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;
1499 case ArrayStartState: {
1500 ASSERT(isArray(vm, inValue));
1501 if (inputObjectStack.size() > maximumFilterRecursion)
1502 return SerializationReturnCode::StackOverflowError;
1504 JSArray* inArray = asArray(inValue);
1505 unsigned length = inArray->length();
1506 if (!startArray(inArray))
1508 inputObjectStack.append(inArray);
1509 indexStack.append(0);
1510 lengthStack.append(length);
1512 arrayStartVisitMember:
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();
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;
1528 propertyStack.removeLast();
1531 inputObjectStack.removeLast();
1534 inValue = array->getDirectIndex(m_exec, index);
1536 indexStack.last()++;
1537 goto arrayStartVisitMember;
1541 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1542 if (dumpIfTerminal(inValue, terminalCode)) {
1543 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1544 return terminalCode;
1545 indexStack.last()++;
1546 goto arrayStartVisitMember;
1548 stateStack.append(ArrayEndVisitMember);
1551 case ArrayEndVisitMember: {
1552 indexStack.last()++;
1553 goto arrayStartVisitMember;
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))
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());
1574 objectStartVisitMember:
1576 case ObjectStartVisitMember: {
1577 JSObject* object = inputObjectStack.last();
1578 uint32_t index = indexStack.last();
1579 PropertyNameArray& properties = propertyStack.last();
1580 if (index == properties.size()) {
1582 inputObjectStack.removeLast();
1583 indexStack.removeLast();
1584 propertyStack.removeLast();
1587 inValue = getProperty(vm, object, properties[index]);
1588 if (shouldTerminate())
1589 return SerializationReturnCode::ExistingExceptionError;
1592 // Property was removed during serialisation
1593 indexStack.last()++;
1594 goto objectStartVisitMember;
1596 write(properties[index]);
1598 if (shouldTerminate())
1599 return SerializationReturnCode::ExistingExceptionError;
1601 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1602 if (!dumpIfTerminal(inValue, terminalCode)) {
1603 stateStack.append(ObjectEndVisitMember);
1606 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1607 return terminalCode;
1610 case ObjectEndVisitMember: {
1611 if (shouldTerminate())
1612 return SerializationReturnCode::ExistingExceptionError;
1614 indexStack.last()++;
1615 goto objectStartVisitMember;
1618 ASSERT(inValue.isObject());
1619 if (inputObjectStack.size() > maximumFilterRecursion)
1620 return SerializationReturnCode::StackOverflowError;
1621 JSMap* inMap = jsCast<JSMap*>(inValue);
1622 if (!startMap(inMap))
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;
1631 mapDataStartVisitEntry:
1632 case MapDataStartVisitEntry: {
1633 JSMapIterator* iterator = mapIteratorStack.last();
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;
1646 m_gcBuffer.appendWithCrashOnOverflow(value);
1647 mapIteratorValueStack.append(value);
1648 stateStack.append(MapDataEndVisitKey);
1651 case MapDataEndVisitKey: {
1652 inValue = mapIteratorValueStack.last();
1653 mapIteratorValueStack.removeLast();
1654 stateStack.append(MapDataEndVisitValue);
1657 case MapDataEndVisitValue: {
1658 goto mapDataStartVisitEntry;
1662 ASSERT(inValue.isObject());
1663 if (inputObjectStack.size() > maximumFilterRecursion)
1664 return SerializationReturnCode::StackOverflowError;
1665 JSSet* inSet = jsCast<JSSet*>(inValue);
1666 if (!startSet(inSet))
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;
1675 setDataStartVisitEntry:
1676 case SetDataStartVisitEntry: {
1677 JSSetIterator* iterator = setIteratorStack.last();
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;
1690 stateStack.append(SetDataEndVisitKey);
1693 case SetDataEndVisitKey: {
1694 goto setDataStartVisitEntry;
1698 case StateUnknown: {
1699 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1700 if (dumpIfTerminal(inValue, terminalCode)) {
1701 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1702 return terminalCode;
1706 if (isArray(vm, inValue))
1707 goto arrayStartState;
1708 if (isMap(vm, inValue))
1710 if (isSet(vm, inValue))
1712 goto objectStartState;
1715 if (stateStack.isEmpty())
1718 state = stateStack.last();
1719 stateStack.removeLast();
1722 return SerializationReturnCode::UnspecifiedError;
1724 return SerializationReturnCode::SuccessfullyCompleted;
1727 class CloneDeserializer : CloneBase {
1729 static String deserializeString(const Vector<uint8_t>& buffer)
1731 if (buffer.isEmpty())
1733 const uint8_t* ptr = buffer.begin();
1734 const uint8_t* end = buffer.end();
1736 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1739 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1742 if (!readLittleEndian(ptr, end, length))
1744 bool is8Bit = length & StringDataIs8BitFlag;
1745 length &= ~StringDataIs8BitFlag;
1747 if (!readString(ptr, end, str, length, is8Bit))
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
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)
1765 if (!deserializer.isValid())
1766 return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
1767 return deserializer.deserialize();
1771 struct CachedString {
1772 CachedString(const String& string)
1777 JSValue jsString(ExecState* exec)
1780 m_jsString = JSC::jsString(exec, m_string);
1783 const String& string() { return m_string; }
1784 String takeString() { return WTFMove(m_string); }
1791 struct CachedStringRef {
1797 CachedStringRef(Vector<CachedString>* base, size_t index)
1803 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1806 Vector<CachedString>* m_base;
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,
1814 const Vector<uint8_t>& buffer)
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)
1830 if (!read(m_version))
1831 m_version = 0xFFFFFFFF;
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
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)
1857 if (!read(m_version))
1858 m_version = 0xFFFFFFFF;
1861 DeserializationResult deserialize();
1863 bool isValid() const { return m_version <= CurrentVersion; }
1865 template <typename T> bool readLittleEndian(T& value)
1867 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1873 #if ASSUME_LITTLE_ENDIAN
1874 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1876 if (ptr > end - sizeof(value))
1882 value = *reinterpret_cast<const T*>(ptr);
1888 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1890 if (ptr > end - sizeof(value))
1897 for (unsigned i = 0; i < sizeof(T); i++)
1898 value += ((T)*ptr++) << (i * 8);
1904 bool read(uint32_t& i)
1906 return readLittleEndian(i);
1909 bool read(int32_t& i)
1911 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1914 bool read(uint16_t& i)
1916 return readLittleEndian(i);
1919 bool read(uint8_t& i)
1921 return readLittleEndian(i);
1924 bool read(double& d)
1930 if (!readLittleEndian(u.i64))
1936 bool read(unsigned long long& i)
1938 return readLittleEndian(i);
1941 bool readStringIndex(uint32_t& i)
1943 return readConstantPoolIndex(m_constantPool, i);
1946 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1948 if (constantPool.size() <= 0xFF) {
1955 if (constantPool.size() <= 0xFFFF) {
1965 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit)
1967 if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar))
1971 if ((end - ptr) < static_cast<int>(length))
1973 str = String(reinterpret_cast<const LChar*>(ptr), length);
1978 unsigned size = length * sizeof(UChar);
1979 if ((end - ptr) < static_cast<int>(size))
1982 #if ASSUME_LITTLE_ENDIAN
1983 str = String(reinterpret_cast<const UChar*>(ptr), length);
1984 ptr += length * sizeof(UChar);
1986 Vector<UChar> buffer;
1987 buffer.reserveCapacity(length);
1988 for (unsigned i = 0; i < length; i++) {
1990 readLittleEndian(ptr, end, ch);
1993 str = String::adopt(WTFMove(buffer));
1998 bool readStringData(CachedStringRef& cachedString)
2001 return readStringData(cachedString, scratch);
2004 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
2008 uint32_t length = 0;
2011 if (length == TerminatorTag) {
2012 wasTerminator = true;
2015 if (length == StringPoolTag) {
2017 if (!readStringIndex(index)) {
2021 if (index >= m_constantPool.size()) {
2025 cachedString = CachedStringRef(&m_constantPool, index);
2028 bool is8Bit = length & StringDataIs8BitFlag;
2029 length &= ~StringDataIs8BitFlag;
2031 if (!readString(m_ptr, m_end, str, length, is8Bit)) {
2035 m_constantPool.append(str);
2036 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
2040 SerializationTag readTag()
2044 return static_cast<SerializationTag>(*m_ptr++);
2047 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
2051 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
2055 void putProperty(JSObject* object, unsigned index, JSValue value)
2057 object->putDirectIndex(m_exec, index, value);
2060 void putProperty(JSObject* object, const Identifier& property, JSValue value)
2062 object->putDirectMayBeIndex(m_exec, property, value);
2065 bool readFile(RefPtr<File>& file)
2067 CachedStringRef path;
2068 if (!readStringData(path))
2070 CachedStringRef url;
2071 if (!readStringData(url))
2073 CachedStringRef type;
2074 if (!readStringData(type))
2076 CachedStringRef name;
2077 if (!readStringData(name))
2079 Optional<int64_t> optionalLastModified;
2080 if (m_version > 6) {
2081 double lastModified;
2082 if (!read(lastModified))
2084 if (lastModified >= 0)
2085 optionalLastModified = lastModified;
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();
2093 if (m_isDOMGlobalObject)
2094 file = File::deserialize(jsCast<JSDOMGlobalObject*>(m_globalObject)->scriptExecutionContext()->sessionID(), filePath, URL(URL(), url->string()), type->string(), name->string(), optionalLastModified);
2098 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
2103 if (m_ptr + length > m_end)
2105 arrayBuffer = ArrayBuffer::create(m_ptr, length);
2110 bool readArrayBufferView(VM& vm, JSValue& arrayBufferView)
2112 ArrayBufferViewSubtag arrayBufferViewSubtag;
2113 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
2115 uint32_t byteOffset;
2116 if (!read(byteOffset))
2118 uint32_t byteLength;
2119 if (!read(byteLength))
2121 JSObject* arrayBufferObj = asObject(readTerminal());
2122 if (!arrayBufferObj || !arrayBufferObj->inherits<JSArrayBuffer>(vm))
2125 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
2128 unsigned length = byteLength / elementSize;
2129 if (length * elementSize != byteLength)
2132 RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(vm, arrayBufferObj);
2133 switch (arrayBufferViewSubtag) {
2135 arrayBufferView = toJS(m_exec, m_globalObject, DataView::create(WTFMove(arrayBuffer), byteOffset, length).get());
2138 arrayBufferView = toJS(m_exec, m_globalObject, Int8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2141 arrayBufferView = toJS(m_exec, m_globalObject, Uint8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2143 case Uint8ClampedArrayTag:
2144 arrayBufferView = toJS(m_exec, m_globalObject, Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2147 arrayBufferView = toJS(m_exec, m_globalObject, Int16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2149 case Uint16ArrayTag:
2150 arrayBufferView = toJS(m_exec, m_globalObject, Uint16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2153 arrayBufferView = toJS(m_exec, m_globalObject, Int32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2155 case Uint32ArrayTag:
2156 arrayBufferView = toJS(m_exec, m_globalObject, Uint32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2158 case Float32ArrayTag:
2159 arrayBufferView = toJS(m_exec, m_globalObject, Float32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2161 case Float64ArrayTag:
2162 arrayBufferView = toJS(m_exec, m_globalObject, Float64Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2169 bool read(Vector<uint8_t>& result)
2171 ASSERT(result.isEmpty());
2175 if (m_ptr + size > m_end)
2177 result.append(m_ptr, size);
2182 #if ENABLE(WEB_CRYPTO)
2183 bool read(CryptoAlgorithmIdentifier& result)
2185 uint8_t algorithmTag;
2186 if (!read(algorithmTag))
2188 if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
2190 switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
2191 case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
2192 result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
2194 case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
2195 result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
2197 case CryptoAlgorithmIdentifierTag::RSA_PSS:
2198 result = CryptoAlgorithmIdentifier::RSA_PSS;
2200 case CryptoAlgorithmIdentifierTag::RSA_OAEP:
2201 result = CryptoAlgorithmIdentifier::RSA_OAEP;
2203 case CryptoAlgorithmIdentifierTag::ECDSA:
2204 result = CryptoAlgorithmIdentifier::ECDSA;
2206 case CryptoAlgorithmIdentifierTag::ECDH:
2207 result = CryptoAlgorithmIdentifier::ECDH;
2209 case CryptoAlgorithmIdentifierTag::AES_CTR:
2210 result = CryptoAlgorithmIdentifier::AES_CTR;
2212 case CryptoAlgorithmIdentifierTag::AES_CBC:
2213 result = CryptoAlgorithmIdentifier::AES_CBC;
2215 case CryptoAlgorithmIdentifierTag::AES_GCM:
2216 result = CryptoAlgorithmIdentifier::AES_GCM;
2218 case CryptoAlgorithmIdentifierTag::AES_CFB:
2219 result = CryptoAlgorithmIdentifier::AES_CFB;
2221 case CryptoAlgorithmIdentifierTag::AES_KW:
2222 result = CryptoAlgorithmIdentifier::AES_KW;
2224 case CryptoAlgorithmIdentifierTag::HMAC:
2225 result = CryptoAlgorithmIdentifier::HMAC;
2227 case CryptoAlgorithmIdentifierTag::SHA_1:
2228 result = CryptoAlgorithmIdentifier::SHA_1;
2230 case CryptoAlgorithmIdentifierTag::SHA_224:
2231 result = CryptoAlgorithmIdentifier::SHA_224;
2233 case CryptoAlgorithmIdentifierTag::SHA_256:
2234 result = CryptoAlgorithmIdentifier::SHA_256;
2236 case CryptoAlgorithmIdentifierTag::SHA_384:
2237 result = CryptoAlgorithmIdentifier::SHA_384;
2239 case CryptoAlgorithmIdentifierTag::SHA_512:
2240 result = CryptoAlgorithmIdentifier::SHA_512;
2242 case CryptoAlgorithmIdentifierTag::HKDF:
2243 result = CryptoAlgorithmIdentifier::HKDF;
2245 case CryptoAlgorithmIdentifierTag::PBKDF2:
2246 result = CryptoAlgorithmIdentifier::PBKDF2;
2252 bool read(CryptoKeyClassSubtag& result)
2257 if (tag > cryptoKeyClassSubtagMaximumValue)
2259 result = static_cast<CryptoKeyClassSubtag>(tag);
2263 bool read(CryptoKeyUsageTag& result)
2268 if (tag > cryptoKeyUsageTagMaximumValue)
2270 result = static_cast<CryptoKeyUsageTag>(tag);
2274 bool read(CryptoKeyAsymmetricTypeSubtag& result)
2279 if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
2281 result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
2285 bool readHMACKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2287 Vector<uint8_t> keyData;
2290 CryptoAlgorithmIdentifier hash;
2293 result = CryptoKeyHMAC::importRaw(0, hash, WTFMove(keyData), extractable, usages);
2297 bool readAESKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2299 CryptoAlgorithmIdentifier algorithm;
2300 if (!read(algorithm))
2302 if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
2304 Vector<uint8_t> keyData;
2307 result = CryptoKeyAES::importRaw(algorithm, WTFMove(keyData), extractable, usages);
2311 bool readRSAKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2313 CryptoAlgorithmIdentifier algorithm;
2314 if (!read(algorithm))
2317 int32_t isRestrictedToHash;
2318 CryptoAlgorithmIdentifier hash;
2319 if (!read(isRestrictedToHash))
2321 if (isRestrictedToHash && !read(hash))
2324 CryptoKeyAsymmetricTypeSubtag type;
2328 Vector<uint8_t> modulus;
2331 Vector<uint8_t> exponent;
2332 if (!read(exponent))
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);
2342 Vector<uint8_t> privateExponent;
2343 if (!read(privateExponent))
2346 uint32_t primeCount;
2347 if (!read(primeCount))
2351 auto keyData = CryptoKeyRSAComponents::createPrivate(modulus, exponent, privateExponent);
2352 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2353 result = WTFMove(key);
2360 CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
2361 CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
2362 Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
2364 if (!read(firstPrimeInfo.primeFactor))
2366 if (!read(firstPrimeInfo.factorCRTExponent))
2368 if (!read(secondPrimeInfo.primeFactor))
2370 if (!read(secondPrimeInfo.factorCRTExponent))
2372 if (!read(secondPrimeInfo.factorCRTCoefficient))
2374 for (unsigned i = 2; i < primeCount; ++i) {
2375 if (!read(otherPrimeInfos[i].primeFactor))
2377 if (!read(otherPrimeInfos[i].factorCRTExponent))
2379 if (!read(otherPrimeInfos[i].factorCRTCoefficient))
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);
2389 bool readECKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2391 CryptoAlgorithmIdentifier algorithm;
2392 if (!read(algorithm))
2394 if (!CryptoKeyEC::isValidECAlgorithm(algorithm))
2396 CachedStringRef curve;
2397 if (!readStringData(curve))
2399 CryptoKeyAsymmetricTypeSubtag type;
2402 Vector<uint8_t> keyData;
2407 case CryptoKeyAsymmetricTypeSubtag::Public:
2408 result = CryptoKeyEC::importRaw(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2410 case CryptoKeyAsymmetricTypeSubtag::Private:
2411 result = CryptoKeyEC::importPkcs8(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2418 bool readRawKey(CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2420 CryptoAlgorithmIdentifier algorithm;
2421 if (!read(algorithm))
2423 Vector<uint8_t> keyData;
2426 result = CryptoKeyRaw::create(algorithm, WTFMove(keyData), usages);
2430 bool readCryptoKey(JSValue& cryptoKey)
2432 uint32_t keyFormatVersion;
2433 if (!read(keyFormatVersion) || keyFormatVersion > currentKeyFormatVersion)
2436 int32_t extractable;
2437 if (!read(extractable))
2440 uint32_t usagesCount;
2441 if (!read(usagesCount))
2444 CryptoKeyUsageBitmap usages = 0;
2445 for (uint32_t i = 0; i < usagesCount; ++i) {
2446 CryptoKeyUsageTag usage;
2450 case CryptoKeyUsageTag::Encrypt:
2451 usages |= CryptoKeyUsageEncrypt;
2453 case CryptoKeyUsageTag::Decrypt:
2454 usages |= CryptoKeyUsageDecrypt;
2456 case CryptoKeyUsageTag::Sign:
2457 usages |= CryptoKeyUsageSign;
2459 case CryptoKeyUsageTag::Verify:
2460 usages |= CryptoKeyUsageVerify;
2462 case CryptoKeyUsageTag::DeriveKey:
2463 usages |= CryptoKeyUsageDeriveKey;
2465 case CryptoKeyUsageTag::DeriveBits:
2466 usages |= CryptoKeyUsageDeriveBits;
2468 case CryptoKeyUsageTag::WrapKey:
2469 usages |= CryptoKeyUsageWrapKey;
2471 case CryptoKeyUsageTag::UnwrapKey:
2472 usages |= CryptoKeyUsageUnwrapKey;
2477 CryptoKeyClassSubtag cryptoKeyClass;
2478 if (!read(cryptoKeyClass))
2480 RefPtr<CryptoKey> result;
2481 switch (cryptoKeyClass) {
2482 case CryptoKeyClassSubtag::HMAC:
2483 if (!readHMACKey(extractable, usages, result))
2486 case CryptoKeyClassSubtag::AES:
2487 if (!readAESKey(extractable, usages, result))
2490 case CryptoKeyClassSubtag::RSA:
2491 if (!readRSAKey(extractable, usages, result))
2494 case CryptoKeyClassSubtag::EC:
2495 if (!readECKey(extractable, usages, result))
2498 case CryptoKeyClassSubtag::Raw:
2499 if (!readRawKey(usages, result))
2503 cryptoKey = getJSValue(result.get());
2509 JSValue getJSValue(T* nativeObj)
2511 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2515 JSValue getJSValue(T& nativeObj)
2517 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2521 JSValue readDOMPoint()
2536 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, z, w));
2540 JSValue readDOMMatrix()
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));
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));
2624 JSValue readDOMRect()
2639 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, width, height));
2642 Optional<DOMPointInit> readDOMPointInit()
2646 return WTF::nullopt;
2648 return WTF::nullopt;
2650 return WTF::nullopt;
2652 return WTF::nullopt;
2657 JSValue readDOMQuad()
2659 auto p1 = readDOMPointInit();
2662 auto p2 = readDOMPointInit();
2665 auto p3 = readDOMPointInit();
2668 auto p4 = readDOMPointInit();
2672 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), DOMQuad::create(p1.value(), p2.value(), p3.value(), p4.value()));
2675 JSValue readImageBitmap()
2678 bool indexSuccessfullyRead = read(index);
2679 if (!indexSuccessfullyRead || index >= m_imageBuffers.size()) {
2684 if (!m_imageBitmaps[index])
2685 m_imageBitmaps[index] = ImageBitmap::create(WTFMove(m_imageBuffers.at(index)));
2687 auto bitmap = m_imageBitmaps[index].get();
2688 return getJSValue(bitmap);
2692 JSValue readRTCCertificate()
2695 if (!read(expires)) {
2699 CachedStringRef certificate;
2700 if (!readStringData(certificate)) {
2704 CachedStringRef origin;
2705 if (!readStringData(origin)) {
2709 CachedStringRef keyedMaterial;
2710 if (!readStringData(keyedMaterial)) {
2718 Vector<RTCCertificate::DtlsFingerprint> fingerprints;
2719 fingerprints.reserveInitialCapacity(size);
2720 for (unsigned i = 0; i < size; i++) {
2721 CachedStringRef algorithm;
2722 if (!readStringData(algorithm))
2724 CachedStringRef value;
2725 if (!readStringData(value))
2727 fingerprints.uncheckedAppend(RTCCertificate::DtlsFingerprint { algorithm->string(), value->string() });
2730 if (!m_isDOMGlobalObject)
2731 return constructEmptyObject(m_exec, m_globalObject->objectPrototype());
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));
2738 JSValue readTerminal()
2740 SerializationTag tag = readTag();
2743 return jsUndefined();
2757 return jsBoolean(false);
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);
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);
2778 case NumberObjectTag: {
2782 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
2783 m_gcBuffer.appendWithCrashOnOverflow(obj);
2790 return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
2794 if (!readFile(file))
2796 if (!m_isDOMGlobalObject)
2798 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
2801 unsigned length = 0;
2804 Vector<Ref<File>> files;
2805 for (unsigned i = 0; i < length; i++) {
2807 if (!readFile(file))
2809 if (m_isDOMGlobalObject)
2810 files.append(file.releaseNonNull());
2812 if (!m_isDOMGlobalObject)
2814 return getJSValue(FileList::create(WTFMove(files)).get());
2816 case ImageDataTag: {
2826 if (static_cast<uint32_t>(m_end - m_ptr) < length) {
2830 if (!m_isDOMGlobalObject) {
2834 IntSize imageSize(width, height);
2835 RELEASE_ASSERT(!length || (imageSize.area() * 4).unsafeGet() <= length);
2836 auto result = ImageData::create(imageSize);
2842 memcpy(result->data()->data(), m_ptr, length);
2844 result->data()->zeroFill();
2846 return getJSValue(result.get());
2849 CachedStringRef url;
2850 if (!readStringData(url))
2852 CachedStringRef type;
2853 if (!readStringData(type))
2855 unsigned long long size = 0;
2858 if (!m_isDOMGlobalObject)
2860 return getJSValue(Blob::deserialize(jsCast<JSDOMGlobalObject*>(m_globalObject)->scriptExecutionContext()->sessionID(), URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get());
2863 CachedStringRef cachedString;
2864 if (!readStringData(cachedString))
2866 return cachedString->jsString(m_exec);
2868 case EmptyStringTag:
2869 return jsEmptyString(&m_exec->vm());
2870 case StringObjectTag: {
2871 CachedStringRef cachedString;
2872 if (!readStringData(cachedString))
2874 StringObject* obj = constructString(m_exec->vm(), m_globalObject, cachedString->jsString(m_exec));
2875 m_gcBuffer.appendWithCrashOnOverflow(obj);
2878 case EmptyStringObjectTag: {
2879 VM& vm = m_exec->vm();
2880 StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(&vm));
2881 m_gcBuffer.appendWithCrashOnOverflow(obj);
2885 CachedStringRef pattern;
2886 if (!readStringData(pattern))
2888 CachedStringRef flags;
2889 if (!readStringData(flags))
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);
2897 case ObjectReferenceTag: {
2899 if (!readConstantPoolIndex(m_gcBuffer, index)) {
2903 return m_gcBuffer.at(index);
2905 case MessagePortReferenceTag: {
2907 bool indexSuccessfullyRead = read(index);
2908 if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
2912 return getJSValue(m_messagePorts[index].get());
2914 #if ENABLE(WEBASSEMBLY)
2915 case WasmModuleTag: {
2917 bool indexSuccessfullyRead = read(index);
2918 if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) {
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
2927 scope.releaseAssertNoException();
2928 m_gcBuffer.appendWithCrashOnOverflow(result);
2932 case ArrayBufferTag: {
2933 RefPtr<ArrayBuffer> arrayBuffer;
2934 if (!readArrayBuffer(arrayBuffer)) {
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.
2945 JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer));
2946 m_gcBuffer.appendWithCrashOnOverflow(result);
2949 case ArrayBufferTransferTag: {
2951 bool indexSuccessfullyRead = read(index);
2952 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
2957 if (!m_arrayBuffers[index])
2958 m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
2960 return getJSValue(m_arrayBuffers[index].get());
2962 case SharedArrayBufferTag: {
2963 uint32_t index = UINT_MAX;
2964 bool indexSuccessfullyRead = read(index);
2965 if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) {
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);
2976 case ArrayBufferViewTag: {
2977 JSValue arrayBufferView;
2978 if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) {
2982 m_gcBuffer.appendWithCrashOnOverflow(arrayBufferView);
2983 return arrayBufferView;
2985 #if ENABLE(WEB_CRYPTO)
2986 case CryptoKeyTag: {
2987 Vector<uint8_t> wrappedKey;
2988 if (!read(wrappedKey)) {
2992 Vector<uint8_t> serializedKey;
2993 if (!unwrapCryptoKey(m_exec, wrappedKey, serializedKey)) {
2998 Vector<RefPtr<MessagePort>> dummyMessagePorts;
2999 CloneDeserializer rawKeyDeserializer(m_exec, m_globalObject, dummyMessagePorts, nullptr, { },
3000 #if ENABLE(WEBASSEMBLY)
3004 if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
3008 m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
3012 case DOMPointReadOnlyTag:
3013 return readDOMPoint<DOMPointReadOnly>();
3015 return readDOMPoint<DOMPoint>();
3016 case DOMRectReadOnlyTag:
3017 return readDOMRect<DOMRectReadOnly>();
3019 return readDOMRect<DOMRect>();
3020 case DOMMatrixReadOnlyTag:
3021 return readDOMMatrix<DOMMatrixReadOnly>();
3023 return readDOMMatrix<DOMMatrix>();
3025 return readDOMQuad();
3026 case ImageBitmapTransferTag:
3027 return readImageBitmap();
3029 case RTCCertificateTag:
3030 return readRTCCertificate();
3034 m_ptr--; // Push the tag back
3039 template<SerializationTag Tag>
3040 bool consumeCollectionDataTerminationIfPossible()
3042 if (readTag() == Tag)
3048 JSGlobalObject* m_globalObject;
3049 bool m_isDOMGlobalObject;
3050 const uint8_t* m_ptr;
3051 const uint8_t* m_end;
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;
3066 String blobFilePathForBlobURL(const String& blobURL)
3069 for (; i < m_blobURLs.size(); ++i) {
3070 if (m_blobURLs[i] == blobURL)
3074 return i < m_blobURLs.size() ? m_blobFilePaths[i] : String();
3078 DeserializationResult CloneDeserializer::deserialize()
3080 VM& vm = m_exec->vm();
3081 auto scope = DECLARE_THROW_SCOPE(vm);
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;
3096 case ArrayStartState: {
3098 if (!read(length)) {
3102 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
3103 if (UNLIKELY(scope.exception()))
3105 m_gcBuffer.appendWithCrashOnOverflow(outArray);
3106 outputObjectStack.append(outArray);
3108 arrayStartVisitMember:
3110 case ArrayStartVisitMember: {
3116 if (index == TerminatorTag) {
3117 JSObject* outArray = outputObjectStack.last();
3118 outValue = outArray;
3119 outputObjectStack.removeLast();
3121 } else if (index == NonIndexPropertiesTag) {
3122 goto objectStartVisitMember;
3125 if (JSValue terminal = readTerminal()) {
3126 putProperty(outputObjectStack.last(), index, terminal);
3127 goto arrayStartVisitMember;
3131 indexStack.append(index);
3132 stateStack.append(ArrayEndVisitMember);
3135 case ArrayEndVisitMember: {
3136 JSObject* outArray = outputObjectStack.last();
3137 putProperty(outArray, indexStack.last(), outValue);
3138 indexStack.removeLast();
3139 goto arrayStartVisitMember;
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);
3149 objectStartVisitMember:
3151 case ObjectStartVisitMember: {
3152 CachedStringRef cachedString;
3153 bool wasTerminator = false;
3154 if (!readStringData(cachedString, wasTerminator)) {
3158 JSObject* outObject = outputObjectStack.last();
3159 outValue = outObject;
3160 outputObjectStack.removeLast();
3164 if (JSValue terminal = readTerminal()) {
3165 putProperty(outputObjectStack.last(), Identifier::fromString(m_exec, cachedString->string()), terminal);
3166 goto objectStartVisitMember;
3168 stateStack.append(ObjectEndVisitMember);
3169 propertyNameStack.append(Identifier::fromString(m_exec, cachedString->string()));
3172 case ObjectEndVisitMember: {
3173 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
3174 propertyNameStack.removeLast();
3175 goto objectStartVisitMember;
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()))
3183 m_gcBuffer.appendWithCrashOnOverflow(map);
3184 outputObjectStack.append(map);
3185 mapStack.append(map);
3186 goto mapDataStartVisitEntry;
3188 mapDataStartVisitEntry:
3189 case MapDataStartVisitEntry: {
3190 if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) {
3191 mapStack.removeLast();