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, const PAL::SessionID& sessionID, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
553 CloneSerializer serializer(exec, messagePorts, arrayBuffers, imageBitmaps,
554 #if ENABLE(WEBASSEMBLY)
557 blobURLs, sessionID, 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, const PAL::SessionID& sessionID, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
587 , m_blobURLs(blobURLs)
588 , m_sessionID(sessionID)
589 , m_emptyIdentifier(Identifier::fromString(exec, emptyString()))
591 , m_sharedBuffers(sharedBuffers)
592 #if ENABLE(WEBASSEMBLY)
593 , m_wasmModules(wasmModules)
596 write(CurrentVersion);
597 fillTransferMap(messagePorts, m_transferredMessagePorts);
598 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
599 fillTransferMap(imageBitmaps, m_transferredImageBitmaps);
603 void fillTransferMap(const Vector<RefPtr<T>>& input, ObjectPool& result)
607 JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
608 for (size_t i = 0; i < input.size(); i++) {
609 JSC::JSValue value = toJS(m_exec, globalObject, input[i].get());
610 JSC::JSObject* obj = value.getObject();
611 if (obj && !result.contains(obj))
616 SerializationReturnCode serialize(JSValue in);
618 bool isArray(VM& vm, JSValue value)
620 if (!value.isObject())
622 JSObject* object = asObject(value);
623 return object->inherits<JSArray>(vm);
626 bool isMap(VM& vm, JSValue value)
628 if (!value.isObject())
630 JSObject* object = asObject(value);
631 return object->inherits<JSMap>(vm);
633 bool isSet(VM& vm, JSValue value)
635 if (!value.isObject())
637 JSObject* object = asObject(value);
638 return object->inherits<JSSet>(vm);
641 bool checkForDuplicate(JSObject* object)
643 // Record object for graph reconstruction
644 ObjectPool::const_iterator found = m_objectPool.find(object);
646 // Handle duplicate references
647 if (found != m_objectPool.end()) {
648 write(ObjectReferenceTag);
649 ASSERT(found->value < m_objectPool.size());
650 writeObjectIndex(found->value);
657 void recordObject(JSObject* object)
659 m_objectPool.add(object, m_objectPool.size());
660 m_gcBuffer.appendWithCrashOnOverflow(object);
663 bool startObjectInternal(JSObject* object)
665 if (checkForDuplicate(object))
667 recordObject(object);
671 bool startObject(JSObject* object)
673 if (!startObjectInternal(object))
679 bool startArray(JSArray* array)
681 if (!startObjectInternal(array))
684 unsigned length = array->length();
690 bool startSet(JSSet* set)
692 if (!startObjectInternal(set))
699 bool startMap(JSMap* map)
701 if (!startObjectInternal(map))
710 write(TerminatorTag);
713 JSValue getProperty(VM& vm, JSObject* object, const Identifier& propertyName)
715 PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
716 if (object->methodTable(vm)->getOwnPropertySlot(object, m_exec, propertyName, slot))
717 return slot.getValue(m_exec, propertyName);
721 void dumpImmediate(JSValue value)
725 else if (value.isUndefined())
727 else if (value.isNumber()) {
728 if (value.isInt32()) {
729 if (!value.asInt32())
731 else if (value.asInt32() == 1)
735 write(static_cast<uint32_t>(value.asInt32()));
739 write(value.asDouble());
741 } else if (value.isBoolean()) {
749 void dumpString(const String& string)
751 if (string.isEmpty())
752 write(EmptyStringTag);
759 void dumpStringObject(const String& string)
761 if (string.isEmpty())
762 write(EmptyStringObjectTag);
764 write(StringObjectTag);
769 JSC::JSValue toJSArrayBuffer(ArrayBuffer& arrayBuffer)
771 auto& vm = m_exec->vm();
772 auto* globalObject = m_exec->lexicalGlobalObject();
773 if (globalObject->inherits<JSDOMGlobalObject>(vm))
774 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(globalObject), &arrayBuffer);
776 if (auto* buffer = arrayBuffer.m_wrapper.get())
779 return JSC::JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(arrayBuffer.sharingMode()), &arrayBuffer);
782 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
784 VM& vm = m_exec->vm();
785 write(ArrayBufferViewTag);
786 if (obj->inherits<JSDataView>(vm))
788 else if (obj->inherits<JSUint8ClampedArray>(vm))
789 write(Uint8ClampedArrayTag);
790 else if (obj->inherits<JSInt8Array>(vm))
792 else if (obj->inherits<JSUint8Array>(vm))
793 write(Uint8ArrayTag);
794 else if (obj->inherits<JSInt16Array>(vm))
795 write(Int16ArrayTag);
796 else if (obj->inherits<JSUint16Array>(vm))
797 write(Uint16ArrayTag);
798 else if (obj->inherits<JSInt32Array>(vm))
799 write(Int32ArrayTag);
800 else if (obj->inherits<JSUint32Array>(vm))
801 write(Uint32ArrayTag);
802 else if (obj->inherits<JSFloat32Array>(vm))
803 write(Float32ArrayTag);
804 else if (obj->inherits<JSFloat64Array>(vm))
805 write(Float64ArrayTag);
809 RefPtr<ArrayBufferView> arrayBufferView = toPossiblySharedArrayBufferView(vm, obj);
810 write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
811 write(static_cast<uint32_t>(arrayBufferView->byteLength()));
812 RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->possiblySharedBuffer();
814 code = SerializationReturnCode::ValidationError;
818 return dumpIfTerminal(toJSArrayBuffer(*arrayBuffer), code);
821 void dumpDOMPoint(const DOMPointReadOnly& point)
829 void dumpDOMPoint(JSObject* obj)
831 VM& vm = m_exec->vm();
832 if (obj->inherits<JSDOMPoint>(vm))
835 write(DOMPointReadOnlyTag);
837 dumpDOMPoint(jsCast<JSDOMPointReadOnly*>(obj)->wrapped());
840 void dumpDOMRect(JSObject* obj)
842 VM& vm = m_exec->vm();
843 if (obj->inherits<JSDOMRect>(vm))
846 write(DOMRectReadOnlyTag);
848 auto& rect = jsCast<JSDOMRectReadOnly*>(obj)->wrapped();
852 write(rect.height());
855 void dumpDOMMatrix(JSObject* obj)
857 VM& vm = m_exec->vm();
858 if (obj->inherits<JSDOMMatrix>(vm))
861 write(DOMMatrixReadOnlyTag);
863 auto& matrix = jsCast<JSDOMMatrixReadOnly*>(obj)->wrapped();
864 bool is2D = matrix.is2D();
865 write(static_cast<uint8_t>(is2D));
893 void dumpDOMQuad(JSObject* obj)
897 auto& quad = jsCast<JSDOMQuad*>(obj)->wrapped();
898 dumpDOMPoint(quad.p1());
899 dumpDOMPoint(quad.p2());
900 dumpDOMPoint(quad.p3());
901 dumpDOMPoint(quad.p4());
904 void dumpImageBitmap(JSObject* obj, SerializationReturnCode& code)
906 auto index = m_transferredImageBitmaps.find(obj);
907 if (index != m_transferredImageBitmaps.end()) {
908 write(ImageBitmapTransferTag);
913 // Copying ImageBitmaps is not yet supported.
914 code = SerializationReturnCode::ValidationError;
917 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
919 if (!value.isCell()) {
920 dumpImmediate(value);
923 ASSERT(value.isCell());
925 if (value.isString()) {
926 dumpString(asString(value)->value(m_exec));
930 if (value.isSymbol()) {
931 code = SerializationReturnCode::DataCloneError;
935 VM& vm = m_exec->vm();
936 if (isArray(vm, value))
939 if (value.isObject()) {
940 auto* obj = asObject(value);
941 if (auto* dateObject = jsDynamicCast<DateInstance*>(vm, obj)) {
943 write(dateObject->internalNumber());
946 if (auto* booleanObject = jsDynamicCast<BooleanObject*>(vm, obj)) {
947 if (!startObjectInternal(booleanObject)) // handle duplicates
949 write(booleanObject->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
952 if (auto* stringObject = jsDynamicCast<StringObject*>(vm, obj)) {
953 if (!startObjectInternal(stringObject)) // handle duplicates
955 String str = asString(stringObject->internalValue())->value(m_exec);
956 dumpStringObject(str);
959 if (auto* numberObject = jsDynamicCast<NumberObject*>(vm, obj)) {
960 if (!startObjectInternal(numberObject)) // handle duplicates
962 write(NumberObjectTag);
963 write(numberObject->internalValue().asNumber());
966 if (auto* file = JSFile::toWrapped(vm, obj)) {
971 if (auto* list = JSFileList::toWrapped(vm, obj)) {
973 write(list->length());
974 for (auto& file : list->files())
978 if (auto* blob = JSBlob::toWrapped(vm, obj)) {
980 m_blobURLs.append(blob->url());
986 if (auto* data = JSImageData::toWrapped(vm, obj)) {
988 write(data->width());
989 write(data->height());
990 write(data->data()->length());
991 write(data->data()->data(), data->data()->length());
994 if (auto* regExp = jsDynamicCast<RegExpObject*>(vm, obj)) {
997 if (regExp->regExp()->global())
998 flags[flagCount++] = 'g';
999 if (regExp->regExp()->ignoreCase())
1000 flags[flagCount++] = 'i';
1001 if (regExp->regExp()->multiline())
1002 flags[flagCount++] = 'm';
1004 write(regExp->regExp()->pattern());
1005 write(String(flags, flagCount));
1008 if (obj->inherits<JSMessagePort>(vm)) {
1009 auto index = m_transferredMessagePorts.find(obj);
1010 if (index != m_transferredMessagePorts.end()) {
1011 write(MessagePortReferenceTag);
1012 write(index->value);
1015 // MessagePort object could not be found in transferred message ports
1016 code = SerializationReturnCode::ValidationError;
1019 if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
1020 if (arrayBuffer->isNeutered()) {
1021 code = SerializationReturnCode::ValidationError;
1024 auto index = m_transferredArrayBuffers.find(obj);
1025 if (index != m_transferredArrayBuffers.end()) {
1026 write(ArrayBufferTransferTag);
1027 write(index->value);
1030 if (!startObjectInternal(obj)) // handle duplicates
1033 if (arrayBuffer->isShared() && m_context == SerializationContext::WorkerPostMessage) {
1034 uint32_t index = m_sharedBuffers.size();
1035 ArrayBufferContents contents;
1036 if (arrayBuffer->shareWith(contents)) {
1037 write(SharedArrayBufferTag);
1038 m_sharedBuffers.append(WTFMove(contents));
1044 write(ArrayBufferTag);
1045 write(arrayBuffer->byteLength());
1046 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
1049 if (obj->inherits<JSArrayBufferView>(vm)) {
1050 if (checkForDuplicate(obj))
1052 bool success = dumpArrayBufferView(obj, code);
1056 #if ENABLE(WEB_CRYPTO)
1057 if (auto* key = JSCryptoKey::toWrapped(vm, obj)) {
1058 write(CryptoKeyTag);
1059 Vector<uint8_t> serializedKey;
1060 Vector<String> dummyBlobURLs;
1061 PAL::SessionID dummySessionID;
1062 Vector<RefPtr<MessagePort>> dummyMessagePorts;
1063 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
1064 #if ENABLE(WEBASSEMBLY)
1065 WasmModuleArray dummyModules;
1067 ArrayBufferContentsArray dummySharedBuffers;
1068 CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, { },
1069 #if ENABLE(WEBASSEMBLY)
1072 dummyBlobURLs, dummySessionID, serializedKey, SerializationContext::Default, dummySharedBuffers);
1073 rawKeySerializer.write(key);
1074 Vector<uint8_t> wrappedKey;
1075 if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey))
1082 if (auto* rtcCertificate = JSRTCCertificate::toWrapped(vm, obj)) {
1083 write(RTCCertificateTag);
1084 write(rtcCertificate->expires());
1085 write(rtcCertificate->pemCertificate());
1086 write(rtcCertificate->origin().toString());
1087 write(rtcCertificate->pemPrivateKey());
1088 write(static_cast<unsigned>(rtcCertificate->getFingerprints().size()));
1089 for (const auto& fingerprint : rtcCertificate->getFingerprints()) {
1090 write(fingerprint.algorithm);
1091 write(fingerprint.value);
1096 #if ENABLE(WEBASSEMBLY)
1097 if (JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, obj)) {
1098 if (m_context != SerializationContext::WorkerPostMessage && m_context != SerializationContext::WindowPostMessage)
1101 uint32_t index = m_wasmModules.size();
1102 m_wasmModules.append(makeRef(module->module()));
1103 write(WasmModuleTag);
1108 if (obj->inherits<JSDOMPointReadOnly>(vm)) {
1112 if (obj->inherits<JSDOMRectReadOnly>(vm)) {
1116 if (obj->inherits<JSDOMMatrixReadOnly>(vm)) {
1120 if (obj->inherits<JSDOMQuad>(vm)) {
1124 if (obj->inherits(vm, JSImageBitmap::info())) {
1125 dumpImageBitmap(obj, code);
1130 // Any other types are expected to serialize as null.
1135 void write(SerializationTag tag)
1137 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1140 void write(ArrayBufferViewSubtag tag)
1142 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1145 #if ENABLE(WEB_CRYPTO)
1146 void write(CryptoKeyClassSubtag tag)
1148 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1151 void write(CryptoKeyAsymmetricTypeSubtag tag)
1153 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1156 void write(CryptoKeyUsageTag tag)
1158 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1161 void write(CryptoAlgorithmIdentifierTag tag)
1163 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
1167 void write(uint8_t c)
1169 writeLittleEndian(m_buffer, c);
1172 void write(uint32_t i)
1174 writeLittleEndian(m_buffer, i);
1177 void write(double d)
1184 writeLittleEndian(m_buffer, u.i);
1187 void write(int32_t i)
1189 writeLittleEndian(m_buffer, i);
1192 void write(unsigned long long i)
1194 writeLittleEndian(m_buffer, i);
1197 void write(uint16_t ch)
1199 writeLittleEndian(m_buffer, ch);
1202 void writeStringIndex(unsigned i)
1204 writeConstantPoolIndex(m_constantPool, i);
1207 void writeObjectIndex(unsigned i)
1209 writeConstantPoolIndex(m_objectPool, i);
1212 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
1214 ASSERT(i < constantPool.size());
1215 if (constantPool.size() <= 0xFF)
1216 write(static_cast<uint8_t>(i));
1217 else if (constantPool.size() <= 0xFFFF)
1218 write(static_cast<uint16_t>(i));
1220 write(static_cast<uint32_t>(i));
1223 void write(const Identifier& ident)
1225 const String& str = ident.string();
1226 StringConstantPool::AddResult addResult = m_constantPool.add(ident.impl(), m_constantPool.size());
1227 if (!addResult.isNewEntry) {
1228 write(StringPoolTag);
1229 writeStringIndex(addResult.iterator->value);
1233 unsigned length = str.length();
1235 // Guard against overflow
1236 if (length > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
1242 writeLittleEndian<uint32_t>(m_buffer, length | StringDataIs8BitFlag);
1244 writeLittleEndian<uint32_t>(m_buffer, length);
1249 if (!writeLittleEndian(m_buffer, str.characters8(), length))
1253 if (!writeLittleEndian(m_buffer, str.characters16(), length))
1257 void write(const String& str)
1260 write(m_emptyIdentifier);
1262 write(Identifier::fromString(m_exec, str));
1265 void write(const Vector<uint8_t>& vector)
1267 uint32_t size = vector.size();
1269 writeLittleEndian(m_buffer, vector.data(), size);
1272 void write(const File& file)
1274 m_blobURLs.append(file.url());
1279 write(static_cast<double>(file.lastModifiedOverride().valueOr(-1)));
1282 #if ENABLE(WEB_CRYPTO)
1283 void write(CryptoAlgorithmIdentifier algorithm)
1285 switch (algorithm) {
1286 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
1287 write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
1289 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
1290 write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
1292 case CryptoAlgorithmIdentifier::RSA_PSS:
1293 write(CryptoAlgorithmIdentifierTag::RSA_PSS);
1295 case CryptoAlgorithmIdentifier::RSA_OAEP:
1296 write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
1298 case CryptoAlgorithmIdentifier::ECDSA:
1299 write(CryptoAlgorithmIdentifierTag::ECDSA);
1301 case CryptoAlgorithmIdentifier::ECDH:
1302 write(CryptoAlgorithmIdentifierTag::ECDH);
1304 case CryptoAlgorithmIdentifier::AES_CTR:
1305 write(CryptoAlgorithmIdentifierTag::AES_CTR);
1307 case CryptoAlgorithmIdentifier::AES_CBC:
1308 write(CryptoAlgorithmIdentifierTag::AES_CBC);
1310 case CryptoAlgorithmIdentifier::AES_GCM:
1311 write(CryptoAlgorithmIdentifierTag::AES_GCM);
1313 case CryptoAlgorithmIdentifier::AES_CFB:
1314 write(CryptoAlgorithmIdentifierTag::AES_CFB);
1316 case CryptoAlgorithmIdentifier::AES_KW:
1317 write(CryptoAlgorithmIdentifierTag::AES_KW);
1319 case CryptoAlgorithmIdentifier::HMAC:
1320 write(CryptoAlgorithmIdentifierTag::HMAC);
1322 case CryptoAlgorithmIdentifier::SHA_1:
1323 write(CryptoAlgorithmIdentifierTag::SHA_1);
1325 case CryptoAlgorithmIdentifier::SHA_224:
1326 write(CryptoAlgorithmIdentifierTag::SHA_224);
1328 case CryptoAlgorithmIdentifier::SHA_256:
1329 write(CryptoAlgorithmIdentifierTag::SHA_256);
1331 case CryptoAlgorithmIdentifier::SHA_384:
1332 write(CryptoAlgorithmIdentifierTag::SHA_384);
1334 case CryptoAlgorithmIdentifier::SHA_512:
1335 write(CryptoAlgorithmIdentifierTag::SHA_512);
1337 case CryptoAlgorithmIdentifier::HKDF:
1338 write(CryptoAlgorithmIdentifierTag::HKDF);
1340 case CryptoAlgorithmIdentifier::PBKDF2:
1341 write(CryptoAlgorithmIdentifierTag::PBKDF2);
1346 void write(CryptoKeyRSAComponents::Type type)
1349 case CryptoKeyRSAComponents::Type::Public:
1350 write(CryptoKeyAsymmetricTypeSubtag::Public);
1352 case CryptoKeyRSAComponents::Type::Private:
1353 write(CryptoKeyAsymmetricTypeSubtag::Private);
1358 void write(const CryptoKeyRSAComponents& key)
1361 write(key.modulus());
1362 write(key.exponent());
1363 if (key.type() == CryptoKeyRSAComponents::Type::Public)
1366 write(key.privateExponent());
1368 unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
1373 write(key.firstPrimeInfo().primeFactor);
1374 write(key.firstPrimeInfo().factorCRTExponent);
1375 write(key.secondPrimeInfo().primeFactor);
1376 write(key.secondPrimeInfo().factorCRTExponent);
1377 write(key.secondPrimeInfo().factorCRTCoefficient);
1378 for (unsigned i = 2; i < primeCount; ++i) {
1379 write(key.otherPrimeInfos()[i].primeFactor);
1380 write(key.otherPrimeInfos()[i].factorCRTExponent);
1381 write(key.otherPrimeInfos()[i].factorCRTCoefficient);
1385 void write(const CryptoKey* key)
1387 write(currentKeyFormatVersion);
1389 write(key->extractable());
1391 CryptoKeyUsageBitmap usages = key->usagesBitmap();
1392 write(countUsages(usages));
1393 if (usages & CryptoKeyUsageEncrypt)
1394 write(CryptoKeyUsageTag::Encrypt);
1395 if (usages & CryptoKeyUsageDecrypt)
1396 write(CryptoKeyUsageTag::Decrypt);
1397 if (usages & CryptoKeyUsageSign)
1398 write(CryptoKeyUsageTag::Sign);
1399 if (usages & CryptoKeyUsageVerify)
1400 write(CryptoKeyUsageTag::Verify);
1401 if (usages & CryptoKeyUsageDeriveKey)
1402 write(CryptoKeyUsageTag::DeriveKey);
1403 if (usages & CryptoKeyUsageDeriveBits)
1404 write(CryptoKeyUsageTag::DeriveBits);
1405 if (usages & CryptoKeyUsageWrapKey)
1406 write(CryptoKeyUsageTag::WrapKey);
1407 if (usages & CryptoKeyUsageUnwrapKey)
1408 write(CryptoKeyUsageTag::UnwrapKey);
1410 switch (key->keyClass()) {
1411 case CryptoKeyClass::HMAC:
1412 write(CryptoKeyClassSubtag::HMAC);
1413 write(downcast<CryptoKeyHMAC>(*key).key());
1414 write(downcast<CryptoKeyHMAC>(*key).hashAlgorithmIdentifier());
1416 case CryptoKeyClass::AES:
1417 write(CryptoKeyClassSubtag::AES);
1418 write(key->algorithmIdentifier());
1419 write(downcast<CryptoKeyAES>(*key).key());
1421 case CryptoKeyClass::EC:
1422 write(CryptoKeyClassSubtag::EC);
1423 write(key->algorithmIdentifier());
1424 write(downcast<CryptoKeyEC>(*key).namedCurveString());
1425 switch (key->type()) {
1426 case CryptoKey::Type::Public: {
1427 write(CryptoKeyAsymmetricTypeSubtag::Public);
1428 auto result = downcast<CryptoKeyEC>(*key).exportRaw();
1429 ASSERT(!result.hasException());
1430 write(result.releaseReturnValue());
1433 case CryptoKey::Type::Private: {
1434 write(CryptoKeyAsymmetricTypeSubtag::Private);
1435 // Use the standard complied method is not very efficient, but simple/reliable.
1436 auto result = downcast<CryptoKeyEC>(*key).exportPkcs8();
1437 ASSERT(!result.hasException());
1438 write(result.releaseReturnValue());
1442 ASSERT_NOT_REACHED();
1445 case CryptoKeyClass::Raw:
1446 write(CryptoKeyClassSubtag::Raw);
1447 write(key->algorithmIdentifier());
1448 write(downcast<CryptoKeyRaw>(*key).key());
1450 case CryptoKeyClass::RSA:
1451 write(CryptoKeyClassSubtag::RSA);
1452 write(key->algorithmIdentifier());
1453 CryptoAlgorithmIdentifier hash;
1454 bool isRestrictedToHash = downcast<CryptoKeyRSA>(*key).isRestrictedToHash(hash);
1455 write(isRestrictedToHash);
1456 if (isRestrictedToHash)
1458 write(*downcast<CryptoKeyRSA>(*key).exportData());
1464 void write(const uint8_t* data, unsigned length)
1466 m_buffer.append(data, length);
1469 Vector<uint8_t>& m_buffer;
1470 Vector<String>& m_blobURLs;
1471 PAL::SessionID m_sessionID;
1472 ObjectPool m_objectPool;
1473 ObjectPool m_transferredMessagePorts;
1474 ObjectPool m_transferredArrayBuffers;
1475 ObjectPool m_transferredImageBitmaps;
1476 typedef HashMap<RefPtr<UniquedStringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
1477 StringConstantPool m_constantPool;
1478 Identifier m_emptyIdentifier;
1479 SerializationContext m_context;
1480 ArrayBufferContentsArray& m_sharedBuffers;
1481 #if ENABLE(WEBASSEMBLY)
1482 WasmModuleArray& m_wasmModules;
1486 SerializationReturnCode CloneSerializer::serialize(JSValue in)
1488 VM& vm = m_exec->vm();
1489 Vector<uint32_t, 16> indexStack;
1490 Vector<uint32_t, 16> lengthStack;
1491 Vector<PropertyNameArray, 16> propertyStack;
1492 Vector<JSObject*, 32> inputObjectStack;
1493 Vector<JSMapIterator*, 4> mapIteratorStack;
1494 Vector<JSSetIterator*, 4> setIteratorStack;
1495 Vector<JSValue, 4> mapIteratorValueStack;
1496 Vector<WalkerState, 16> stateStack;
1497 WalkerState state = StateUnknown;
1498 JSValue inValue = in;
1502 case ArrayStartState: {
1503 ASSERT(isArray(vm, inValue));
1504 if (inputObjectStack.size() > maximumFilterRecursion)
1505 return SerializationReturnCode::StackOverflowError;
1507 JSArray* inArray = asArray(inValue);
1508 unsigned length = inArray->length();
1509 if (!startArray(inArray))
1511 inputObjectStack.append(inArray);
1512 indexStack.append(0);
1513 lengthStack.append(length);
1515 arrayStartVisitMember:
1517 case ArrayStartVisitMember: {
1518 JSObject* array = inputObjectStack.last();
1519 uint32_t index = indexStack.last();
1520 if (index == lengthStack.last()) {
1521 indexStack.removeLast();
1522 lengthStack.removeLast();
1524 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1525 array->methodTable(vm)->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), EnumerationMode());
1526 if (propertyStack.last().size()) {
1527 write(NonIndexPropertiesTag);
1528 indexStack.append(0);
1529 goto objectStartVisitMember;
1531 propertyStack.removeLast();
1534 inputObjectStack.removeLast();
1537 inValue = array->getDirectIndex(m_exec, index);
1539 indexStack.last()++;
1540 goto arrayStartVisitMember;
1544 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1545 if (dumpIfTerminal(inValue, terminalCode)) {
1546 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1547 return terminalCode;
1548 indexStack.last()++;
1549 goto arrayStartVisitMember;
1551 stateStack.append(ArrayEndVisitMember);
1554 case ArrayEndVisitMember: {
1555 indexStack.last()++;
1556 goto arrayStartVisitMember;
1559 case ObjectStartState: {
1560 ASSERT(inValue.isObject());
1561 if (inputObjectStack.size() > maximumFilterRecursion)
1562 return SerializationReturnCode::StackOverflowError;
1563 JSObject* inObject = asObject(inValue);
1564 if (!startObject(inObject))
1566 // At this point, all supported objects other than Object
1567 // objects have been handled. If we reach this point and
1568 // the input is not an Object object then we should throw
1569 // a DataCloneError.
1570 if (inObject->classInfo(vm) != JSFinalObject::info())
1571 return SerializationReturnCode::DataCloneError;
1572 inputObjectStack.append(inObject);
1573 indexStack.append(0);
1574 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1575 inObject->methodTable(vm)->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), EnumerationMode());
1577 objectStartVisitMember:
1579 case ObjectStartVisitMember: {
1580 JSObject* object = inputObjectStack.last();
1581 uint32_t index = indexStack.last();
1582 PropertyNameArray& properties = propertyStack.last();
1583 if (index == properties.size()) {
1585 inputObjectStack.removeLast();
1586 indexStack.removeLast();
1587 propertyStack.removeLast();
1590 inValue = getProperty(vm, object, properties[index]);
1591 if (shouldTerminate())
1592 return SerializationReturnCode::ExistingExceptionError;
1595 // Property was removed during serialisation
1596 indexStack.last()++;
1597 goto objectStartVisitMember;
1599 write(properties[index]);
1601 if (shouldTerminate())
1602 return SerializationReturnCode::ExistingExceptionError;
1604 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1605 if (!dumpIfTerminal(inValue, terminalCode)) {
1606 stateStack.append(ObjectEndVisitMember);
1609 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1610 return terminalCode;
1613 case ObjectEndVisitMember: {
1614 if (shouldTerminate())
1615 return SerializationReturnCode::ExistingExceptionError;
1617 indexStack.last()++;
1618 goto objectStartVisitMember;
1621 ASSERT(inValue.isObject());
1622 if (inputObjectStack.size() > maximumFilterRecursion)
1623 return SerializationReturnCode::StackOverflowError;
1624 JSMap* inMap = jsCast<JSMap*>(inValue);
1625 if (!startMap(inMap))
1627 JSMapIterator* iterator = JSMapIterator::create(vm, vm.mapIteratorStructure(), inMap, IterateKeyValue);
1628 m_gcBuffer.appendWithCrashOnOverflow(inMap);
1629 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1630 mapIteratorStack.append(iterator);
1631 inputObjectStack.append(inMap);
1632 goto mapDataStartVisitEntry;
1634 mapDataStartVisitEntry:
1635 case MapDataStartVisitEntry: {
1636 JSMapIterator* iterator = mapIteratorStack.last();
1638 if (!iterator->nextKeyValue(m_exec, key, value)) {
1639 mapIteratorStack.removeLast();
1640 JSObject* object = inputObjectStack.last();
1641 ASSERT(jsDynamicCast<JSMap*>(vm, object));
1642 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1643 object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1644 write(NonMapPropertiesTag);
1645 indexStack.append(0);
1646 goto objectStartVisitMember;
1649 m_gcBuffer.appendWithCrashOnOverflow(value);
1650 mapIteratorValueStack.append(value);
1651 stateStack.append(MapDataEndVisitKey);
1654 case MapDataEndVisitKey: {
1655 inValue = mapIteratorValueStack.last();
1656 mapIteratorValueStack.removeLast();
1657 stateStack.append(MapDataEndVisitValue);
1660 case MapDataEndVisitValue: {
1661 goto mapDataStartVisitEntry;
1665 ASSERT(inValue.isObject());
1666 if (inputObjectStack.size() > maximumFilterRecursion)
1667 return SerializationReturnCode::StackOverflowError;
1668 JSSet* inSet = jsCast<JSSet*>(inValue);
1669 if (!startSet(inSet))
1671 JSSetIterator* iterator = JSSetIterator::create(vm, vm.setIteratorStructure(), inSet, IterateKey);
1672 m_gcBuffer.appendWithCrashOnOverflow(inSet);
1673 m_gcBuffer.appendWithCrashOnOverflow(iterator);
1674 setIteratorStack.append(iterator);
1675 inputObjectStack.append(inSet);
1676 goto setDataStartVisitEntry;
1678 setDataStartVisitEntry:
1679 case SetDataStartVisitEntry: {
1680 JSSetIterator* iterator = setIteratorStack.last();
1682 if (!iterator->next(m_exec, key)) {
1683 setIteratorStack.removeLast();
1684 JSObject* object = inputObjectStack.last();
1685 ASSERT(jsDynamicCast<JSSet*>(vm, object));
1686 propertyStack.append(PropertyNameArray(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude));
1687 object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
1688 write(NonSetPropertiesTag);
1689 indexStack.append(0);
1690 goto objectStartVisitMember;
1693 stateStack.append(SetDataEndVisitKey);
1696 case SetDataEndVisitKey: {
1697 goto setDataStartVisitEntry;
1701 case StateUnknown: {
1702 auto terminalCode = SerializationReturnCode::SuccessfullyCompleted;
1703 if (dumpIfTerminal(inValue, terminalCode)) {
1704 if (terminalCode != SerializationReturnCode::SuccessfullyCompleted)
1705 return terminalCode;
1709 if (isArray(vm, inValue))
1710 goto arrayStartState;
1711 if (isMap(vm, inValue))
1713 if (isSet(vm, inValue))
1715 goto objectStartState;
1718 if (stateStack.isEmpty())
1721 state = stateStack.last();
1722 stateStack.removeLast();
1725 return SerializationReturnCode::UnspecifiedError;
1727 return SerializationReturnCode::SuccessfullyCompleted;
1730 class CloneDeserializer : CloneBase {
1732 static String deserializeString(const Vector<uint8_t>& buffer)
1734 if (buffer.isEmpty())
1736 const uint8_t* ptr = buffer.begin();
1737 const uint8_t* end = buffer.end();
1739 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1742 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1745 if (!readLittleEndian(ptr, end, length))
1747 bool is8Bit = length & StringDataIs8BitFlag;
1748 length &= ~StringDataIs8BitFlag;
1750 if (!readString(ptr, end, str, length, is8Bit))
1755 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 PAL::SessionID& sessionID, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
1756 #if ENABLE(WEBASSEMBLY)
1757 , WasmModuleArray* wasmModules
1762 return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
1763 CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, sessionID, blobFilePaths, sharedBuffers, WTFMove(imageBuffers)
1764 #if ENABLE(WEBASSEMBLY)
1768 if (!deserializer.isValid())
1769 return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
1770 return deserializer.deserialize();
1774 struct CachedString {
1775 CachedString(const String& string)
1780 JSValue jsString(ExecState* exec)
1783 m_jsString = JSC::jsString(exec, m_string);
1786 const String& string() { return m_string; }
1787 String takeString() { return WTFMove(m_string); }
1794 struct CachedStringRef {
1800 CachedStringRef(Vector<CachedString>* base, size_t index)
1806 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1809 Vector<CachedString>* m_base;
1813 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers,
1814 #if ENABLE(WEBASSEMBLY)
1815 WasmModuleArray* wasmModules,
1817 const Vector<uint8_t>& buffer)
1819 , m_globalObject(globalObject)
1820 , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1821 , m_ptr(buffer.data())
1822 , m_end(buffer.data() + buffer.size())
1823 , m_version(0xFFFFFFFF)
1824 , m_messagePorts(messagePorts)
1825 , m_arrayBufferContents(arrayBufferContents)
1826 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1827 , m_imageBuffers(WTFMove(imageBuffers))
1828 , m_imageBitmaps(m_imageBuffers.size())
1829 #if ENABLE(WEBASSEMBLY)
1830 , m_wasmModules(wasmModules)
1833 if (!read(m_version))
1834 m_version = 0xFFFFFFFF;
1837 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers
1838 #if ENABLE(WEBASSEMBLY)
1839 , WasmModuleArray* wasmModules
1843 , m_globalObject(globalObject)
1844 , m_isDOMGlobalObject(globalObject->inherits<JSDOMGlobalObject>(globalObject->vm()))
1845 , m_ptr(buffer.data())
1846 , m_end(buffer.data() + buffer.size())
1847 , m_version(0xFFFFFFFF)
1848 , m_messagePorts(messagePorts)
1849 , m_arrayBufferContents(arrayBufferContents)
1850 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
1851 , m_blobURLs(blobURLs)
1852 , m_sessionID(sessionID)
1853 , m_blobFilePaths(blobFilePaths)
1854 , m_sharedBuffers(sharedBuffers)
1855 , m_imageBuffers(WTFMove(imageBuffers))
1856 , m_imageBitmaps(m_imageBuffers.size())
1857 #if ENABLE(WEBASSEMBLY)
1858 , m_wasmModules(wasmModules)
1861 if (!read(m_version))
1862 m_version = 0xFFFFFFFF;
1865 DeserializationResult deserialize();
1867 bool isValid() const { return m_version <= CurrentVersion; }
1869 template <typename T> bool readLittleEndian(T& value)
1871 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1877 #if ASSUME_LITTLE_ENDIAN
1878 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1880 if (ptr > end - sizeof(value))
1886 value = *reinterpret_cast<const T*>(ptr);
1892 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
1894 if (ptr > end - sizeof(value))
1901 for (unsigned i = 0; i < sizeof(T); i++)
1902 value += ((T)*ptr++) << (i * 8);
1908 bool read(uint32_t& i)
1910 return readLittleEndian(i);
1913 bool read(int32_t& i)
1915 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1918 bool read(uint16_t& i)
1920 return readLittleEndian(i);
1923 bool read(uint8_t& i)
1925 return readLittleEndian(i);
1928 bool read(double& d)
1934 if (!readLittleEndian(u.i64))
1940 bool read(unsigned long long& i)
1942 return readLittleEndian(i);
1945 bool readStringIndex(uint32_t& i)
1947 return readConstantPoolIndex(m_constantPool, i);
1950 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1952 if (constantPool.size() <= 0xFF) {
1959 if (constantPool.size() <= 0xFFFF) {
1969 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit)
1971 if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar))
1975 if ((end - ptr) < static_cast<int>(length))
1977 str = String(reinterpret_cast<const LChar*>(ptr), length);
1982 unsigned size = length * sizeof(UChar);
1983 if ((end - ptr) < static_cast<int>(size))
1986 #if ASSUME_LITTLE_ENDIAN
1987 str = String(reinterpret_cast<const UChar*>(ptr), length);
1988 ptr += length * sizeof(UChar);
1990 Vector<UChar> buffer;
1991 buffer.reserveCapacity(length);
1992 for (unsigned i = 0; i < length; i++) {
1994 readLittleEndian(ptr, end, ch);
1997 str = String::adopt(WTFMove(buffer));
2002 bool readStringData(CachedStringRef& cachedString)
2005 return readStringData(cachedString, scratch);
2008 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
2012 uint32_t length = 0;
2015 if (length == TerminatorTag) {
2016 wasTerminator = true;
2019 if (length == StringPoolTag) {
2021 if (!readStringIndex(index)) {
2025 if (index >= m_constantPool.size()) {
2029 cachedString = CachedStringRef(&m_constantPool, index);
2032 bool is8Bit = length & StringDataIs8BitFlag;
2033 length &= ~StringDataIs8BitFlag;
2035 if (!readString(m_ptr, m_end, str, length, is8Bit)) {
2039 m_constantPool.append(str);
2040 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
2044 SerializationTag readTag()
2048 return static_cast<SerializationTag>(*m_ptr++);
2051 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
2055 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
2059 void putProperty(JSObject* object, unsigned index, JSValue value)
2061 object->putDirectIndex(m_exec, index, value);
2064 void putProperty(JSObject* object, const Identifier& property, JSValue value)
2066 object->putDirectMayBeIndex(m_exec, property, value);
2069 bool readFile(RefPtr<File>& file)
2071 CachedStringRef path;
2072 if (!readStringData(path))
2074 CachedStringRef url;
2075 if (!readStringData(url))
2077 CachedStringRef type;
2078 if (!readStringData(type))
2080 CachedStringRef name;
2081 if (!readStringData(name))
2083 Optional<int64_t> optionalLastModified;
2084 if (m_version > 6) {
2085 double lastModified;
2086 if (!read(lastModified))
2088 if (lastModified >= 0)
2089 optionalLastModified = lastModified;
2092 // If the blob URL for this file has an associated blob file path, prefer that one over the "built-in" path.
2093 String filePath = blobFilePathForBlobURL(url->string());
2094 if (filePath.isEmpty())
2095 filePath = path->string();
2097 if (m_isDOMGlobalObject)
2098 file = File::deserialize(jsCast<JSDOMGlobalObject*>(m_globalObject)->scriptExecutionContext()->sessionID(), filePath, URL(URL(), url->string()), type->string(), name->string(), optionalLastModified);
2102 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
2107 if (m_ptr + length > m_end)
2109 arrayBuffer = ArrayBuffer::create(m_ptr, length);
2114 bool readArrayBufferView(VM& vm, JSValue& arrayBufferView)
2116 ArrayBufferViewSubtag arrayBufferViewSubtag;
2117 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
2119 uint32_t byteOffset;
2120 if (!read(byteOffset))
2122 uint32_t byteLength;
2123 if (!read(byteLength))
2125 JSObject* arrayBufferObj = asObject(readTerminal());
2126 if (!arrayBufferObj || !arrayBufferObj->inherits<JSArrayBuffer>(vm))
2129 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
2132 unsigned length = byteLength / elementSize;
2133 if (length * elementSize != byteLength)
2136 RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(vm, arrayBufferObj);
2137 switch (arrayBufferViewSubtag) {
2139 arrayBufferView = toJS(m_exec, m_globalObject, DataView::create(WTFMove(arrayBuffer), byteOffset, length).get());
2142 arrayBufferView = toJS(m_exec, m_globalObject, Int8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2145 arrayBufferView = toJS(m_exec, m_globalObject, Uint8Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2147 case Uint8ClampedArrayTag:
2148 arrayBufferView = toJS(m_exec, m_globalObject, Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2151 arrayBufferView = toJS(m_exec, m_globalObject, Int16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2153 case Uint16ArrayTag:
2154 arrayBufferView = toJS(m_exec, m_globalObject, Uint16Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2157 arrayBufferView = toJS(m_exec, m_globalObject, Int32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2159 case Uint32ArrayTag:
2160 arrayBufferView = toJS(m_exec, m_globalObject, Uint32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2162 case Float32ArrayTag:
2163 arrayBufferView = toJS(m_exec, m_globalObject, Float32Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2165 case Float64ArrayTag:
2166 arrayBufferView = toJS(m_exec, m_globalObject, Float64Array::tryCreate(WTFMove(arrayBuffer), byteOffset, length).get());
2173 bool read(Vector<uint8_t>& result)
2175 ASSERT(result.isEmpty());
2179 if (m_ptr + size > m_end)
2181 result.append(m_ptr, size);
2186 #if ENABLE(WEB_CRYPTO)
2187 bool read(CryptoAlgorithmIdentifier& result)
2189 uint8_t algorithmTag;
2190 if (!read(algorithmTag))
2192 if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
2194 switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
2195 case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
2196 result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
2198 case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
2199 result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
2201 case CryptoAlgorithmIdentifierTag::RSA_PSS:
2202 result = CryptoAlgorithmIdentifier::RSA_PSS;
2204 case CryptoAlgorithmIdentifierTag::RSA_OAEP:
2205 result = CryptoAlgorithmIdentifier::RSA_OAEP;
2207 case CryptoAlgorithmIdentifierTag::ECDSA:
2208 result = CryptoAlgorithmIdentifier::ECDSA;
2210 case CryptoAlgorithmIdentifierTag::ECDH:
2211 result = CryptoAlgorithmIdentifier::ECDH;
2213 case CryptoAlgorithmIdentifierTag::AES_CTR:
2214 result = CryptoAlgorithmIdentifier::AES_CTR;
2216 case CryptoAlgorithmIdentifierTag::AES_CBC:
2217 result = CryptoAlgorithmIdentifier::AES_CBC;
2219 case CryptoAlgorithmIdentifierTag::AES_GCM:
2220 result = CryptoAlgorithmIdentifier::AES_GCM;
2222 case CryptoAlgorithmIdentifierTag::AES_CFB:
2223 result = CryptoAlgorithmIdentifier::AES_CFB;
2225 case CryptoAlgorithmIdentifierTag::AES_KW:
2226 result = CryptoAlgorithmIdentifier::AES_KW;
2228 case CryptoAlgorithmIdentifierTag::HMAC:
2229 result = CryptoAlgorithmIdentifier::HMAC;
2231 case CryptoAlgorithmIdentifierTag::SHA_1:
2232 result = CryptoAlgorithmIdentifier::SHA_1;
2234 case CryptoAlgorithmIdentifierTag::SHA_224:
2235 result = CryptoAlgorithmIdentifier::SHA_224;
2237 case CryptoAlgorithmIdentifierTag::SHA_256:
2238 result = CryptoAlgorithmIdentifier::SHA_256;
2240 case CryptoAlgorithmIdentifierTag::SHA_384:
2241 result = CryptoAlgorithmIdentifier::SHA_384;
2243 case CryptoAlgorithmIdentifierTag::SHA_512:
2244 result = CryptoAlgorithmIdentifier::SHA_512;
2246 case CryptoAlgorithmIdentifierTag::HKDF:
2247 result = CryptoAlgorithmIdentifier::HKDF;
2249 case CryptoAlgorithmIdentifierTag::PBKDF2:
2250 result = CryptoAlgorithmIdentifier::PBKDF2;
2256 bool read(CryptoKeyClassSubtag& result)
2261 if (tag > cryptoKeyClassSubtagMaximumValue)
2263 result = static_cast<CryptoKeyClassSubtag>(tag);
2267 bool read(CryptoKeyUsageTag& result)
2272 if (tag > cryptoKeyUsageTagMaximumValue)
2274 result = static_cast<CryptoKeyUsageTag>(tag);
2278 bool read(CryptoKeyAsymmetricTypeSubtag& result)
2283 if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
2285 result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
2289 bool readHMACKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2291 Vector<uint8_t> keyData;
2294 CryptoAlgorithmIdentifier hash;
2297 result = CryptoKeyHMAC::importRaw(0, hash, WTFMove(keyData), extractable, usages);
2301 bool readAESKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2303 CryptoAlgorithmIdentifier algorithm;
2304 if (!read(algorithm))
2306 if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
2308 Vector<uint8_t> keyData;
2311 result = CryptoKeyAES::importRaw(algorithm, WTFMove(keyData), extractable, usages);
2315 bool readRSAKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2317 CryptoAlgorithmIdentifier algorithm;
2318 if (!read(algorithm))
2321 int32_t isRestrictedToHash;
2322 CryptoAlgorithmIdentifier hash;
2323 if (!read(isRestrictedToHash))
2325 if (isRestrictedToHash && !read(hash))
2328 CryptoKeyAsymmetricTypeSubtag type;
2332 Vector<uint8_t> modulus;
2335 Vector<uint8_t> exponent;
2336 if (!read(exponent))
2339 if (type == CryptoKeyAsymmetricTypeSubtag::Public) {
2340 auto keyData = CryptoKeyRSAComponents::createPublic(modulus, exponent);
2341 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2342 result = WTFMove(key);
2346 Vector<uint8_t> privateExponent;
2347 if (!read(privateExponent))
2350 uint32_t primeCount;
2351 if (!read(primeCount))
2355 auto keyData = CryptoKeyRSAComponents::createPrivate(modulus, exponent, privateExponent);
2356 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2357 result = WTFMove(key);
2364 CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
2365 CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
2366 Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
2368 if (!read(firstPrimeInfo.primeFactor))
2370 if (!read(firstPrimeInfo.factorCRTExponent))
2372 if (!read(secondPrimeInfo.primeFactor))
2374 if (!read(secondPrimeInfo.factorCRTExponent))
2376 if (!read(secondPrimeInfo.factorCRTCoefficient))
2378 for (unsigned i = 2; i < primeCount; ++i) {
2379 if (!read(otherPrimeInfos[i].primeFactor))
2381 if (!read(otherPrimeInfos[i].factorCRTExponent))
2383 if (!read(otherPrimeInfos[i].factorCRTCoefficient))
2387 auto keyData = CryptoKeyRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
2388 auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages);
2389 result = WTFMove(key);
2393 bool readECKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2395 CryptoAlgorithmIdentifier algorithm;
2396 if (!read(algorithm))
2398 if (!CryptoKeyEC::isValidECAlgorithm(algorithm))
2400 CachedStringRef curve;
2401 if (!readStringData(curve))
2403 CryptoKeyAsymmetricTypeSubtag type;
2406 Vector<uint8_t> keyData;
2411 case CryptoKeyAsymmetricTypeSubtag::Public:
2412 result = CryptoKeyEC::importRaw(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2414 case CryptoKeyAsymmetricTypeSubtag::Private:
2415 result = CryptoKeyEC::importPkcs8(algorithm, curve->string(), WTFMove(keyData), extractable, usages);
2422 bool readRawKey(CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result)
2424 CryptoAlgorithmIdentifier algorithm;
2425 if (!read(algorithm))
2427 Vector<uint8_t> keyData;
2430 result = CryptoKeyRaw::create(algorithm, WTFMove(keyData), usages);
2434 bool readCryptoKey(JSValue& cryptoKey)
2436 uint32_t keyFormatVersion;
2437 if (!read(keyFormatVersion) || keyFormatVersion > currentKeyFormatVersion)
2440 int32_t extractable;
2441 if (!read(extractable))
2444 uint32_t usagesCount;
2445 if (!read(usagesCount))
2448 CryptoKeyUsageBitmap usages = 0;
2449 for (uint32_t i = 0; i < usagesCount; ++i) {
2450 CryptoKeyUsageTag usage;
2454 case CryptoKeyUsageTag::Encrypt:
2455 usages |= CryptoKeyUsageEncrypt;
2457 case CryptoKeyUsageTag::Decrypt:
2458 usages |= CryptoKeyUsageDecrypt;
2460 case CryptoKeyUsageTag::Sign:
2461 usages |= CryptoKeyUsageSign;
2463 case CryptoKeyUsageTag::Verify:
2464 usages |= CryptoKeyUsageVerify;
2466 case CryptoKeyUsageTag::DeriveKey:
2467 usages |= CryptoKeyUsageDeriveKey;
2469 case CryptoKeyUsageTag::DeriveBits:
2470 usages |= CryptoKeyUsageDeriveBits;
2472 case CryptoKeyUsageTag::WrapKey:
2473 usages |= CryptoKeyUsageWrapKey;
2475 case CryptoKeyUsageTag::UnwrapKey:
2476 usages |= CryptoKeyUsageUnwrapKey;
2481 CryptoKeyClassSubtag cryptoKeyClass;
2482 if (!read(cryptoKeyClass))
2484 RefPtr<CryptoKey> result;
2485 switch (cryptoKeyClass) {
2486 case CryptoKeyClassSubtag::HMAC:
2487 if (!readHMACKey(extractable, usages, result))
2490 case CryptoKeyClassSubtag::AES:
2491 if (!readAESKey(extractable, usages, result))
2494 case CryptoKeyClassSubtag::RSA:
2495 if (!readRSAKey(extractable, usages, result))
2498 case CryptoKeyClassSubtag::EC:
2499 if (!readECKey(extractable, usages, result))
2502 case CryptoKeyClassSubtag::Raw:
2503 if (!readRawKey(usages, result))
2507 cryptoKey = getJSValue(result.get());
2513 JSValue getJSValue(T* nativeObj)
2515 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2519 JSValue getJSValue(T& nativeObj)
2521 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
2525 JSValue readDOMPoint()
2540 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, z, w));
2544 JSValue readDOMMatrix()
2570 TransformationMatrix matrix(m11, m12, m21, m22, m41, m42);
2571 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::Yes));
2622 TransformationMatrix matrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
2623 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(WTFMove(matrix), DOMMatrixReadOnly::Is2D::No));
2628 JSValue readDOMRect()
2643 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), T::create(x, y, width, height));
2646 Optional<DOMPointInit> readDOMPointInit()
2650 return WTF::nullopt;
2652 return WTF::nullopt;
2654 return WTF::nullopt;
2656 return WTF::nullopt;
2661 JSValue readDOMQuad()
2663 auto p1 = readDOMPointInit();
2666 auto p2 = readDOMPointInit();
2669 auto p3 = readDOMPointInit();
2672 auto p4 = readDOMPointInit();
2676 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), DOMQuad::create(p1.value(), p2.value(), p3.value(), p4.value()));
2679 JSValue readImageBitmap()
2682 bool indexSuccessfullyRead = read(index);
2683 if (!indexSuccessfullyRead || index >= m_imageBuffers.size()) {
2688 if (!m_imageBitmaps[index])
2689 m_imageBitmaps[index] = ImageBitmap::create(WTFMove(m_imageBuffers.at(index)));
2691 auto bitmap = m_imageBitmaps[index].get();
2692 return getJSValue(bitmap);
2696 JSValue readRTCCertificate()
2699 if (!read(expires)) {
2703 CachedStringRef certificate;
2704 if (!readStringData(certificate)) {
2708 CachedStringRef origin;
2709 if (!readStringData(origin)) {
2713 CachedStringRef keyedMaterial;
2714 if (!readStringData(keyedMaterial)) {
2722 Vector<RTCCertificate::DtlsFingerprint> fingerprints;
2723 fingerprints.reserveInitialCapacity(size);
2724 for (unsigned i = 0; i < size; i++) {
2725 CachedStringRef algorithm;
2726 if (!readStringData(algorithm))
2728 CachedStringRef value;
2729 if (!readStringData(value))
2731 fingerprints.uncheckedAppend(RTCCertificate::DtlsFingerprint { algorithm->string(), value->string() });
2734 if (!m_isDOMGlobalObject)
2735 return constructEmptyObject(m_exec, m_globalObject->objectPrototype());
2737 auto rtcCertificate = RTCCertificate::create(SecurityOrigin::createFromString(origin->string()), expires, WTFMove(fingerprints), certificate->takeString(), keyedMaterial->takeString());
2738 return toJSNewlyCreated(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), WTFMove(rtcCertificate));
2742 JSValue readTerminal()
2744 SerializationTag tag = readTag();
2747 return jsUndefined();
2761 return jsBoolean(false);
2763 return jsBoolean(true);
2764 case FalseObjectTag: {
2765 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2766 obj->setInternalValue(m_exec->vm(), jsBoolean(false));
2767 m_gcBuffer.appendWithCrashOnOverflow(obj);
2770 case TrueObjectTag: {
2771 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2772 obj->setInternalValue(m_exec->vm(), jsBoolean(true));
2773 m_gcBuffer.appendWithCrashOnOverflow(obj);
2782 case NumberObjectTag: {
2786 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
2787 m_gcBuffer.appendWithCrashOnOverflow(obj);
2794 return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
2798 if (!readFile(file))
2800 if (!m_isDOMGlobalObject)
2802 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
2805 unsigned length = 0;
2808 Vector<Ref<File>> files;
2809 for (unsigned i = 0; i < length; i++) {
2811 if (!readFile(file))
2813 if (m_isDOMGlobalObject)
2814 files.append(file.releaseNonNull());
2816 if (!m_isDOMGlobalObject)
2818 return getJSValue(FileList::create(WTFMove(files)).get());
2820 case ImageDataTag: {
2830 if (static_cast<uint32_t>(m_end - m_ptr) < length) {
2834 if (!m_isDOMGlobalObject) {
2838 IntSize imageSize(width, height);
2839 RELEASE_ASSERT(!length || (imageSize.area() * 4).unsafeGet() <= length);
2840 auto result = ImageData::create(imageSize);
2846 memcpy(result->data()->data(), m_ptr, length);
2848 result->data()->zeroFill();
2850 return getJSValue(result.get());
2853 CachedStringRef url;
2854 if (!readStringData(url))
2856 CachedStringRef type;
2857 if (!readStringData(type))
2859 unsigned long long size = 0;
2862 if (!m_isDOMGlobalObject)
2864 return getJSValue(Blob::deserialize(jsCast<JSDOMGlobalObject*>(m_globalObject)->scriptExecutionContext()->sessionID(), URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get());
2867 CachedStringRef cachedString;
2868 if (!readStringData(cachedString))
2870 return cachedString->jsString(m_exec);
2872 case EmptyStringTag:
2873 return jsEmptyString(&m_exec->vm());
2874 case StringObjectTag: {
2875 CachedStringRef cachedString;
2876 if (!readStringData(cachedString))
2878 StringObject* obj = constructString(m_exec->vm(), m_globalObject, cachedString->jsString(m_exec));
2879 m_gcBuffer.appendWithCrashOnOverflow(obj);
2882 case EmptyStringObjectTag: {
2883 VM& vm = m_exec->vm();
2884 StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(&vm));
2885 m_gcBuffer.appendWithCrashOnOverflow(obj);
2889 CachedStringRef pattern;
2890 if (!readStringData(pattern))
2892 CachedStringRef flags;
2893 if (!readStringData(flags))
2895 auto reFlags = Yarr::parseFlags(flags->string());
2896 ASSERT(reFlags.hasValue());
2897 VM& vm = m_exec->vm();
2898 RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
2899 return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
2901 case ObjectReferenceTag: {
2903 if (!readConstantPoolIndex(m_gcBuffer, index)) {
2907 return m_gcBuffer.at(index);
2909 case MessagePortReferenceTag: {
2911 bool indexSuccessfullyRead = read(index);
2912 if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
2916 return getJSValue(m_messagePorts[index].get());
2918 #if ENABLE(WEBASSEMBLY)
2919 case WasmModuleTag: {
2921 bool indexSuccessfullyRead = read(index);
2922 if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) {
2926 auto scope = DECLARE_THROW_SCOPE(m_exec->vm());
2927 JSValue result = JSC::JSWebAssemblyModule::createStub(m_exec->vm(), m_exec, m_globalObject->webAssemblyModuleStructure(), m_wasmModules->at(index));
2928 // Since we are cloning a JSWebAssemblyModule, it's impossible for that
2929 // module to not have been a valid module. Therefore, createStub should
2931 scope.releaseAssertNoException();
2932 m_gcBuffer.appendWithCrashOnOverflow(result);
2936 case ArrayBufferTag: {
2937 RefPtr<ArrayBuffer> arrayBuffer;
2938 if (!readArrayBuffer(arrayBuffer)) {
2942 Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
2943 // A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
2944 // array buffers while the sender is. In that case, we would see a null structure here.
2949 JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer));
2950 m_gcBuffer.appendWithCrashOnOverflow(result);
2953 case ArrayBufferTransferTag: {
2955 bool indexSuccessfullyRead = read(index);
2956 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
2961 if (!m_arrayBuffers[index])
2962 m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
2964 return getJSValue(m_arrayBuffers[index].get());
2966 case SharedArrayBufferTag: {
2967 uint32_t index = UINT_MAX;
2968 bool indexSuccessfullyRead = read(index);
2969 if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) {
2974 RELEASE_ASSERT(m_sharedBuffers->at(index));
2975 auto buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index)));
2976 JSValue result = getJSValue(buffer.get());
2977 m_gcBuffer.appendWithCrashOnOverflow(result);
2980 case ArrayBufferViewTag: {
2981 JSValue arrayBufferView;
2982 if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) {
2986 m_gcBuffer.appendWithCrashOnOverflow(arrayBufferView);
2987 return arrayBufferView;
2989 #if ENABLE(WEB_CRYPTO)
2990 case CryptoKeyTag: {
2991 Vector<uint8_t> wrappedKey;
2992 if (!read(wrappedKey)) {
2996 Vector<uint8_t> serializedKey;
2997 if (!unwrapCryptoKey(m_exec, wrappedKey, serializedKey)) {
3002 Vector<RefPtr<MessagePort>> dummyMessagePorts;
3003 CloneDeserializer rawKeyDeserializer(m_exec, m_globalObject, dummyMessagePorts, nullptr, { },
3004 #if ENABLE(WEBASSEMBLY)
3008 if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
3012 m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
3016 case DOMPointReadOnlyTag:
3017 return readDOMPoint<DOMPointReadOnly>();
3019 return readDOMPoint<DOMPoint>();
3020 case DOMRectReadOnlyTag:
3021 return readDOMRect<DOMRectReadOnly>();
3023 return readDOMRect<DOMRect>();
3024 case DOMMatrixReadOnlyTag:
3025 return readDOMMatrix<DOMMatrixReadOnly>();
3027 return readDOMMatrix<DOMMatrix>();
3029 return readDOMQuad();
3030 case ImageBitmapTransferTag:
3031 return readImageBitmap();
3033 case RTCCertificateTag:
3034 return readRTCCertificate();
3038 m_ptr--; // Push the tag back
3043 template<SerializationTag Tag>
3044 bool consumeCollectionDataTerminationIfPossible()
3046 if (readTag() == Tag)
3052 JSGlobalObject* m_globalObject;
3053 bool m_isDOMGlobalObject;
3054 const uint8_t* m_ptr;
3055 const uint8_t* m_end;
3057 Vector<CachedString> m_constantPool;
3058 const Vector<RefPtr<MessagePort>>& m_messagePorts;
3059 ArrayBufferContentsArray* m_arrayBufferContents;
3060 Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers;
3061 Vector<String> m_blobURLs;
3062 PAL::SessionID m_sessionID;
3063 Vector<String> m_blobFilePaths;
3064 ArrayBufferContentsArray* m_sharedBuffers;
3065 Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>> m_imageBuffers;
3066 Vector<RefPtr<ImageBitmap>> m_imageBitmaps;
3067 #if ENABLE(WEBASSEMBLY)
3068 WasmModuleArray* m_wasmModules;
3071 String blobFilePathForBlobURL(const String& blobURL)
3074 for (; i < m_blobURLs.size(); ++i) {
3075 if (m_blobURLs[i] == blobURL)
3079 return i < m_blobURLs.size() ? m_blobFilePaths[i] : String();
3083 DeserializationResult CloneDeserializer::deserialize()
3085 VM& vm = m_exec->vm();
3086 auto scope = DECLARE_THROW_SCOPE(vm);
3088 Vector<uint32_t, 16> indexStack;
3089 Vector<Identifier, 16> propertyNameStack;
3090 Vector<JSObject*, 32> outputObjectStack;
3091 Vector<JSValue, 4> mapKeyStack;
3092 Vector<JSMap*, 4> mapStack;
3093 Vector<JSSet*, 4> setStack;
3094 Vector<WalkerState, 16> stateStack;
3095 WalkerState state = StateUnknown;
3101 case ArrayStartState: {
3103 if (!read(length)) {
3107 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
3108 if (UNLIKELY(scope.exception()))
3110 m_gcBuffer.appendWithCrashOnOverflow(outArray);
3111 outputObjectStack.append(outArray);
3113 arrayStartVisitMember:
3115 case ArrayStartVisitMember: {
3121 if (index == TerminatorTag) {
3122 JSObject* outArray = outputObjectStack.last();
3123 outValue = outArray;
3124 outputObjectStack.removeLast();
3126 } else if (index == NonIndexPropertiesTag) {
3127 goto objectStartVisitMember;
3130 if (JSValue terminal = readTerminal()) {
3131 putProperty(outputObjectStack.last(), index, terminal);
3132 goto arrayStartVisitMember;
3136 indexStack.append(index);
3137 stateStack.append(ArrayEndVisitMember);
3140 case ArrayEndVisitMember: {
3141 JSObject* outArray = outputObjectStack.last();
3142 putProperty(outArray, indexStack.last(), outValue);
3143 indexStack.removeLast();
3144 goto arrayStartVisitMember;
3147 case ObjectStartState: {
3148 if (outputObjectStack.size() > maximumFilterRecursion)
3149 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3150 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
3151 m_gcBuffer.appendWithCrashOnOverflow(outObject);
3152 outputObjectStack.append(outObject);
3154 objectStartVisitMember:
3156 case ObjectStartVisitMember: {
3157 CachedStringRef cachedString;
3158 bool wasTerminator = false;
3159 if (!readStringData(cachedString, wasTerminator)) {
3163 JSObject* outObject = outputObjectStack.last();
3164 outValue = outObject;
3165 outputObjectStack.removeLast();
3169 if (JSValue terminal = readTerminal()) {
3170 putProperty(outputObjectStack.last(), Identifier::fromString(m_exec, cachedString->string()), terminal);
3171 goto objectStartVisitMember;
3173 stateStack.append(ObjectEndVisitMember);
3174 propertyNameStack.append(Identifier::fromString(m_exec, cachedString->string()));
3177 case ObjectEndVisitMember: {
3178 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
3179 propertyNameStack.removeLast();
3180 goto objectStartVisitMember;
3182 mapObjectStartState: {
3183 if (outputObjectStack.size() > maximumFilterRecursion)
3184 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3185 JSMap* map = JSMap::create(m_exec, m_exec->vm(), m_globalObject->mapStructure());
3186 if (UNLIKELY(scope.exception()))
3188 m_gcBuffer.appendWithCrashOnOverflow(map);
3189 outputObjectStack.append(map);
3190 mapStack.append(map);
3191 goto mapDataStartVisitEntry;
3193 mapDataStartVisitEntry:
3194 case MapDataStartVisitEntry: {
3195 if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) {
3196 mapStack.removeLast();
3197 goto objectStartVisitMember;
3199 stateStack.append(MapDataEndVisitKey);
3202 case MapDataEndVisitKey: {
3203 mapKeyStack.append(outValue);
3204 stateStack.append(MapDataEndVisitValue);
3207 case MapDataEndVisitValue: {
3208 mapStack.last()->set(m_exec, mapKeyStack.last(), outValue);
3209 mapKeyStack.removeLast();
3210 goto mapDataStartVisitEntry;
3213 setObjectStartState: {
3214 if (outputObjectStack.size() > maximumFilterRecursion)
3215 return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError);
3216 JSSet* set = JSSet::create(m_exec, m_exec->vm(), m_globalObject->setStructure());
3217 if (UNLIKELY(scope.exception()))
3219 m_gcBuffer.appendWithCrashOnOverflow(set);
3220 outputObjectStack.append(set);
3221 setStack.append(set);
3222 goto setDataStartVisitEntry;
3224 setDataStartVisitEntry:
3225 case SetDataStartVisitEntry: {
3226 if (consumeCollectionDataTerminationIfPossible<NonSetPropertiesTag>()) {
3227 setStack.removeLast();
3228 goto objectStartVisitMember;
3230 stateStack.append(SetDataEndVisitKey);
3233 case SetDataEndVisitKey: {
3234 JSSet* set = setStack.last();
3235 set->add(m_exec, outValue);
3236 goto setDataStartVisitEntry;
3241 if (JSValue terminal = readTerminal()) {
3242 outValue = terminal;
3245 SerializationTag tag = readTag();
3246 if (tag == ArrayTag)
3247 goto arrayStartState;
3248 if (tag == ObjectTag)
3249 goto objectStartState;
3250 if (tag == MapObjectTag)
3251 goto mapObjectStartState;
3252 if (tag == SetObjectTag)
3253 goto setObjectStartState;
3256 if (stateStack.isEmpty())
3259 state = stateStack.last();
3260 stateStack.removeLast();
3264 return std::make_pair(outValue, SerializationReturnCode::SuccessfullyCompleted);
3267 return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
3270 SerializedScriptValue::~SerializedScriptValue() = default;
3272 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer)
3273 : m_data(WTFMove(buffer))
3277 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray)
3278 : m_data(WTFMove(buffer))
3279 , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray))
3283 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray, std::unique_ptr<ArrayBufferContentsArray> sharedBufferContentsArray, Vector<std::pair<std::unique_ptr<ImageBuffer>, bool>>&& imageBuffers
3284 #if ENABLE(WEBASSEMBLY)
3285 , std::unique_ptr<WasmModuleArray> wasmModulesArray
3288 : m_data(WTFMove(buffer))
3289 , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray))
3290 , m_sharedBufferContentsArray(WTFMove(sharedBufferContentsArray))
3291 , m_imageBuffers(WTFMove(imageBuffers))
3292 #if ENABLE(WEBASSEMBLY)
3293 , m_wasmModulesArray(WTFMove(wasmModulesArray))
3295 , m_sessionID(sessionID)
3297 // Since this SerializedScriptValue is meant to be passed between threads, its String data members
3298 // need to be isolatedCopies so we don't run into thread safety issues for the StringImpls.
3299 m_blobURLs.reserveInitialCapacity(blobURLs.size());
3300 for (auto& url : blobURLs)
3301 m_blobURLs.uncheckedAppend(url.isolatedCopy());
3304 static ExceptionOr<std::unique_ptr<ArrayBufferContentsArray>> transferArrayBuffers(VM& vm, const Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers)
3306 if (arrayBuffers.isEmpty())
3309 auto contents = std::make_unique<ArrayBufferContentsArray>(arrayBuffers.size());
3311 HashSet<JSC::ArrayBuffer*> visited;
3312 for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
3313 if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
3315 visited.add(arrayBuffers[arrayBufferIndex].get());
3317 bool result = arrayBuffers[arrayBufferIndex]->transferTo(vm, contents->at(arrayBufferIndex));
3319 return Exception { TypeError };
3325 static void maybeThrowExceptionIfSerializationFailed(ExecState& state, SerializationReturnCode code)
3327 auto& vm = state.vm();
3328 auto scope = DECLARE_THROW_SCOPE(vm);
3331 case SerializationReturnCode::SuccessfullyCompleted:
3333 case SerializationReturnCode::StackOverflowError:
3334 throwException(&state, scope, createStackOverflowError(&state));
3336 case SerializationReturnCode::ValidationError:
3337 throwTypeError(&state, scope, "Unable to deserialize data."_s);
3339 case SerializationReturnCode::DataCloneError:
3340 throwDataCloneError(state, scope);
3342 case SerializationReturnCode::ExistingExceptionError:
3343 case SerializationReturnCode::UnspecifiedError:
3345 case SerializationReturnCode::InterruptedExecutionError:
3346 ASSERT_NOT_REACHED();
3350 static Exception exceptionForSerializationFailure(SerializationReturnCode code)
3352 ASSERT(code != SerializationReturnCode::SuccessfullyCompleted);
3355 case SerializationReturnCode::StackOverflowError:
3356 return Exception { StackOverflowError };
3357 case SerializationReturnCode::ValidationError:
3358 return Exception { TypeError };
3359 case SerializationReturnCode::DataCloneError:
3360 return Exception { DataCloneError };
3361 case SerializationReturnCode::ExistingExceptionError:
3362 return Exception { ExistingExceptionError };
3363 case SerializationReturnCode::UnspecifiedError:
3364 return Exception { TypeError };
3365 case SerializationReturnCode::SuccessfullyCompleted:
3366 case SerializationReturnCode::InterruptedExecutionError:
3367 ASSERT_NOT_REACHED();
3368 return Exception { TypeError };
3370 ASSERT_NOT_REACHED();
3371 return Exception { TypeError };
3374 RefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState& exec, JSValue value, SerializationErrorMode throwExceptions)
3376 Vector<uint8_t> buffer;
3377 Vector<String> blobURLs;
3378 PAL::SessionID sessionID;
3379 Vector<RefPtr<MessagePort>> dummyMessagePorts;
3380 Vector<RefPtr<ImageBitmap>> dummyImageBitmaps;
3381 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
3382 #if ENABLE(WEBASSEMBLY)
3383 WasmModuleArray dummyModules;
3385 ArrayBufferContentsArray dummySharedBuffers;
3386 auto code = CloneSerializer::serialize(&exec, value, dummyMessagePorts, dummyArrayBuffers, dummyImageBitmaps,
3387 #if ENABLE(WEBASSEMBLY)
3390 blobURLs, sessionID, buffer, SerializationContext::Default, dummySharedBuffers);
3392 #if ENABLE(WEBASSEMBLY)
3393 ASSERT_WITH_MESSAGE(dummyModules.isEmpty(), "Wasm::Module serialization is only allowed in the postMessage context");
3396 if (throwExceptions == SerializationErrorMode::Throwing)
3397 maybeThrowExceptionIfSerializationFailed(exec, code);
3399 if (code != SerializationReturnCode::SuccessfullyCompleted)
3402 return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, sessionID, nullptr, nullptr, { }
3403 #if ENABLE(WEBASSEMBLY)
3409 static bool containsDuplicates(const Vector<RefPtr<ImageBitmap>>& imageBitmaps)
3411 HashSet<ImageBitmap*> visited;
3412 for (auto& imageBitmap : imageBitmaps) {
3413 if (!visited.add(imageBitmap.get()))
3419 ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState& state, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationContext context)
3421 VM& vm = state.vm();
3422 Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
3423 Vector<RefPtr<ImageBitmap>> imageBitmaps;
3424 for (auto& transferable : transferList) {
3425 if (auto arrayBuffer = toPossiblySharedArrayBuffer(vm, transferable.get())) {
3426 if (arrayBuffer->isNeutered())
3427 return Exception { DataCloneError };
3428 if (arrayBuffer->isLocked()) {
3429 auto scope = DECLARE_THROW_SCOPE(vm);
3430 throwVMTypeError(&state, scope, errorMesasgeForTransfer(arrayBuffer));
3431 return Exception { ExistingExceptionError };
3433 arrayBuffers.append(WTFMove(arrayBuffer));
3436 if (auto port = JSMessagePort::toWrapped(vm, transferable.get())) {
3437 // FIXME: This should check if the port is detached as per https://html.spec.whatwg.org/multipage/infrastructure.html#istransferable.
3438 messagePorts.append(WTFMove(port));
3442 if (auto imageBitmap = JSImageBitmap::toWrapped(vm, transferable.get())) {
3443 if (imageBitmap->isDetached())
3444 return Exception { DataCloneError };
3446 imageBitmaps.append(WTFMove(imageBitmap));
3450 return Exception { DataCloneError };
3453 if (containsDuplicates(imageBitmaps))
3454 return Exception { DataCloneError };
3456 Vector<uint8_t> buffer;
3457 Vector<String> blobURLs;
3458 PAL::SessionID sessionID;
3459 #if ENABLE(WEBASSEMBLY)
3460 WasmModuleArray wasmModules;
3462 std::unique_ptr<ArrayBufferContentsArray> sharedBuffers = std::make_unique<ArrayBufferContentsArray>();
3463 auto code = CloneSerializer::serialize(&state, value, messagePorts, arrayBuffers, imageBitmaps,
3464 #if ENABLE(WEBASSEMBLY)
3467 blobURLs, sessionID, buffer, context, *sharedBuffers);
3469 if (code != SerializationReturnCode::SuccessfullyCompleted)
3470 return exceptionForSerializationFailure(code);
3472 auto arrayBufferContentsArray = transferArrayBuffers(vm, arrayBuffers);
3473 if (arrayBufferContentsArray.hasException())
3474 return arrayBufferContentsArray.releaseException();
3476 auto imageBuffers = ImageBitmap::detachBitmaps(WTFMove(imageBitmaps));
3478 return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, sessionID, arrayBufferContentsArray.releaseReturnValue(), context == SerializationContext::WorkerPostMessage ? WTFMove(sharedBuffers) : nullptr, WTFMove(imageBuffers)
3479 #if ENABLE(WEBASSEMBLY)
3480 , std::make_unique<WasmModuleArray>(wasmModules)
3485 RefPtr<SerializedScriptValue> SerializedScriptValue::create(StringView string)
3487 Vector<uint8_t> buffer;
3488 if (!CloneSerializer::serialize(string, buffer))
3490 return adoptRef(*new SerializedScriptValue(WTFMove(buffer)));
3493 RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
3495 ExecState* exec = toJS(originContext);
3496 VM& vm = exec->vm();
3497 JSLockHolder locker(vm);
3498 auto scope = DECLARE_CATCH_SCOPE(vm);
3500 JSValue value = toJS(exec, apiValue);
3501 auto serializedValue = SerializedScriptValue::create(*exec, value);
3502 if (UNLIKELY(scope.exception())) {
3504 *exception = toRef(exec, scope.exception()->value());
3505 scope.clearException();
3508 ASSERT(serializedValue);
3509 return serializedValue;
3512 String SerializedScriptValue::toString()
3514 return CloneDeserializer::deserializeString(m_data);
3517 JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions)
3519 return deserialize(exec, globalObject, { }, throwExceptions);
3522 JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, SerializationErrorMode throwExceptions)
3524 Vector<String> dummyBlobs;
3525 Vector<String> dummyPaths;
3526 PAL::SessionID dummySessionID;
3527 return deserialize(exec, globalObject, messagePorts, dummyBlobs, dummySessionID, dummyPaths, throwExceptions);
3530 JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, const Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const PAL::SessionID& sessionID, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions)
3532 DeserializationResult result = CloneDeserializer::deserialize(&exec, globalObject, messagePorts, WTFMove(m_imageBuffers), m_arrayBufferContentsArray.get(), m_data, blobURLs, sessionID, blobFilePaths, m_sharedBufferContentsArray.get()
3533 #if ENABLE(WEBASSEMBLY)
3534 , m_wasmModulesArray.get()
3537 if (throwExceptions == SerializationErrorMode::Throwing)
3538 maybeThrowExceptionIfSerializationFailed(exec, result.second);
3539 return result.first ? result.first : jsNull();
3542 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
3544 ExecState* exec = toJS(destinationContext);
3545 VM& vm = exec->vm();
3546 JSLockHolder locker(vm);
3547 auto scope = DECLARE_CATCH_SCOPE(vm);
3549 JSValue value = deserialize(*exec, exec->lexicalGlobalObject());
3550 if (UNLIKELY(scope.exception())) {
3552 *exception = toRef(exec, scope.exception()->value());
3553 scope.clearException();
3557 return toRef(exec, value);
3560 Ref<SerializedScriptValue> SerializedScriptValue::nullValue()
3562 return adoptRef(*new SerializedScriptValue(Vector<uint8_t>()));
3565 uint32_t SerializedScriptValue::wireFormatVersion()
3567 return CurrentVersion;
3570 #if ENABLE(INDEXED_DATABASE)
3571 Vector<String> SerializedScriptValue::blobURLsIsolatedCopy() const
3573 Vector<String> result;
3574 result.reserveInitialCapacity(m_blobURLs.size());
3575 for (auto& url : m_blobURLs)
3576 result.uncheckedAppend(url.isolatedCopy());
3581 void SerializedScriptValue::writeBlobsToDiskForIndexedDB(CompletionHandler<void(IDBValue&&)>&& completionHandler)
3583 ASSERT(isMainThread());
3584 ASSERT(hasBlobURLs());
3586 // FIXME: Add m_sessionID as a parameter here.
3587 blobRegistry().writeBlobsToTemporaryFiles(m_blobURLs, [completionHandler = WTFMove(completionHandler), this, protectedThis = makeRef(*this)] (auto&& blobFilePaths) mutable {
3588 ASSERT(isMainThread());
3590 if (blobFilePaths.isEmpty()) {
3591 // We should have successfully written blobs to temporary files.
3592 // If we failed, then we can't successfully store this record.
3593 completionHandler({ });
3597 ASSERT(m_blobURLs.size() == blobFilePaths.size());
3599 completionHandler({ *this, m_blobURLs, m_sessionID, blobFilePaths });
3603 IDBValue SerializedScriptValue::writeBlobsToDiskForIndexedDBSynchronously()
3605 ASSERT(!isMainThread());
3609 Condition condition;
3612 RunLoop::main().dispatch([this, conditionPtr = &condition, valuePtr = &value] {
3613 writeBlobsToDiskForIndexedDB([conditionPtr, valuePtr](IDBValue&& result) {
3614 ASSERT(isMainThread());
3615 valuePtr->setAsIsolatedCopy(result);
3617 conditionPtr->notifyAll();
3621 condition.wait(lock);
3626 #endif // ENABLE(INDEXED_DATABASE)
3628 } // namespace WebCore