blob: f0a8d7211af8fd2467557f053fc8bb6258b99cea [file] [log] [blame]
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001/*
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002 * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000028#include "SerializedScriptValue.h"
29
jianli@chromium.org51ceb752010-08-11 00:03:19 +000030#include "Blob.h"
ap@apple.com351ac9c2013-12-11 22:13:55 +000031#include "CryptoKeyAES.h"
32#include "CryptoKeyDataOctetSequence.h"
33#include "CryptoKeyDataRSAComponents.h"
34#include "CryptoKeyHMAC.h"
35#include "CryptoKeyRSA.h"
akling@apple.comb15671a2013-02-24 13:01:06 +000036#include "ExceptionCode.h"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000037#include "File.h"
oliver@apple.comcebc1862010-01-24 07:44:05 +000038#include "FileList.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000039#include "ImageData.h"
jianli@chromium.org51ceb752010-08-11 00:03:19 +000040#include "JSBlob.h"
ap@apple.com351ac9c2013-12-11 22:13:55 +000041#include "JSCryptoKey.h"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000042#include "JSDOMGlobalObject.h"
43#include "JSFile.h"
44#include "JSFileList.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000045#include "JSImageData.h"
dslomov@google.comd60d08e2011-10-31 21:07:22 +000046#include "JSMessagePort.h"
slewis@apple.comfc28de52011-04-12 21:50:04 +000047#include "JSNavigator.h"
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +000048#include "NotImplemented.h"
oliver@apple.com8128fe12010-09-06 21:29:06 +000049#include "SharedBuffer.h"
fpizlo@apple.coma9188442013-08-01 22:14:28 +000050#include "WebCoreJSClientData.h"
oliver@apple.com8128fe12010-09-06 21:29:06 +000051#include <limits>
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +000052#include <JavaScriptCore/APICast.h>
timothy@apple.comf5a07a92011-03-03 18:28:29 +000053#include <JavaScriptCore/APIShims.h>
oliver@apple.comdf606082013-08-05 22:11:50 +000054#include <runtime/ArrayBuffer.h>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +000055#include <runtime/BooleanObject.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000056#include <runtime/DateInstance.h>
barraclough@apple.com9c099f92010-06-06 23:34:36 +000057#include <runtime/Error.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000058#include <runtime/ExceptionHelpers.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000059#include <runtime/JSArrayBuffer.h>
60#include <runtime/JSArrayBufferView.h>
61#include <runtime/JSDataView.h>
oliver@apple.com901740c2013-09-03 23:21:10 +000062#include <runtime/JSMap.h>
63#include <runtime/JSSet.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000064#include <runtime/JSTypedArrays.h>
oliver@apple.com901740c2013-09-03 23:21:10 +000065#include <runtime/MapData.h>
ggaren@apple.comc862eac2013-01-29 05:48:01 +000066#include <runtime/ObjectConstructor.h>
fpizlo@apple.coma4b4cbe2013-01-12 04:47:03 +000067#include <runtime/Operations.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000068#include <runtime/PropertyNameArray.h>
commit-queue@webkit.org7648c242010-09-08 00:33:15 +000069#include <runtime/RegExp.h>
70#include <runtime/RegExpObject.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000071#include <runtime/TypedArrayInlines.h>
72#include <runtime/TypedArrays.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000073#include <wtf/HashTraits.h>
74#include <wtf/Vector.h>
75
76using namespace JSC;
oliver@apple.com8128fe12010-09-06 21:29:06 +000077
oliver@apple.comf87795d2011-03-02 01:23:00 +000078#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
oliver@apple.com8128fe12010-09-06 21:29:06 +000079#define ASSUME_LITTLE_ENDIAN 0
80#else
81#define ASSUME_LITTLE_ENDIAN 1
82#endif
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000083
oliver@apple.comd83a9a22009-10-07 02:21:49 +000084namespace WebCore {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000085
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000086static const unsigned maximumFilterRecursion = 40000;
oliver@apple.com8128fe12010-09-06 21:29:06 +000087
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000088enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
oliver@apple.com901740c2013-09-03 23:21:10 +000089 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
90 MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue };
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000091
oliver@apple.com8128fe12010-09-06 21:29:06 +000092// These can't be reordered, and any new types must be added to the end of the list
93enum SerializationTag {
94 ArrayTag = 1,
95 ObjectTag = 2,
96 UndefinedTag = 3,
97 NullTag = 4,
98 IntTag = 5,
99 ZeroTag = 6,
100 OneTag = 7,
101 FalseTag = 8,
102 TrueTag = 9,
103 DoubleTag = 10,
104 DateTag = 11,
105 FileTag = 12,
106 FileListTag = 13,
107 ImageDataTag = 14,
108 BlobTag = 15,
109 StringTag = 16,
110 EmptyStringTag = 17,
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000111 RegExpTag = 18,
oliver@apple.come8641552010-12-20 22:40:37 +0000112 ObjectReferenceTag = 19,
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000113 MessagePortReferenceTag = 20,
dslomov@google.coma3962422012-02-23 02:51:20 +0000114 ArrayBufferTag = 21,
115 ArrayBufferViewTag = 22,
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000116 ArrayBufferTransferTag = 23,
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000117 TrueObjectTag = 24,
118 FalseObjectTag = 25,
119 StringObjectTag = 26,
120 EmptyStringObjectTag = 27,
121 NumberObjectTag = 28,
oliver@apple.com901740c2013-09-03 23:21:10 +0000122 SetObjectTag = 29,
123 MapObjectTag = 30,
124 NonMapPropertiesTag = 31,
ap@apple.com351ac9c2013-12-11 22:13:55 +0000125#if ENABLE(SUBTLE_CRYPTO)
126 CryptoKeyTag = 32,
127#endif
oliver@apple.com8128fe12010-09-06 21:29:06 +0000128 ErrorTag = 255
129};
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000130
dslomov@google.coma3962422012-02-23 02:51:20 +0000131enum ArrayBufferViewSubtag {
132 DataViewTag = 0,
133 Int8ArrayTag = 1,
134 Uint8ArrayTag = 2,
135 Uint8ClampedArrayTag = 3,
136 Int16ArrayTag = 4,
137 Uint16ArrayTag = 5,
138 Int32ArrayTag = 6,
139 Uint32ArrayTag = 7,
140 Float32ArrayTag = 8,
141 Float64ArrayTag = 9
142};
143
144static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
145{
146 switch (tag) {
147 case DataViewTag:
148 case Int8ArrayTag:
149 case Uint8ArrayTag:
150 case Uint8ClampedArrayTag:
151 return 1;
152 case Int16ArrayTag:
153 case Uint16ArrayTag:
154 return 2;
155 case Int32ArrayTag:
156 case Uint32ArrayTag:
157 case Float32ArrayTag:
158 return 4;
159 case Float64ArrayTag:
160 return 8;
161 default:
162 return 0;
163 }
164
165}
166
ap@apple.com351ac9c2013-12-11 22:13:55 +0000167#if ENABLE(SUBTLE_CRYPTO)
168
andersca@apple.com82c2afe2013-12-17 02:27:01 +0000169enum class CryptoKeyClassSubtag {
ap@apple.com351ac9c2013-12-11 22:13:55 +0000170 HMAC = 0,
171 AES = 1,
172 RSA = 2
173};
174const uint8_t cryptoKeyClassSubtagMaximumValue = 2;
175
andersca@apple.com82c2afe2013-12-17 02:27:01 +0000176enum class CryptoKeyAsymmetricTypeSubtag {
ap@apple.com351ac9c2013-12-11 22:13:55 +0000177 Public = 0,
178 Private = 1
179};
180const uint8_t cryptoKeyAsymmetricTypeSubtagMaximumValue = 1;
181
andersca@apple.com82c2afe2013-12-17 02:27:01 +0000182enum class CryptoKeyUsageTag {
ap@apple.com351ac9c2013-12-11 22:13:55 +0000183 Encrypt = 0,
184 Decrypt = 1,
185 Sign = 2,
186 Verify = 3,
187 DeriveKey = 4,
188 DeriveBits = 5,
189 WrapKey = 6,
190 UnwrapKey = 7
191};
192const uint8_t cryptoKeyUsageTagMaximumValue = 7;
193
andersca@apple.com82c2afe2013-12-17 02:27:01 +0000194enum class CryptoAlgorithmIdentifierTag {
ap@apple.com351ac9c2013-12-11 22:13:55 +0000195 RSAES_PKCS1_v1_5 = 0,
196 RSASSA_PKCS1_v1_5 = 1,
197 RSA_PSS = 2,
198 RSA_OAEP = 3,
199 ECDSA = 4,
200 ECDH = 5,
201 AES_CTR = 6,
202 AES_CBC = 7,
203 AES_CMAC = 8,
204 AES_GCM = 9,
205 AES_CFB = 10,
206 AES_KW = 11,
207 HMAC = 12,
208 DH = 13,
209 SHA_1 = 14,
210 SHA_224 = 15,
211 SHA_256 = 16,
212 SHA_384 = 17,
213 SHA_512 = 18,
214 CONCAT = 19,
215 HKDF_CTR = 20,
216 PBKDF2 = 21,
217};
218const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21;
219
220static unsigned countUsages(CryptoKeyUsage usages)
221{
222 // Fast bit count algorithm for sparse bit maps.
223 unsigned count = 0;
224 while (usages) {
225 usages = usages & (usages - 1);
226 ++count;
227 }
228 return count;
229}
230
231#endif
232
ap@apple.com49030772013-12-06 22:31:39 +0000233/* CurrentVersion tracks the serialization version so that persistent stores
oliver@apple.come8641552010-12-20 22:40:37 +0000234 * are able to correctly bail out in the case of encountering newer formats.
235 *
236 * Initial version was 1.
237 * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000238 * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
239 * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000240 * Version 4. added support for serializing non-index properties of arrays.
oliver@apple.com901740c2013-09-03 23:21:10 +0000241 * Version 5. added support for Map and Set types.
oliver@apple.come8641552010-12-20 22:40:37 +0000242 */
oliver@apple.com901740c2013-09-03 23:21:10 +0000243static const unsigned CurrentVersion = 5;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000244static const unsigned TerminatorTag = 0xFFFFFFFF;
245static const unsigned StringPoolTag = 0xFFFFFFFE;
246static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000247
oliver@apple.com8128fe12010-09-06 21:29:06 +0000248/*
249 * Object serialization is performed according to the following grammar, all tags
250 * are recorded as a single uint8_t.
251 *
oliver@apple.come8641552010-12-20 22:40:37 +0000252 * IndexType (used for the object pool and StringData's constant pool) is the
253 * minimum sized unsigned integer type required to represent the maximum index
254 * in the constant pool.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000255 *
256 * SerializedValue :- <CurrentVersion:uint32_t> Value
oliver@apple.com901740c2013-09-03 23:21:10 +0000257 * Value :- Array | Object | Map | Set | Terminal
oliver@apple.com8128fe12010-09-06 21:29:06 +0000258 *
259 * Array :-
260 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
261 *
262 * Object :-
263 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
264 *
oliver@apple.com901740c2013-09-03 23:21:10 +0000265 * Map :- MapObjectTag MapData
266 *
267 * Set :- SetObjectTag MapData
268 *
269 * MapData :- (<key:Value><value:Value>) NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
270 *
oliver@apple.com8128fe12010-09-06 21:29:06 +0000271 * Terminal :-
272 * UndefinedTag
273 * | NullTag
274 * | IntTag <value:int32_t>
275 * | ZeroTag
276 * | OneTag
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000277 * | FalseTag
278 * | TrueTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000279 * | FalseObjectTag
280 * | TrueObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000281 * | DoubleTag <value:double>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000282 * | NumberObjectTag <value:double>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000283 * | DateTag <value:double>
284 * | String
285 * | EmptyStringTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000286 * | EmptyStringObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000287 * | File
288 * | FileList
289 * | ImageData
290 * | Blob
dslomov@google.coma3962422012-02-23 02:51:20 +0000291 * | ObjectReference
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000292 * | MessagePortReferenceTag <value:uint32_t>
dslomov@google.coma3962422012-02-23 02:51:20 +0000293 * | ArrayBuffer
ap@apple.com351ac9c2013-12-11 22:13:55 +0000294 * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000295 * | ArrayBufferTransferTag <value:uint32_t>
ap@apple.com351ac9c2013-12-11 22:13:55 +0000296 * | CryptoKeyTag <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000297 *
298 * String :-
299 * EmptyStringTag
300 * StringTag StringData
301 *
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000302 * StringObject:
303 * EmptyStringObjectTag
304 * StringObjectTag StringData
305 *
oliver@apple.com8128fe12010-09-06 21:29:06 +0000306 * StringData :-
307 * StringPoolTag <cpIndex:IndexType>
308 * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
309 *
310 * File :-
311 * FileTag FileData
312 *
313 * FileData :-
314 * <path:StringData> <url:StringData> <type:StringData>
315 *
316 * FileList :-
317 * FileListTag <length:uint32_t>(<file:FileData>){length}
318 *
319 * ImageData :-
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000320 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000321 *
322 * Blob :-
323 * BlobTag <url:StringData><type:StringData><size:long long>
324 *
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000325 * RegExp :-
326 * RegExpTag <pattern:StringData><flags:StringData>
dslomov@google.coma3962422012-02-23 02:51:20 +0000327 *
328 * ObjectReference :-
329 * ObjectReferenceTag <opIndex:IndexType>
330 *
331 * ArrayBuffer :-
332 * ArrayBufferTag <length:uint32_t> <contents:byte{length}>
ap@apple.com351ac9c2013-12-11 22:13:55 +0000333 *
334 * CryptoKeyHMAC :-
335 * <keySize:uint32_t> <keyData:byte{keySize}> CryptoAlgorithmIdentifierTag // Algorithm tag inner hash function.
336 *
337 * CryptoKeyAES :-
338 * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
339 *
340 * CryptoKeyRSA :-
341 * CryptoAlgorithmIdentifierTag <isRestrictedToHash:int32_t> CryptoAlgorithmIdentifierTag? CryptoKeyAsymmetricTypeSubtag CryptoKeyRSAPublicComponents CryptoKeyRSAPrivateComponents?
342 *
343 * CryptoKeyRSAPublicComponents :-
344 * <modulusSize:uint32_t> <modulus:byte{modulusSize}> <exponentSize:uint32_t> <exponent:byte{exponentSize}>
345 *
346 * CryptoKeyRSAPrivateComponents :-
347 * <privateExponentSize:uint32_t> <privateExponent:byte{privateExponentSize}> <primeCount:uint32_t> FirstPrimeInfo? PrimeInfo{primeCount - 1}
348 *
349 * // CRT data could be computed from prime factors. It is only serialized to reuse a code path that's needed for JWK.
350 * FirstPrimeInfo :-
351 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}>
352 *
353 * PrimeInfo :-
354 * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000355 */
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000356
zandobersek@gmail.com83a31192014-01-04 17:26:52 +0000357typedef std::pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
slewis@apple.comfc28de52011-04-12 21:50:04 +0000358
oliver@apple.com8128fe12010-09-06 21:29:06 +0000359class CloneBase {
360protected:
361 CloneBase(ExecState* exec)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000362 : m_exec(exec)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000363 , m_failed(false)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000364 {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000365 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000366
367 bool shouldTerminate()
368 {
369 return m_exec->hadException();
370 }
371
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000372 void throwStackOverflow()
373 {
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +0000374 m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000375 }
376
weinig@apple.com21498652011-08-13 02:40:51 +0000377 NO_RETURN_DUE_TO_ASSERT
oliver@apple.com8128fe12010-09-06 21:29:06 +0000378 void fail()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000379 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000380 ASSERT_NOT_REACHED();
381 m_failed = true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000382 }
383
oliver@apple.com8128fe12010-09-06 21:29:06 +0000384 ExecState* m_exec;
385 bool m_failed;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000386 MarkedArgumentBuffer m_gcBuffer;
387};
388
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000389#if ASSUME_LITTLE_ENDIAN
390template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
391{
392 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
393}
394#else
395template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
396{
397 for (unsigned i = 0; i < sizeof(T); i++) {
398 buffer.append(value & 0xFF);
399 value >>= 8;
400 }
401}
402#endif
403
cwzwarich@webkit.orgd0ef6552011-03-13 03:36:23 +0000404template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000405{
406 buffer.append(value);
407}
408
409template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
410{
andersca@apple.comff9adb82013-10-25 01:15:36 +0000411 if (length > std::numeric_limits<uint32_t>::max() / sizeof(T))
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000412 return false;
413
414#if ASSUME_LITTLE_ENDIAN
415 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
416#else
417 for (unsigned i = 0; i < length; i++) {
418 T value = values[i];
419 for (unsigned j = 0; j < sizeof(T); j++) {
420 buffer.append(static_cast<uint8_t>(value & 0xFF));
421 value >>= 8;
422 }
423 }
424#endif
425 return true;
426}
427
dbates@webkit.org6cc899e2014-01-13 20:56:04 +0000428template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8_t* values, uint32_t length)
429{
430 buffer.append(values, length);
431 return true;
432}
433
oliver@apple.com8128fe12010-09-06 21:29:06 +0000434class CloneSerializer : CloneBase {
435public:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000436 static SerializationReturnCode serialize(ExecState* exec, JSValue value,
437 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000438 Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000439 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000440 CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000441 return serializer.serialize(value);
442 }
443
tony@chromium.org6b09aa62011-06-24 06:43:34 +0000444 static bool serialize(const String& s, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000445 {
446 writeLittleEndian(out, CurrentVersion);
447 if (s.isEmpty()) {
448 writeLittleEndian<uint8_t>(out, EmptyStringTag);
449 return true;
450 }
451 writeLittleEndian<uint8_t>(out, StringTag);
452 writeLittleEndian(out, s.length());
darin@apple.comda57a4d2014-01-13 02:29:47 +0000453 return writeLittleEndian(out, s.impl()->deprecatedCharacters(), s.length());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000454 }
455
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000456 static void serializeUndefined(Vector<uint8_t>& out)
457 {
458 writeLittleEndian(out, CurrentVersion);
459 writeLittleEndian<uint8_t>(out, UndefinedTag);
460 }
461
462 static void serializeBoolean(bool value, Vector<uint8_t>& out)
463 {
464 writeLittleEndian(out, CurrentVersion);
465 writeLittleEndian<uint8_t>(out, value ? TrueTag : FalseTag);
466 }
467
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +0000468 static void serializeNumber(double value, Vector<uint8_t>& out)
469 {
470 writeLittleEndian(out, CurrentVersion);
471 writeLittleEndian<uint8_t>(out, DoubleTag);
472 union {
473 double d;
474 int64_t i;
475 } u;
476 u.d = value;
477 writeLittleEndian(out, u.i);
478 }
479
oliver@apple.com8128fe12010-09-06 21:29:06 +0000480private:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000481 typedef HashMap<JSObject*, uint32_t> ObjectPool;
482
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000483 CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000484 : CloneBase(exec)
485 , m_buffer(out)
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000486 , m_blobURLs(blobURLs)
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000487 , m_emptyIdentifier(exec, emptyString())
oliver@apple.com8128fe12010-09-06 21:29:06 +0000488 {
489 write(CurrentVersion);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000490 fillTransferMap(messagePorts, m_transferredMessagePorts);
491 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
492 }
493
494 template <class T>
495 void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result)
496 {
497 if (!input)
498 return;
oliver@apple.comffe14422012-04-05 22:33:19 +0000499 JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000500 for (size_t i = 0; i < input->size(); i++) {
501 JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get());
502 JSC::JSObject* obj = value.getObject();
503 if (obj && !result.contains(obj))
504 result.add(obj, i);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000505 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000506 }
507
slewis@apple.comfc28de52011-04-12 21:50:04 +0000508 SerializationReturnCode serialize(JSValue in);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000509
510 bool isArray(JSValue value)
511 {
512 if (!value.isObject())
513 return false;
514 JSObject* object = asObject(value);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000515 return isJSArray(object) || object->inherits(JSArray::info());
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000516 }
517
oliver@apple.com901740c2013-09-03 23:21:10 +0000518 bool isMap(JSValue value)
519 {
520 if (!value.isObject())
521 return false;
522 JSObject* object = asObject(value);
523 return object->inherits(JSMap::info());
524 }
525 bool isSet(JSValue value)
526 {
527 if (!value.isObject())
528 return false;
529 JSObject* object = asObject(value);
530 return object->inherits(JSSet::info());
531 }
532
dslomov@google.com6c31be52012-04-04 20:43:31 +0000533 bool checkForDuplicate(JSObject* object)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000534 {
oliver@apple.come8641552010-12-20 22:40:37 +0000535 // Record object for graph reconstruction
dslomov@google.comfd060da2012-04-12 19:16:49 +0000536 ObjectPool::const_iterator found = m_objectPool.find(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000537
oliver@apple.come8641552010-12-20 22:40:37 +0000538 // Handle duplicate references
dslomov@google.comfd060da2012-04-12 19:16:49 +0000539 if (found != m_objectPool.end()) {
oliver@apple.come8641552010-12-20 22:40:37 +0000540 write(ObjectReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000541 ASSERT(static_cast<int32_t>(found->value) < m_objectPool.size());
542 writeObjectIndex(found->value);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000543 return true;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000544 }
dslomov@google.com6c31be52012-04-04 20:43:31 +0000545
546 return false;
547 }
548
549 void recordObject(JSObject* object)
550 {
551 m_objectPool.add(object, m_objectPool.size());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000552 m_gcBuffer.append(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000553 }
554
555 bool startObjectInternal(JSObject* object)
556 {
557 if (checkForDuplicate(object))
558 return false;
559 recordObject(object);
oliver@apple.come8641552010-12-20 22:40:37 +0000560 return true;
561 }
562
563 bool startObject(JSObject* object)
564 {
565 if (!startObjectInternal(object))
566 return false;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000567 write(ObjectTag);
568 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000569 }
570
oliver@apple.com8128fe12010-09-06 21:29:06 +0000571 bool startArray(JSArray* array)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000572 {
oliver@apple.come8641552010-12-20 22:40:37 +0000573 if (!startObjectInternal(array))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000574 return false;
oliver@apple.come8641552010-12-20 22:40:37 +0000575
oliver@apple.com8128fe12010-09-06 21:29:06 +0000576 unsigned length = array->length();
577 write(ArrayTag);
578 write(length);
579 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000580 }
581
oliver@apple.com901740c2013-09-03 23:21:10 +0000582 bool startSet(JSSet* set)
583 {
584 if (!startObjectInternal(set))
585 return false;
586
587 write(SetObjectTag);
588 return true;
589 }
590
591 bool startMap(JSMap* map)
592 {
593 if (!startObjectInternal(map))
594 return false;
595
596 write(MapObjectTag);
597 return true;
598 }
599
oliver@apple.come8641552010-12-20 22:40:37 +0000600 void endObject()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000601 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000602 write(TerminatorTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000603 }
604
oliver@apple.com8128fe12010-09-06 21:29:06 +0000605 JSValue getProperty(JSObject* object, const Identifier& propertyName)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000606 {
607 PropertySlot slot(object);
mhahnenberg@apple.com5c103b02011-10-26 17:55:34 +0000608 if (object->methodTable()->getOwnPropertySlot(object, m_exec, propertyName, slot))
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000609 return slot.getValue(m_exec, propertyName);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000610 return JSValue();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000611 }
612
oliver@apple.com8128fe12010-09-06 21:29:06 +0000613 void dumpImmediate(JSValue value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000614 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000615 if (value.isNull())
616 write(NullTag);
617 else if (value.isUndefined())
618 write(UndefinedTag);
619 else if (value.isNumber()) {
620 if (value.isInt32()) {
621 if (!value.asInt32())
622 write(ZeroTag);
623 else if (value.asInt32() == 1)
624 write(OneTag);
625 else {
626 write(IntTag);
627 write(static_cast<uint32_t>(value.asInt32()));
628 }
629 } else {
630 write(DoubleTag);
631 write(value.asDouble());
632 }
633 } else if (value.isBoolean()) {
634 if (value.isTrue())
635 write(TrueTag);
636 else
637 write(FalseTag);
638 }
639 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000640
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000641 void dumpString(String str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000642 {
643 if (str.isEmpty())
644 write(EmptyStringTag);
645 else {
646 write(StringTag);
647 write(str);
648 }
649 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000650
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000651 void dumpStringObject(String str)
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000652 {
653 if (str.isEmpty())
654 write(EmptyStringObjectTag);
655 else {
656 write(StringObjectTag);
657 write(str);
658 }
659 }
660
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000661 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
dslomov@google.coma3962422012-02-23 02:51:20 +0000662 {
663 write(ArrayBufferViewTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000664 if (obj->inherits(JSDataView::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000665 write(DataViewTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000666 else if (obj->inherits(JSUint8ClampedArray::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000667 write(Uint8ClampedArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000668 else if (obj->inherits(JSInt8Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000669 write(Int8ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000670 else if (obj->inherits(JSUint8Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000671 write(Uint8ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000672 else if (obj->inherits(JSInt16Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000673 write(Int16ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000674 else if (obj->inherits(JSUint16Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000675 write(Uint16ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000676 else if (obj->inherits(JSInt32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000677 write(Int32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000678 else if (obj->inherits(JSUint32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000679 write(Uint32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000680 else if (obj->inherits(JSFloat32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000681 write(Float32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000682 else if (obj->inherits(JSFloat64Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000683 write(Float64ArrayTag);
684 else
685 return false;
686
687 RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj);
688 write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
689 write(static_cast<uint32_t>(arrayBufferView->byteLength()));
690 RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000691 if (!arrayBuffer) {
692 code = ValidationError;
693 return true;
694 }
oliver@apple.comffe14422012-04-05 22:33:19 +0000695 JSValue bufferObj = toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000696 return dumpIfTerminal(bufferObj, code);
dslomov@google.coma3962422012-02-23 02:51:20 +0000697 }
698
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000699 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000700 {
701 if (!value.isCell()) {
702 dumpImmediate(value);
703 return true;
704 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000705
oliver@apple.com8128fe12010-09-06 21:29:06 +0000706 if (value.isString()) {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000707 String str = asString(value)->value(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000708 dumpString(str);
709 return true;
710 }
711
712 if (value.isNumber()) {
713 write(DoubleTag);
ggaren@apple.com7831f0c2011-10-05 02:38:49 +0000714 write(value.asNumber());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000715 return true;
716 }
717
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000718 if (value.isObject() && asObject(value)->inherits(DateInstance::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000719 write(DateTag);
720 write(asDateInstance(value)->internalNumber());
721 return true;
722 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000723
724 if (isArray(value))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000725 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000726
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000727 if (value.isObject()) {
728 JSObject* obj = asObject(value);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000729 if (obj->inherits(BooleanObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000730 if (!startObjectInternal(obj)) // handle duplicates
731 return true;
mhahnenberg@apple.com3b9069c2012-08-23 23:00:31 +0000732 write(asBooleanObject(value)->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000733 return true;
734 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000735 if (obj->inherits(StringObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000736 if (!startObjectInternal(obj)) // handle duplicates
737 return true;
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000738 String str = asString(asStringObject(value)->internalValue())->value(m_exec);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000739 dumpStringObject(str);
740 return true;
741 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000742 if (obj->inherits(NumberObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000743 if (!startObjectInternal(obj)) // handle duplicates
744 return true;
745 write(NumberObjectTag);
746 NumberObject* obj = static_cast<NumberObject*>(asObject(value));
747 write(obj->internalValue().asNumber());
748 return true;
749 }
ap@apple.com49030772013-12-06 22:31:39 +0000750 if (File* file = toFile(obj)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000751 write(FileTag);
ap@apple.com49030772013-12-06 22:31:39 +0000752 write(file);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000753 return true;
754 }
ap@apple.com49030772013-12-06 22:31:39 +0000755 if (FileList* list = toFileList(obj)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000756 write(FileListTag);
757 unsigned length = list->length();
758 write(length);
759 for (unsigned i = 0; i < length; i++)
760 write(list->item(i));
761 return true;
762 }
ap@apple.com49030772013-12-06 22:31:39 +0000763 if (Blob* blob = toBlob(obj)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000764 write(BlobTag);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000765 m_blobURLs.append(blob->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000766 write(blob->url());
767 write(blob->type());
768 write(blob->size());
769 return true;
770 }
ap@apple.com49030772013-12-06 22:31:39 +0000771 if (ImageData* data = toImageData(obj)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000772 write(ImageDataTag);
773 write(data->width());
774 write(data->height());
775 write(data->data()->length());
kbr@google.com1262e442012-04-24 03:43:31 +0000776 write(data->data()->data(), data->data()->length());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000777 return true;
778 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000779 if (obj->inherits(RegExpObject::info())) {
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000780 RegExpObject* regExp = asRegExpObject(obj);
781 char flags[3];
782 int flagCount = 0;
783 if (regExp->regExp()->global())
784 flags[flagCount++] = 'g';
785 if (regExp->regExp()->ignoreCase())
786 flags[flagCount++] = 'i';
787 if (regExp->regExp()->multiline())
788 flags[flagCount++] = 'm';
789 write(RegExpTag);
790 write(regExp->regExp()->pattern());
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000791 write(String(flags, flagCount));
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000792 return true;
793 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000794 if (obj->inherits(JSMessagePort::info())) {
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000795 ObjectPool::iterator index = m_transferredMessagePorts.find(obj);
796 if (index != m_transferredMessagePorts.end()) {
797 write(MessagePortReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000798 write(index->value);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000799 return true;
800 }
commit-queue@webkit.orgd9ae4552012-05-31 02:58:48 +0000801 // MessagePort object could not be found in transferred message ports
802 code = ValidationError;
803 return true;
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000804 }
ap@apple.com49030772013-12-06 22:31:39 +0000805 if (ArrayBuffer* arrayBuffer = toArrayBuffer(obj)) {
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000806 if (arrayBuffer->isNeutered()) {
807 code = ValidationError;
808 return true;
809 }
810 ObjectPool::iterator index = m_transferredArrayBuffers.find(obj);
811 if (index != m_transferredArrayBuffers.end()) {
812 write(ArrayBufferTransferTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000813 write(index->value);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000814 return true;
815 }
dslomov@google.coma3962422012-02-23 02:51:20 +0000816 if (!startObjectInternal(obj)) // handle duplicates
817 return true;
818 write(ArrayBufferTag);
dslomov@google.coma3962422012-02-23 02:51:20 +0000819 write(arrayBuffer->byteLength());
ap@apple.com49030772013-12-06 22:31:39 +0000820 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
dslomov@google.coma3962422012-02-23 02:51:20 +0000821 return true;
822 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000823 if (obj->inherits(JSArrayBufferView::info())) {
dslomov@google.com6c31be52012-04-04 20:43:31 +0000824 if (checkForDuplicate(obj))
dslomov@google.coma3962422012-02-23 02:51:20 +0000825 return true;
dslomov@google.com6c31be52012-04-04 20:43:31 +0000826 bool success = dumpArrayBufferView(obj, code);
827 recordObject(obj);
828 return success;
dslomov@google.coma3962422012-02-23 02:51:20 +0000829 }
ap@apple.com351ac9c2013-12-11 22:13:55 +0000830#if ENABLE(SUBTLE_CRYPTO)
831 if (CryptoKey* key = toCryptoKey(obj)) {
832 write(CryptoKeyTag);
833 write(key);
834 return true;
835 }
836#endif
oliver@apple.com8128fe12010-09-06 21:29:06 +0000837
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000838 return false;
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000839 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000840 // Any other types are expected to serialize as null.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000841 write(NullTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000842 return true;
843 }
844
oliver@apple.com8128fe12010-09-06 21:29:06 +0000845 void write(SerializationTag tag)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000846 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000847 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000848 }
849
dslomov@google.coma3962422012-02-23 02:51:20 +0000850 void write(ArrayBufferViewSubtag tag)
851 {
852 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
853 }
854
ap@apple.com351ac9c2013-12-11 22:13:55 +0000855#if ENABLE(SUBTLE_CRYPTO)
856 void write(CryptoKeyClassSubtag tag)
857 {
858 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
859 }
860
861 void write(CryptoKeyAsymmetricTypeSubtag tag)
862 {
863 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
864 }
865
866 void write(CryptoKeyUsageTag tag)
867 {
868 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
869 }
870
871 void write(CryptoAlgorithmIdentifierTag tag)
872 {
873 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
874 }
875#endif
876
oliver@apple.com8128fe12010-09-06 21:29:06 +0000877 void write(uint8_t c)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000878 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000879 writeLittleEndian(m_buffer, c);
880 }
881
oliver@apple.com8128fe12010-09-06 21:29:06 +0000882 void write(uint32_t i)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000883 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000884 writeLittleEndian(m_buffer, i);
885 }
886
887 void write(double d)
888 {
889 union {
890 double d;
891 int64_t i;
892 } u;
893 u.d = d;
894 writeLittleEndian(m_buffer, u.i);
895 }
896
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000897 void write(int32_t i)
898 {
899 writeLittleEndian(m_buffer, i);
900 }
901
oliver@apple.com8128fe12010-09-06 21:29:06 +0000902 void write(unsigned long long i)
903 {
904 writeLittleEndian(m_buffer, i);
905 }
oliver@apple.coma9b47542010-09-06 22:53:32 +0000906
907 void write(uint16_t ch)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000908 {
oliver@apple.coma9b47542010-09-06 22:53:32 +0000909 writeLittleEndian(m_buffer, ch);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000910 }
911
912 void writeStringIndex(unsigned i)
913 {
oliver@apple.come8641552010-12-20 22:40:37 +0000914 writeConstantPoolIndex(m_constantPool, i);
915 }
916
917 void writeObjectIndex(unsigned i)
918 {
919 writeConstantPoolIndex(m_objectPool, i);
920 }
921
922 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
923 {
924 ASSERT(static_cast<int32_t>(i) < constantPool.size());
925 if (constantPool.size() <= 0xFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000926 write(static_cast<uint8_t>(i));
oliver@apple.come8641552010-12-20 22:40:37 +0000927 else if (constantPool.size() <= 0xFFFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000928 write(static_cast<uint16_t>(i));
929 else
930 write(static_cast<uint32_t>(i));
931 }
932
933 void write(const Identifier& ident)
934 {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +0000935 const String& str = ident.string();
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000936 StringConstantPool::AddResult addResult = m_constantPool.add(str.impl(), m_constantPool.size());
937 if (!addResult.isNewEntry) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000938 write(StringPoolTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000939 writeStringIndex(addResult.iterator->value);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000940 return;
941 }
942
943 // This condition is unlikely to happen as they would imply an ~8gb
944 // string but we should guard against it anyway
945 if (str.length() >= StringPoolTag) {
946 fail();
947 return;
948 }
949
950 // Guard against overflow
andersca@apple.comff9adb82013-10-25 01:15:36 +0000951 if (str.length() > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000952 fail();
953 return;
954 }
955
956 writeLittleEndian<uint32_t>(m_buffer, str.length());
darin@apple.comda57a4d2014-01-13 02:29:47 +0000957 if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.deprecatedCharacters()), str.length()))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000958 fail();
959 }
960
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000961 void write(const String& str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000962 {
963 if (str.isNull())
964 write(m_emptyIdentifier);
965 else
966 write(Identifier(m_exec, str));
967 }
968
ap@apple.com351ac9c2013-12-11 22:13:55 +0000969 void write(const Vector<uint8_t>& vector)
970 {
971 uint32_t size = vector.size();
972 write(size);
973 writeLittleEndian(m_buffer, vector.data(), size);
974 }
975
oliver@apple.com8128fe12010-09-06 21:29:06 +0000976 void write(const File* file)
977 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000978 m_blobURLs.append(file->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000979 write(file->path());
980 write(file->url());
981 write(file->type());
982 }
983
ap@apple.com351ac9c2013-12-11 22:13:55 +0000984#if ENABLE(SUBTLE_CRYPTO)
985 void write(CryptoAlgorithmIdentifier algorithm)
986 {
987 switch (algorithm) {
988 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
989 write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
990 break;
991 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
992 write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
993 break;
994 case CryptoAlgorithmIdentifier::RSA_PSS:
995 write(CryptoAlgorithmIdentifierTag::RSA_PSS);
996 break;
997 case CryptoAlgorithmIdentifier::RSA_OAEP:
998 write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
999 break;
1000 case CryptoAlgorithmIdentifier::ECDSA:
1001 write(CryptoAlgorithmIdentifierTag::ECDSA);
1002 break;
1003 case CryptoAlgorithmIdentifier::ECDH:
1004 write(CryptoAlgorithmIdentifierTag::ECDH);
1005 break;
1006 case CryptoAlgorithmIdentifier::AES_CTR:
1007 write(CryptoAlgorithmIdentifierTag::AES_CTR);
1008 break;
1009 case CryptoAlgorithmIdentifier::AES_CBC:
1010 write(CryptoAlgorithmIdentifierTag::AES_CBC);
1011 break;
1012 case CryptoAlgorithmIdentifier::AES_CMAC:
1013 write(CryptoAlgorithmIdentifierTag::AES_CMAC);
1014 break;
1015 case CryptoAlgorithmIdentifier::AES_GCM:
1016 write(CryptoAlgorithmIdentifierTag::AES_GCM);
1017 break;
1018 case CryptoAlgorithmIdentifier::AES_CFB:
1019 write(CryptoAlgorithmIdentifierTag::AES_CFB);
1020 break;
1021 case CryptoAlgorithmIdentifier::AES_KW:
1022 write(CryptoAlgorithmIdentifierTag::AES_KW);
1023 break;
1024 case CryptoAlgorithmIdentifier::HMAC:
1025 write(CryptoAlgorithmIdentifierTag::HMAC);
1026 break;
1027 case CryptoAlgorithmIdentifier::DH:
1028 write(CryptoAlgorithmIdentifierTag::DH);
1029 break;
1030 case CryptoAlgorithmIdentifier::SHA_1:
1031 write(CryptoAlgorithmIdentifierTag::SHA_1);
1032 break;
1033 case CryptoAlgorithmIdentifier::SHA_224:
1034 write(CryptoAlgorithmIdentifierTag::SHA_224);
1035 break;
1036 case CryptoAlgorithmIdentifier::SHA_256:
1037 write(CryptoAlgorithmIdentifierTag::SHA_256);
1038 break;
1039 case CryptoAlgorithmIdentifier::SHA_384:
1040 write(CryptoAlgorithmIdentifierTag::SHA_384);
1041 break;
1042 case CryptoAlgorithmIdentifier::SHA_512:
1043 write(CryptoAlgorithmIdentifierTag::SHA_512);
1044 break;
1045 case CryptoAlgorithmIdentifier::CONCAT:
1046 write(CryptoAlgorithmIdentifierTag::CONCAT);
1047 break;
1048 case CryptoAlgorithmIdentifier::HKDF_CTR:
1049 write(CryptoAlgorithmIdentifierTag::HKDF_CTR);
1050 break;
1051 case CryptoAlgorithmIdentifier::PBKDF2:
1052 write(CryptoAlgorithmIdentifierTag::PBKDF2);
1053 break;
1054 }
1055 }
1056
1057 void write(CryptoKeyDataRSAComponents::Type type)
1058 {
1059 switch (type) {
1060 case CryptoKeyDataRSAComponents::Type::Public:
1061 write(CryptoKeyAsymmetricTypeSubtag::Public);
1062 return;
1063 case CryptoKeyDataRSAComponents::Type::Private:
1064 write(CryptoKeyAsymmetricTypeSubtag::Private);
1065 return;
1066 }
1067 }
1068
1069 void write(const CryptoKeyDataRSAComponents& key)
1070 {
1071 write(key.type());
1072 write(key.modulus());
1073 write(key.exponent());
1074 if (key.type() == CryptoKeyDataRSAComponents::Type::Public)
1075 return;
1076
1077 write(key.privateExponent());
1078
1079 unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
1080 write(primeCount);
1081 if (!primeCount)
1082 return;
1083
1084 write(key.firstPrimeInfo().primeFactor);
1085 write(key.firstPrimeInfo().factorCRTExponent);
1086 write(key.secondPrimeInfo().primeFactor);
1087 write(key.secondPrimeInfo().factorCRTExponent);
1088 write(key.secondPrimeInfo().factorCRTCoefficient);
1089 for (unsigned i = 2; i < primeCount; ++i) {
1090 write(key.otherPrimeInfos()[i].primeFactor);
1091 write(key.otherPrimeInfos()[i].factorCRTExponent);
1092 write(key.otherPrimeInfos()[i].factorCRTCoefficient);
1093 }
1094 }
1095
1096 void write(const CryptoKey* key)
1097 {
1098 write(key->extractable());
1099
1100 CryptoKeyUsage usages = key->usagesBitmap();
1101 write(countUsages(usages));
1102 if (usages & CryptoKeyUsageEncrypt)
1103 write(CryptoKeyUsageTag::Encrypt);
1104 if (usages & CryptoKeyUsageDecrypt)
1105 write(CryptoKeyUsageTag::Decrypt);
1106 if (usages & CryptoKeyUsageSign)
1107 write(CryptoKeyUsageTag::Sign);
1108 if (usages & CryptoKeyUsageVerify)
1109 write(CryptoKeyUsageTag::Verify);
1110 if (usages & CryptoKeyUsageDeriveKey)
1111 write(CryptoKeyUsageTag::DeriveKey);
1112 if (usages & CryptoKeyUsageDeriveBits)
1113 write(CryptoKeyUsageTag::DeriveBits);
1114 if (usages & CryptoKeyUsageWrapKey)
1115 write(CryptoKeyUsageTag::WrapKey);
1116 if (usages & CryptoKeyUsageUnwrapKey)
1117 write(CryptoKeyUsageTag::UnwrapKey);
1118
1119 switch (key->keyClass()) {
1120 case CryptoKeyClass::HMAC:
1121 write(CryptoKeyClassSubtag::HMAC);
1122 write(toCryptoKeyHMAC(key)->key());
1123 write(toCryptoKeyHMAC(key)->hashAlgorithmIdentifier());
1124 break;
1125 case CryptoKeyClass::AES:
1126 write(CryptoKeyClassSubtag::AES);
1127 write(key->algorithmIdentifier());
1128 write(toCryptoKeyAES(key)->key());
1129 break;
1130 case CryptoKeyClass::RSA:
1131 write(CryptoKeyClassSubtag::RSA);
1132 write(key->algorithmIdentifier());
1133 CryptoAlgorithmIdentifier hash;
1134 bool isRestrictedToHash = toCryptoKeyRSA(key)->isRestrictedToHash(hash);
1135 write(isRestrictedToHash);
1136 if (isRestrictedToHash)
1137 write(hash);
1138 write(toCryptoKeyDataRSAComponents(*key->exportData()));
1139 break;
1140 }
1141 }
1142#endif
1143
oliver@apple.com8128fe12010-09-06 21:29:06 +00001144 void write(const uint8_t* data, unsigned length)
1145 {
1146 m_buffer.append(data, length);
1147 }
1148
1149 Vector<uint8_t>& m_buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001150 Vector<String>& m_blobURLs;
oliver@apple.come8641552010-12-20 22:40:37 +00001151 ObjectPool m_objectPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001152 ObjectPool m_transferredMessagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001153 ObjectPool m_transferredArrayBuffers;
oliver@apple.come8641552010-12-20 22:40:37 +00001154 typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
1155 StringConstantPool m_constantPool;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001156 Identifier m_emptyIdentifier;
1157};
1158
slewis@apple.comfc28de52011-04-12 21:50:04 +00001159SerializationReturnCode CloneSerializer::serialize(JSValue in)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001160{
1161 Vector<uint32_t, 16> indexStack;
1162 Vector<uint32_t, 16> lengthStack;
1163 Vector<PropertyNameArray, 16> propertyStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001164 Vector<JSObject*, 32> inputObjectStack;
oliver@apple.com901740c2013-09-03 23:21:10 +00001165 Vector<MapData*, 4> mapDataStack;
1166 Vector<MapData::const_iterator, 4> iteratorStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001167 Vector<WalkerState, 16> stateStack;
1168 WalkerState state = StateUnknown;
1169 JSValue inValue = in;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001170 while (1) {
1171 switch (state) {
1172 arrayStartState:
1173 case ArrayStartState: {
1174 ASSERT(isArray(inValue));
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001175 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001176 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001177
1178 JSArray* inArray = asArray(inValue);
1179 unsigned length = inArray->length();
1180 if (!startArray(inArray))
oliver@apple.come8641552010-12-20 22:40:37 +00001181 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001182 inputObjectStack.append(inArray);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001183 indexStack.append(0);
1184 lengthStack.append(length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001185 }
1186 arrayStartVisitMember:
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00001187 FALLTHROUGH;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001188 case ArrayStartVisitMember: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001189 JSObject* array = inputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001190 uint32_t index = indexStack.last();
1191 if (index == lengthStack.last()) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001192 indexStack.removeLast();
1193 lengthStack.removeLast();
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001194
1195 propertyStack.append(PropertyNameArray(m_exec));
1196 array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
1197 if (propertyStack.last().size()) {
1198 write(NonIndexPropertiesTag);
1199 indexStack.append(0);
1200 goto objectStartVisitMember;
1201 }
1202 propertyStack.removeLast();
1203
1204 endObject();
1205 inputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001206 break;
1207 }
fpizlo@apple.com7ebfaed2012-09-25 23:42:52 +00001208 inValue = array->getDirectIndex(m_exec, index);
1209 if (!inValue) {
1210 indexStack.last()++;
1211 goto arrayStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001212 }
1213
1214 write(index);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001215 SerializationReturnCode terminalCode = SuccessfullyCompleted;
1216 if (dumpIfTerminal(inValue, terminalCode)) {
1217 if (terminalCode != SuccessfullyCompleted)
1218 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001219 indexStack.last()++;
1220 goto arrayStartVisitMember;
1221 }
1222 stateStack.append(ArrayEndVisitMember);
1223 goto stateUnknown;
1224 }
1225 case ArrayEndVisitMember: {
1226 indexStack.last()++;
1227 goto arrayStartVisitMember;
1228 }
1229 objectStartState:
1230 case ObjectStartState: {
1231 ASSERT(inValue.isObject());
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001232 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001233 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001234 JSObject* inObject = asObject(inValue);
1235 if (!startObject(inObject))
oliver@apple.come8641552010-12-20 22:40:37 +00001236 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +00001237 // At this point, all supported objects other than Object
1238 // objects have been handled. If we reach this point and
1239 // the input is not an Object object then we should throw
1240 // a DataCloneError.
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +00001241 if (inObject->classInfo() != JSFinalObject::info())
commit-queue@webkit.org597f0812012-08-20 21:12:55 +00001242 return DataCloneError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001243 inputObjectStack.append(inObject);
1244 indexStack.append(0);
1245 propertyStack.append(PropertyNameArray(m_exec));
mhahnenberg@apple.com57262382011-11-03 00:25:45 +00001246 inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001247 }
1248 objectStartVisitMember:
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00001249 FALLTHROUGH;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001250 case ObjectStartVisitMember: {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001251 JSObject* object = inputObjectStack.last();
1252 uint32_t index = indexStack.last();
1253 PropertyNameArray& properties = propertyStack.last();
1254 if (index == properties.size()) {
oliver@apple.come8641552010-12-20 22:40:37 +00001255 endObject();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001256 inputObjectStack.removeLast();
1257 indexStack.removeLast();
1258 propertyStack.removeLast();
1259 break;
1260 }
1261 inValue = getProperty(object, properties[index]);
1262 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +00001263 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001264
1265 if (!inValue) {
1266 // Property was removed during serialisation
1267 indexStack.last()++;
1268 goto objectStartVisitMember;
1269 }
1270 write(properties[index]);
1271
1272 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +00001273 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001274
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001275 SerializationReturnCode terminalCode = SuccessfullyCompleted;
1276 if (!dumpIfTerminal(inValue, terminalCode)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001277 stateStack.append(ObjectEndVisitMember);
1278 goto stateUnknown;
1279 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001280 if (terminalCode != SuccessfullyCompleted)
1281 return terminalCode;
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00001282 FALLTHROUGH;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001283 }
1284 case ObjectEndVisitMember: {
1285 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +00001286 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001287
1288 indexStack.last()++;
1289 goto objectStartVisitMember;
1290 }
oliver@apple.com901740c2013-09-03 23:21:10 +00001291 mapStartState: {
1292 ASSERT(inValue.isObject());
1293 if (inputObjectStack.size() > maximumFilterRecursion)
1294 return StackOverflowError;
1295 JSMap* inMap = jsCast<JSMap*>(inValue);
1296 if (!startMap(inMap))
1297 break;
1298 MapData* mapData = inMap->mapData();
1299 m_gcBuffer.append(mapData);
1300 mapDataStack.append(mapData);
1301 iteratorStack.append(mapData->begin());
1302 inputObjectStack.append(inMap);
1303 goto mapDataStartVisitEntry;
1304 }
1305 setStartState: {
1306 ASSERT(inValue.isObject());
1307 if (inputObjectStack.size() > maximumFilterRecursion)
1308 return StackOverflowError;
1309 JSSet* inSet = jsCast<JSSet*>(inValue);
1310 if (!startSet(inSet))
1311 break;
1312 MapData* mapData = inSet->mapData();
1313 m_gcBuffer.append(mapData);
1314 mapDataStack.append(mapData);
1315 iteratorStack.append(mapData->begin());
1316 inputObjectStack.append(inSet);
1317 goto mapDataStartVisitEntry;
1318 }
1319 mapDataStartVisitEntry:
1320 case MapDataStartVisitEntry: {
1321 MapData::const_iterator& ptr = iteratorStack.last();
1322 MapData* mapData = mapDataStack.last();
1323 if (ptr == mapData->end()) {
1324 iteratorStack.removeLast();
1325 mapDataStack.removeLast();
1326 JSObject* object = inputObjectStack.last();
1327 ASSERT(jsDynamicCast<JSSet*>(object) || jsDynamicCast<JSMap*>(object));
1328 propertyStack.append(PropertyNameArray(m_exec));
1329 object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
1330 write(NonMapPropertiesTag);
1331 indexStack.append(0);
1332 goto objectStartVisitMember;
1333 }
1334 inValue = ptr.key();
1335 stateStack.append(MapDataEndVisitKey);
1336 goto stateUnknown;
1337 }
1338 case MapDataEndVisitKey: {
1339 inValue = iteratorStack.last().value();
1340 stateStack.append(MapDataEndVisitValue);
1341 goto stateUnknown;
1342 }
1343 case MapDataEndVisitValue: {
1344 ++iteratorStack.last();
1345 goto mapDataStartVisitEntry;
1346 }
1347
oliver@apple.com8128fe12010-09-06 21:29:06 +00001348 stateUnknown:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001349 case StateUnknown: {
1350 SerializationReturnCode terminalCode = SuccessfullyCompleted;
1351 if (dumpIfTerminal(inValue, terminalCode)) {
1352 if (terminalCode != SuccessfullyCompleted)
1353 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001354 break;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001355 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001356
1357 if (isArray(inValue))
1358 goto arrayStartState;
oliver@apple.com901740c2013-09-03 23:21:10 +00001359 if (isMap(inValue))
1360 goto mapStartState;
1361 if (isSet(inValue))
1362 goto setStartState;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001363 goto objectStartState;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001364 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001365 }
1366 if (stateStack.isEmpty())
1367 break;
1368
1369 state = stateStack.last();
1370 stateStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001371 }
1372 if (m_failed)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001373 return UnspecifiedError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001374
slewis@apple.comfc28de52011-04-12 21:50:04 +00001375 return SuccessfullyCompleted;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001376}
1377
oliver@apple.comdf606082013-08-05 22:11:50 +00001378typedef Vector<JSC::ArrayBufferContents> ArrayBufferContentsArray;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001379
oliver@apple.com8128fe12010-09-06 21:29:06 +00001380class CloneDeserializer : CloneBase {
1381public:
1382 static String deserializeString(const Vector<uint8_t>& buffer)
1383 {
1384 const uint8_t* ptr = buffer.begin();
1385 const uint8_t* end = buffer.end();
1386 uint32_t version;
1387 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1388 return String();
1389 uint8_t tag;
1390 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1391 return String();
1392 uint32_t length;
1393 if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
1394 return String();
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001395 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001396 if (!readString(ptr, end, str, length))
1397 return String();
1398 return String(str.impl());
1399 }
1400
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001401 static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
1402 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001403 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001404 {
1405 if (!buffer.size())
andersca@apple.comff9adb82013-10-25 01:15:36 +00001406 return std::make_pair(jsNull(), UnspecifiedError);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001407 CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
slewis@apple.comfc28de52011-04-12 21:50:04 +00001408 if (!deserializer.isValid())
andersca@apple.comff9adb82013-10-25 01:15:36 +00001409 return std::make_pair(JSValue(), ValidationError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001410 return deserializer.deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001411 }
1412
1413private:
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001414 struct CachedString {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001415 CachedString(const String& string)
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001416 : m_string(string)
1417 {
1418 }
1419
1420 JSValue jsString(ExecState* exec)
1421 {
1422 if (!m_jsString)
1423 m_jsString = JSC::jsString(exec, m_string);
1424 return m_jsString;
1425 }
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001426 const String& string() { return m_string; }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001427
1428 private:
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001429 String m_string;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001430 JSValue m_jsString;
1431 };
1432
oliver@apple.com86609602010-10-19 02:33:33 +00001433 struct CachedStringRef {
1434 CachedStringRef()
1435 : m_base(0)
1436 , m_index(0)
1437 {
1438 }
1439 CachedStringRef(Vector<CachedString>* base, size_t index)
1440 : m_base(base)
1441 , m_index(index)
1442 {
1443 }
1444
1445 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1446
1447 private:
1448 Vector<CachedString>* m_base;
1449 size_t m_index;
1450 };
1451
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001452 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject,
1453 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
1454 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001455 : CloneBase(exec)
oliver@apple.com5deb8d82010-01-28 04:47:07 +00001456 , m_globalObject(globalObject)
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +00001457 , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info()))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001458 , m_ptr(buffer.data())
1459 , m_end(buffer.data() + buffer.size())
1460 , m_version(0xFFFFFFFF)
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001461 , m_messagePorts(messagePorts)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001462 , m_arrayBufferContents(arrayBufferContents)
1463 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001464 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001465 if (!read(m_version))
1466 m_version = 0xFFFFFFFF;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001467 }
1468
slewis@apple.comfc28de52011-04-12 21:50:04 +00001469 DeserializationResult deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001470
oliver@apple.com8128fe12010-09-06 21:29:06 +00001471 void throwValidationError()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001472 {
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00001473 m_exec->vm().throwException(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001474 }
1475
oliver@apple.com8128fe12010-09-06 21:29:06 +00001476 bool isValid() const { return m_version <= CurrentVersion; }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001477
oliver@apple.com8128fe12010-09-06 21:29:06 +00001478 template <typename T> bool readLittleEndian(T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001479 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001480 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1481 fail();
1482 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001483 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001484 return true;
1485 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001486#if ASSUME_LITTLE_ENDIAN
1487 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001488 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001489 if (ptr > end - sizeof(value))
1490 return false;
1491
1492 if (sizeof(T) == 1)
1493 value = *ptr++;
1494 else {
commit-queue@webkit.orgbfe8ef62010-10-13 19:21:48 +00001495 value = *reinterpret_cast<const T*>(ptr);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001496 ptr += sizeof(T);
1497 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001498 return true;
1499 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001500#else
1501 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001502 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001503 if (ptr > end - sizeof(value))
1504 return false;
1505
1506 if (sizeof(T) == 1)
1507 value = *ptr++;
1508 else {
1509 value = 0;
1510 for (unsigned i = 0; i < sizeof(T); i++)
1511 value += ((T)*ptr++) << (i * 8);
1512 }
1513 return true;
1514 }
1515#endif
1516
1517 bool read(uint32_t& i)
1518 {
1519 return readLittleEndian(i);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001520 }
1521
oliver@apple.com8128fe12010-09-06 21:29:06 +00001522 bool read(int32_t& i)
1523 {
1524 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1525 }
1526
1527 bool read(uint16_t& i)
1528 {
1529 return readLittleEndian(i);
1530 }
1531
1532 bool read(uint8_t& i)
1533 {
1534 return readLittleEndian(i);
1535 }
1536
1537 bool read(double& d)
1538 {
1539 union {
1540 double d;
1541 uint64_t i64;
1542 } u;
1543 if (!readLittleEndian(u.i64))
1544 return false;
1545 d = u.d;
1546 return true;
1547 }
1548
1549 bool read(unsigned long long& i)
1550 {
1551 return readLittleEndian(i);
1552 }
1553
1554 bool readStringIndex(uint32_t& i)
1555 {
oliver@apple.come8641552010-12-20 22:40:37 +00001556 return readConstantPoolIndex(m_constantPool, i);
1557 }
1558
1559 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1560 {
1561 if (constantPool.size() <= 0xFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001562 uint8_t i8;
1563 if (!read(i8))
1564 return false;
1565 i = i8;
1566 return true;
1567 }
oliver@apple.come8641552010-12-20 22:40:37 +00001568 if (constantPool.size() <= 0xFFFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001569 uint16_t i16;
1570 if (!read(i16))
1571 return false;
1572 i = i16;
1573 return true;
1574 }
1575 return read(i);
1576 }
1577
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001578 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001579 {
andersca@apple.comff9adb82013-10-25 01:15:36 +00001580 if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001581 return false;
1582
1583 unsigned size = length * sizeof(UChar);
1584 if ((end - ptr) < static_cast<int>(size))
1585 return false;
1586
1587#if ASSUME_LITTLE_ENDIAN
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001588 str = String(reinterpret_cast<const UChar*>(ptr), length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001589 ptr += length * sizeof(UChar);
1590#else
1591 Vector<UChar> buffer;
1592 buffer.reserveCapacity(length);
1593 for (unsigned i = 0; i < length; i++) {
1594 uint16_t ch;
1595 readLittleEndian(ptr, end, ch);
1596 buffer.append(ch);
1597 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001598 str = String::adopt(buffer);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001599#endif
1600 return true;
1601 }
1602
oliver@apple.com86609602010-10-19 02:33:33 +00001603 bool readStringData(CachedStringRef& cachedString)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001604 {
1605 bool scratch;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001606 return readStringData(cachedString, scratch);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001607 }
1608
oliver@apple.com86609602010-10-19 02:33:33 +00001609 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001610 {
1611 if (m_failed)
1612 return false;
1613 uint32_t length = 0;
1614 if (!read(length))
1615 return false;
1616 if (length == TerminatorTag) {
1617 wasTerminator = true;
1618 return false;
1619 }
1620 if (length == StringPoolTag) {
1621 unsigned index = 0;
1622 if (!readStringIndex(index)) {
1623 fail();
1624 return false;
1625 }
1626 if (index >= m_constantPool.size()) {
1627 fail();
1628 return false;
1629 }
oliver@apple.com86609602010-10-19 02:33:33 +00001630 cachedString = CachedStringRef(&m_constantPool, index);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001631 return true;
1632 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001633 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001634 if (!readString(m_ptr, m_end, str, length)) {
1635 fail();
1636 return false;
1637 }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001638 m_constantPool.append(str);
oliver@apple.com86609602010-10-19 02:33:33 +00001639 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001640 return true;
1641 }
1642
1643 SerializationTag readTag()
1644 {
1645 if (m_ptr >= m_end)
1646 return ErrorTag;
1647 return static_cast<SerializationTag>(*m_ptr++);
1648 }
1649
dslomov@google.coma3962422012-02-23 02:51:20 +00001650 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
1651 {
1652 if (m_ptr >= m_end)
1653 return false;
1654 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
1655 return true;
1656 }
1657
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001658 void putProperty(JSObject* object, unsigned index, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001659 {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001660 object->putDirectIndex(m_exec, index, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001661 }
1662
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001663 void putProperty(JSObject* object, const Identifier& property, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001664 {
fpizlo@apple.com904bab82012-09-25 05:27:33 +00001665 object->putDirectMayBeIndex(m_exec, property, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001666 }
1667
1668 bool readFile(RefPtr<File>& file)
1669 {
oliver@apple.com86609602010-10-19 02:33:33 +00001670 CachedStringRef path;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001671 if (!readStringData(path))
1672 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001673 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001674 if (!readStringData(url))
1675 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001676 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001677 if (!readStringData(type))
1678 return 0;
commit-queue@webkit.orgfa990e92010-09-10 16:19:57 +00001679 if (m_isDOMGlobalObject)
darin@apple.com5ffbb5c2013-09-27 16:39:41 +00001680 file = File::create(path->string(), URL(URL(), url->string()), type->string());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001681 return true;
1682 }
1683
dslomov@google.coma3962422012-02-23 02:51:20 +00001684 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
1685 {
1686 uint32_t length;
1687 if (!read(length))
1688 return false;
1689 if (m_ptr + length > m_end)
1690 return false;
1691 arrayBuffer = ArrayBuffer::create(m_ptr, length);
1692 m_ptr += length;
1693 return true;
1694 }
1695
1696 bool readArrayBufferView(JSValue& arrayBufferView)
1697 {
1698 ArrayBufferViewSubtag arrayBufferViewSubtag;
1699 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
1700 return false;
1701 uint32_t byteOffset;
1702 if (!read(byteOffset))
1703 return false;
1704 uint32_t byteLength;
1705 if (!read(byteLength))
1706 return false;
1707 JSObject* arrayBufferObj = asObject(readTerminal());
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +00001708 if (!arrayBufferObj || !arrayBufferObj->inherits(JSArrayBuffer::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +00001709 return false;
1710
1711 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
1712 if (!elementSize)
1713 return false;
1714 unsigned length = byteLength / elementSize;
1715 if (length * elementSize != byteLength)
1716 return false;
1717
1718 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj);
1719 switch (arrayBufferViewSubtag) {
1720 case DataViewTag:
1721 arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get());
1722 return true;
1723 case Int8ArrayTag:
1724 arrayBufferView = getJSValue(Int8Array::create(arrayBuffer, byteOffset, length).get());
1725 return true;
1726 case Uint8ArrayTag:
1727 arrayBufferView = getJSValue(Uint8Array::create(arrayBuffer, byteOffset, length).get());
1728 return true;
1729 case Uint8ClampedArrayTag:
1730 arrayBufferView = getJSValue(Uint8ClampedArray::create(arrayBuffer, byteOffset, length).get());
1731 return true;
1732 case Int16ArrayTag:
1733 arrayBufferView = getJSValue(Int16Array::create(arrayBuffer, byteOffset, length).get());
1734 return true;
1735 case Uint16ArrayTag:
1736 arrayBufferView = getJSValue(Uint16Array::create(arrayBuffer, byteOffset, length).get());
1737 return true;
1738 case Int32ArrayTag:
1739 arrayBufferView = getJSValue(Int32Array::create(arrayBuffer, byteOffset, length).get());
1740 return true;
1741 case Uint32ArrayTag:
1742 arrayBufferView = getJSValue(Uint32Array::create(arrayBuffer, byteOffset, length).get());
1743 return true;
1744 case Float32ArrayTag:
1745 arrayBufferView = getJSValue(Float32Array::create(arrayBuffer, byteOffset, length).get());
1746 return true;
1747 case Float64ArrayTag:
1748 arrayBufferView = getJSValue(Float64Array::create(arrayBuffer, byteOffset, length).get());
1749 return true;
1750 default:
1751 return false;
1752 }
1753 }
1754
ap@apple.com351ac9c2013-12-11 22:13:55 +00001755 bool read(Vector<uint8_t>& result)
1756 {
1757 ASSERT(result.isEmpty());
1758 uint32_t size;
1759 if (!read(size))
1760 return false;
1761 if (m_ptr + size > m_end)
1762 return false;
1763 result.append(m_ptr, size);
1764 m_ptr += size;
1765 return true;
1766 }
1767
1768#if ENABLE(SUBTLE_CRYPTO)
1769 bool read(CryptoAlgorithmIdentifier& result)
1770 {
1771 uint8_t algorithmTag;
1772 if (!read(algorithmTag))
1773 return false;
1774 if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
1775 return false;
1776 switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
1777 case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
1778 result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
1779 break;
1780 case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
1781 result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
1782 break;
1783 case CryptoAlgorithmIdentifierTag::RSA_PSS:
1784 result = CryptoAlgorithmIdentifier::RSA_PSS;
1785 break;
1786 case CryptoAlgorithmIdentifierTag::RSA_OAEP:
1787 result = CryptoAlgorithmIdentifier::RSA_OAEP;
1788 break;
1789 case CryptoAlgorithmIdentifierTag::ECDSA:
1790 result = CryptoAlgorithmIdentifier::ECDSA;
1791 break;
1792 case CryptoAlgorithmIdentifierTag::ECDH:
1793 result = CryptoAlgorithmIdentifier::ECDH;
1794 break;
1795 case CryptoAlgorithmIdentifierTag::AES_CTR:
1796 result = CryptoAlgorithmIdentifier::AES_CTR;
1797 break;
1798 case CryptoAlgorithmIdentifierTag::AES_CBC:
1799 result = CryptoAlgorithmIdentifier::AES_CBC;
1800 break;
1801 case CryptoAlgorithmIdentifierTag::AES_CMAC:
1802 result = CryptoAlgorithmIdentifier::AES_CMAC;
1803 break;
1804 case CryptoAlgorithmIdentifierTag::AES_GCM:
1805 result = CryptoAlgorithmIdentifier::AES_GCM;
1806 break;
1807 case CryptoAlgorithmIdentifierTag::AES_CFB:
1808 result = CryptoAlgorithmIdentifier::AES_CFB;
1809 break;
1810 case CryptoAlgorithmIdentifierTag::AES_KW:
1811 result = CryptoAlgorithmIdentifier::AES_KW;
1812 break;
1813 case CryptoAlgorithmIdentifierTag::HMAC:
1814 result = CryptoAlgorithmIdentifier::HMAC;
1815 break;
1816 case CryptoAlgorithmIdentifierTag::DH:
1817 result = CryptoAlgorithmIdentifier::DH;
1818 break;
1819 case CryptoAlgorithmIdentifierTag::SHA_1:
1820 result = CryptoAlgorithmIdentifier::SHA_1;
1821 break;
1822 case CryptoAlgorithmIdentifierTag::SHA_224:
1823 result = CryptoAlgorithmIdentifier::SHA_224;
1824 break;
1825 case CryptoAlgorithmIdentifierTag::SHA_256:
1826 result = CryptoAlgorithmIdentifier::SHA_256;
1827 break;
1828 case CryptoAlgorithmIdentifierTag::SHA_384:
1829 result = CryptoAlgorithmIdentifier::SHA_384;
1830 break;
1831 case CryptoAlgorithmIdentifierTag::SHA_512:
1832 result = CryptoAlgorithmIdentifier::SHA_512;
1833 break;
1834 case CryptoAlgorithmIdentifierTag::CONCAT:
1835 result = CryptoAlgorithmIdentifier::CONCAT;
1836 break;
1837 case CryptoAlgorithmIdentifierTag::HKDF_CTR:
1838 result = CryptoAlgorithmIdentifier::HKDF_CTR;
1839 break;
1840 case CryptoAlgorithmIdentifierTag::PBKDF2:
1841 result = CryptoAlgorithmIdentifier::PBKDF2;
1842 break;
1843 }
1844 return true;
1845 }
1846
1847 bool read(CryptoKeyClassSubtag& result)
1848 {
1849 uint8_t tag;
1850 if (!read(tag))
1851 return false;
1852 if (tag > cryptoKeyClassSubtagMaximumValue)
1853 return false;
1854 result = static_cast<CryptoKeyClassSubtag>(tag);
1855 return true;
1856 }
1857
1858 bool read(CryptoKeyUsageTag& result)
1859 {
1860 uint8_t tag;
1861 if (!read(tag))
1862 return false;
1863 if (tag > cryptoKeyUsageTagMaximumValue)
1864 return false;
1865 result = static_cast<CryptoKeyUsageTag>(tag);
1866 return true;
1867 }
1868
1869 bool read(CryptoKeyAsymmetricTypeSubtag& result)
1870 {
1871 uint8_t tag;
1872 if (!read(tag))
1873 return false;
1874 if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
1875 return false;
1876 result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
1877 return true;
1878 }
1879
1880 bool readHMACKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
1881 {
1882 Vector<uint8_t> keyData;
1883 if (!read(keyData))
1884 return false;
1885 CryptoAlgorithmIdentifier hash;
1886 if (!read(hash))
1887 return false;
1888 result = CryptoKeyHMAC::create(keyData, hash, extractable, usages);
1889 return true;
1890 }
1891
1892 bool readAESKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
1893 {
1894 CryptoAlgorithmIdentifier algorithm;
1895 if (!read(algorithm))
1896 return false;
1897 if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
1898 return false;
1899 Vector<uint8_t> keyData;
1900 if (!read(keyData))
1901 return false;
1902 result = CryptoKeyAES::create(algorithm, keyData, extractable, usages);
1903 return true;
1904 }
1905
1906 bool readRSAKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
1907 {
1908 CryptoAlgorithmIdentifier algorithm;
1909 if (!read(algorithm))
1910 return false;
1911
1912 int32_t isRestrictedToHash;
1913 CryptoAlgorithmIdentifier hash;
1914 if (!read(isRestrictedToHash))
1915 return false;
1916 if (isRestrictedToHash && !read(hash))
1917 return false;
1918
1919 CryptoKeyAsymmetricTypeSubtag type;
1920 if (!read(type))
1921 return false;
1922
1923 Vector<uint8_t> modulus;
1924 if (!read(modulus))
1925 return false;
1926 Vector<uint8_t> exponent;
1927 if (!read(exponent))
1928 return false;
1929
1930 if (type == CryptoKeyAsymmetricTypeSubtag::Public) {
1931 auto keyData = CryptoKeyDataRSAComponents::createPublic(modulus, exponent);
1932 auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
1933 if (isRestrictedToHash)
1934 key->restrictToHash(hash);
1935 result = std::move(key);
1936 return true;
1937 }
1938
1939 Vector<uint8_t> privateExponent;
1940 if (!read(privateExponent))
1941 return false;
1942
1943 uint32_t primeCount;
1944 if (!read(primeCount))
1945 return false;
1946
1947 if (!primeCount) {
1948 auto keyData = CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent);
1949 auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
1950 if (isRestrictedToHash)
1951 key->restrictToHash(hash);
1952 result = std::move(key);
1953 return true;
1954 }
1955
1956 if (primeCount < 2)
1957 return false;
1958
1959 CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
1960 CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
1961 Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
1962
1963 if (!read(firstPrimeInfo.primeFactor))
1964 return false;
1965 if (!read(firstPrimeInfo.factorCRTExponent))
1966 return false;
1967 if (!read(secondPrimeInfo.primeFactor))
1968 return false;
1969 if (!read(secondPrimeInfo.factorCRTExponent))
1970 return false;
1971 if (!read(secondPrimeInfo.factorCRTCoefficient))
1972 return false;
1973 for (unsigned i = 2; i < primeCount; ++i) {
1974 if (!read(otherPrimeInfos[i].primeFactor))
1975 return false;
1976 if (!read(otherPrimeInfos[i].factorCRTExponent))
1977 return false;
1978 if (!read(otherPrimeInfos[i].factorCRTCoefficient))
1979 return false;
1980 }
1981
1982 auto keyData = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
1983 auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
1984 if (isRestrictedToHash)
1985 key->restrictToHash(hash);
1986 result = std::move(key);
1987 return true;
1988 }
1989
1990 bool readCryptoKey(JSValue& cryptoKey)
1991 {
1992 int32_t extractable;
1993 if (!read(extractable))
1994 return false;
1995
1996 uint32_t usagesCount;
1997 if (!read(usagesCount))
1998 return false;
1999
2000 CryptoKeyUsage usages = 0;
2001 for (uint32_t i = 0; i < usagesCount; ++i) {
2002 CryptoKeyUsageTag usage;
2003 if (!read(usage))
2004 return false;
2005 switch (usage) {
2006 case CryptoKeyUsageTag::Encrypt:
2007 usages |= CryptoKeyUsageEncrypt;
2008 break;
2009 case CryptoKeyUsageTag::Decrypt:
2010 usages |= CryptoKeyUsageDecrypt;
2011 break;
2012 case CryptoKeyUsageTag::Sign:
2013 usages |= CryptoKeyUsageSign;
2014 break;
2015 case CryptoKeyUsageTag::Verify:
2016 usages |= CryptoKeyUsageVerify;
2017 break;
2018 case CryptoKeyUsageTag::DeriveKey:
2019 usages |= CryptoKeyUsageDeriveKey;
2020 break;
2021 case CryptoKeyUsageTag::DeriveBits:
2022 usages |= CryptoKeyUsageDeriveBits;
2023 break;
2024 case CryptoKeyUsageTag::WrapKey:
2025 usages |= CryptoKeyUsageWrapKey;
2026 break;
2027 case CryptoKeyUsageTag::UnwrapKey:
2028 usages |= CryptoKeyUsageUnwrapKey;
2029 break;
2030 }
2031 }
2032
2033 CryptoKeyClassSubtag cryptoKeyClass;
2034 if (!read(cryptoKeyClass))
2035 return false;
2036 RefPtr<CryptoKey> result;
2037 switch (cryptoKeyClass) {
2038 case CryptoKeyClassSubtag::HMAC:
2039 if (!readHMACKey(extractable, usages, result))
2040 return false;
2041 break;
2042 case CryptoKeyClassSubtag::AES:
2043 if (!readAESKey(extractable, usages, result))
2044 return false;
2045 break;
2046 case CryptoKeyClassSubtag::RSA:
2047 if (!readRSAKey(extractable, usages, result))
2048 return false;
2049 break;
2050 }
2051 cryptoKey = getJSValue(result.get());
2052 return true;
2053 }
2054#endif
2055
dslomov@google.coma3962422012-02-23 02:51:20 +00002056 template<class T>
2057 JSValue getJSValue(T* nativeObj)
2058 {
oliver@apple.comffe14422012-04-05 22:33:19 +00002059 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
dslomov@google.coma3962422012-02-23 02:51:20 +00002060 }
2061
oliver@apple.com8128fe12010-09-06 21:29:06 +00002062 JSValue readTerminal()
2063 {
2064 SerializationTag tag = readTag();
2065 switch (tag) {
2066 case UndefinedTag:
2067 return jsUndefined();
2068 case NullTag:
2069 return jsNull();
2070 case IntTag: {
2071 int32_t i;
2072 if (!read(i))
2073 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00002074 return jsNumber(i);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002075 }
2076 case ZeroTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00002077 return jsNumber(0);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002078 case OneTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00002079 return jsNumber(1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002080 case FalseTag:
2081 return jsBoolean(false);
2082 case TrueTag:
2083 return jsBoolean(true);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002084 case FalseObjectTag: {
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00002085 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2086 obj->setInternalValue(m_exec->vm(), jsBoolean(false));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002087 m_gcBuffer.append(obj);
2088 return obj;
2089 }
2090 case TrueObjectTag: {
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00002091 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
2092 obj->setInternalValue(m_exec->vm(), jsBoolean(true));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002093 m_gcBuffer.append(obj);
2094 return obj;
2095 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002096 case DoubleTag: {
2097 double d;
2098 if (!read(d))
2099 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00002100 return jsNumber(d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002101 }
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002102 case NumberObjectTag: {
2103 double d;
2104 if (!read(d))
2105 return JSValue();
2106 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
2107 m_gcBuffer.append(obj);
2108 return obj;
2109 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002110 case DateTag: {
2111 double d;
2112 if (!read(d))
2113 return JSValue();
akling@apple.comb34659a2013-09-29 22:20:26 +00002114 return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002115 }
2116 case FileTag: {
2117 RefPtr<File> file;
2118 if (!readFile(file))
2119 return JSValue();
2120 if (!m_isDOMGlobalObject)
2121 return jsNull();
oliver@apple.comffe14422012-04-05 22:33:19 +00002122 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00002123 }
2124 case FileListTag: {
2125 unsigned length = 0;
2126 if (!read(length))
2127 return JSValue();
2128 RefPtr<FileList> result = FileList::create();
2129 for (unsigned i = 0; i < length; i++) {
2130 RefPtr<File> file;
2131 if (!readFile(file))
2132 return JSValue();
2133 if (m_isDOMGlobalObject)
2134 result->append(file.get());
2135 }
2136 if (!m_isDOMGlobalObject)
2137 return jsNull();
dslomov@google.coma3962422012-02-23 02:51:20 +00002138 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00002139 }
2140 case ImageDataTag: {
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00002141 int32_t width;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002142 if (!read(width))
2143 return JSValue();
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00002144 int32_t height;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002145 if (!read(height))
2146 return JSValue();
2147 uint32_t length;
2148 if (!read(length))
2149 return JSValue();
2150 if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
2151 fail();
2152 return JSValue();
2153 }
2154 if (!m_isDOMGlobalObject) {
2155 m_ptr += length;
2156 return jsNull();
2157 }
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00002158 RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
kbr@google.com1262e442012-04-24 03:43:31 +00002159 memcpy(result->data()->data(), m_ptr, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002160 m_ptr += length;
dslomov@google.coma3962422012-02-23 02:51:20 +00002161 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00002162 }
2163 case BlobTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00002164 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002165 if (!readStringData(url))
2166 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00002167 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002168 if (!readStringData(type))
2169 return JSValue();
2170 unsigned long long size = 0;
2171 if (!read(size))
2172 return JSValue();
2173 if (!m_isDOMGlobalObject)
2174 return jsNull();
darin@apple.com5ffbb5c2013-09-27 16:39:41 +00002175 return getJSValue(Blob::create(URL(URL(), url->string()), type->string(), size).get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00002176 }
2177 case StringTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00002178 CachedStringRef cachedString;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00002179 if (!readStringData(cachedString))
oliver@apple.com8128fe12010-09-06 21:29:06 +00002180 return JSValue();
oliver@apple.comaf02ea32010-09-10 19:52:53 +00002181 return cachedString->jsString(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002182 }
2183 case EmptyStringTag:
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00002184 return jsEmptyString(&m_exec->vm());
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002185 case StringObjectTag: {
2186 CachedStringRef cachedString;
2187 if (!readStringData(cachedString))
2188 return JSValue();
akling@apple.com019809c2013-10-06 18:16:48 +00002189 StringObject* obj = constructString(m_exec->vm(), m_globalObject, cachedString->jsString(m_exec));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002190 m_gcBuffer.append(obj);
2191 return obj;
2192 }
2193 case EmptyStringObjectTag: {
akling@apple.com019809c2013-10-06 18:16:48 +00002194 VM& vm = m_exec->vm();
2195 StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(&vm));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00002196 m_gcBuffer.append(obj);
2197 return obj;
2198 }
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00002199 case RegExpTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00002200 CachedStringRef pattern;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00002201 if (!readStringData(pattern))
2202 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00002203 CachedStringRef flags;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00002204 if (!readStringData(flags))
2205 return JSValue();
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00002206 RegExpFlags reFlags = regExpFlags(flags->string());
barraclough@apple.com12812932011-03-09 23:04:27 +00002207 ASSERT(reFlags != InvalidFlags);
akling@apple.com8662c392013-09-30 18:58:51 +00002208 VM& vm = m_exec->vm();
2209 RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags);
2210 return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00002211 }
oliver@apple.come8641552010-12-20 22:40:37 +00002212 case ObjectReferenceTag: {
2213 unsigned index = 0;
2214 if (!readConstantPoolIndex(m_gcBuffer, index)) {
2215 fail();
2216 return JSValue();
2217 }
2218 return m_gcBuffer.at(index);
2219 }
dslomov@google.comd60d08e2011-10-31 21:07:22 +00002220 case MessagePortReferenceTag: {
2221 uint32_t index;
2222 bool indexSuccessfullyRead = read(index);
2223 if (!indexSuccessfullyRead || !m_messagePorts || index >= m_messagePorts->size()) {
2224 fail();
2225 return JSValue();
2226 }
dslomov@google.coma3962422012-02-23 02:51:20 +00002227 return getJSValue(m_messagePorts->at(index).get());
2228 }
2229 case ArrayBufferTag: {
2230 RefPtr<ArrayBuffer> arrayBuffer;
2231 if (!readArrayBuffer(arrayBuffer)) {
2232 fail();
2233 return JSValue();
2234 }
2235 JSValue result = getJSValue(arrayBuffer.get());
2236 m_gcBuffer.append(result);
2237 return result;
2238 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002239 case ArrayBufferTransferTag: {
2240 uint32_t index;
2241 bool indexSuccessfullyRead = read(index);
2242 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
2243 fail();
2244 return JSValue();
2245 }
2246
2247 if (!m_arrayBuffers[index])
2248 m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
2249
2250 return getJSValue(m_arrayBuffers[index].get());
2251 }
dslomov@google.coma3962422012-02-23 02:51:20 +00002252 case ArrayBufferViewTag: {
2253 JSValue arrayBufferView;
2254 if (!readArrayBufferView(arrayBufferView)) {
2255 fail();
2256 return JSValue();
2257 }
2258 m_gcBuffer.append(arrayBufferView);
2259 return arrayBufferView;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00002260 }
ap@apple.com351ac9c2013-12-11 22:13:55 +00002261#if ENABLE(SUBTLE_CRYPTO)
2262 case CryptoKeyTag: {
2263 JSValue cryptoKey;
2264 if (!readCryptoKey(cryptoKey)) {
2265 fail();
2266 return JSValue();
2267 }
2268 m_gcBuffer.append(cryptoKey);
2269 return cryptoKey;
2270 }
2271#endif
oliver@apple.com8128fe12010-09-06 21:29:06 +00002272 default:
2273 m_ptr--; // Push the tag back
2274 return JSValue();
2275 }
2276 }
2277
oliver@apple.com901740c2013-09-03 23:21:10 +00002278 bool consumeMapDataTerminationIfPossible()
2279 {
2280 if (readTag() == NonMapPropertiesTag)
2281 return true;
2282 m_ptr--;
2283 return false;
2284 }
2285
oliver@apple.com02a5f152010-01-24 22:54:18 +00002286 JSGlobalObject* m_globalObject;
2287 bool m_isDOMGlobalObject;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002288 const uint8_t* m_ptr;
2289 const uint8_t* m_end;
2290 unsigned m_version;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00002291 Vector<CachedString> m_constantPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00002292 MessagePortArray* m_messagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002293 ArrayBufferContentsArray* m_arrayBufferContents;
2294 ArrayBufferArray m_arrayBuffers;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002295};
2296
slewis@apple.comfc28de52011-04-12 21:50:04 +00002297DeserializationResult CloneDeserializer::deserialize()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002298{
oliver@apple.com8128fe12010-09-06 21:29:06 +00002299 Vector<uint32_t, 16> indexStack;
2300 Vector<Identifier, 16> propertyNameStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002301 Vector<JSObject*, 32> outputObjectStack;
oliver@apple.com901740c2013-09-03 23:21:10 +00002302 Vector<JSValue, 4> keyStack;
2303 Vector<MapData*, 4> mapDataStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002304 Vector<WalkerState, 16> stateStack;
2305 WalkerState state = StateUnknown;
2306 JSValue outValue;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002307
oliver@apple.com8128fe12010-09-06 21:29:06 +00002308 while (1) {
2309 switch (state) {
2310 arrayStartState:
2311 case ArrayStartState: {
2312 uint32_t length;
2313 if (!read(length)) {
2314 fail();
2315 goto error;
2316 }
fpizlo@apple.com75c91a72012-11-08 22:28:25 +00002317 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002318 m_gcBuffer.append(outArray);
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002319 outputObjectStack.append(outArray);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002320 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002321 arrayStartVisitMember:
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002322 FALLTHROUGH;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002323 case ArrayStartVisitMember: {
oliver@apple.com8128fe12010-09-06 21:29:06 +00002324 uint32_t index;
2325 if (!read(index)) {
2326 fail();
2327 goto error;
2328 }
2329 if (index == TerminatorTag) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002330 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002331 outValue = outArray;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002332 outputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002333 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002334 } else if (index == NonIndexPropertiesTag) {
2335 goto objectStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002336 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002337
oliver@apple.com8128fe12010-09-06 21:29:06 +00002338 if (JSValue terminal = readTerminal()) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002339 putProperty(outputObjectStack.last(), index, terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002340 goto arrayStartVisitMember;
2341 }
2342 if (m_failed)
2343 goto error;
2344 indexStack.append(index);
2345 stateStack.append(ArrayEndVisitMember);
2346 goto stateUnknown;
2347 }
2348 case ArrayEndVisitMember: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002349 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002350 putProperty(outArray, indexStack.last(), outValue);
2351 indexStack.removeLast();
2352 goto arrayStartVisitMember;
2353 }
2354 objectStartState:
2355 case ObjectStartState: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00002356 if (outputObjectStack.size() > maximumFilterRecursion)
andersca@apple.comff9adb82013-10-25 01:15:36 +00002357 return std::make_pair(JSValue(), StackOverflowError);
ggaren@apple.comc862eac2013-01-29 05:48:01 +00002358 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
oliver@apple.com8128fe12010-09-06 21:29:06 +00002359 m_gcBuffer.append(outObject);
2360 outputObjectStack.append(outObject);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002361 }
2362 objectStartVisitMember:
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002363 FALLTHROUGH;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002364 case ObjectStartVisitMember: {
oliver@apple.com86609602010-10-19 02:33:33 +00002365 CachedStringRef cachedString;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002366 bool wasTerminator = false;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00002367 if (!readStringData(cachedString, wasTerminator)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00002368 if (!wasTerminator)
2369 goto error;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00002370
oliver@apple.com8128fe12010-09-06 21:29:06 +00002371 JSObject* outObject = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002372 outValue = outObject;
2373 outputObjectStack.removeLast();
2374 break;
2375 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002376
oliver@apple.com8128fe12010-09-06 21:29:06 +00002377 if (JSValue terminal = readTerminal()) {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00002378 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->string()), terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002379 goto objectStartVisitMember;
2380 }
2381 stateStack.append(ObjectEndVisitMember);
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00002382 propertyNameStack.append(Identifier(m_exec, cachedString->string()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00002383 goto stateUnknown;
2384 }
2385 case ObjectEndVisitMember: {
2386 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
2387 propertyNameStack.removeLast();
2388 goto objectStartVisitMember;
2389 }
oliver@apple.com901740c2013-09-03 23:21:10 +00002390 mapObjectStartState: {
2391 if (outputObjectStack.size() > maximumFilterRecursion)
andersca@apple.comff9adb82013-10-25 01:15:36 +00002392 return std::make_pair(JSValue(), StackOverflowError);
oliver@apple.com901740c2013-09-03 23:21:10 +00002393 JSMap* map = JSMap::create(m_exec->vm(), m_globalObject->mapStructure());
2394 m_gcBuffer.append(map);
2395 outputObjectStack.append(map);
2396 MapData* mapData = map->mapData();
2397 mapDataStack.append(mapData);
2398 goto mapDataStartVisitEntry;
2399 }
2400 setObjectStartState: {
2401 if (outputObjectStack.size() > maximumFilterRecursion)
andersca@apple.comff9adb82013-10-25 01:15:36 +00002402 return std::make_pair(JSValue(), StackOverflowError);
oliver@apple.com901740c2013-09-03 23:21:10 +00002403 JSSet* set = JSSet::create(m_exec->vm(), m_globalObject->setStructure());
2404 m_gcBuffer.append(set);
2405 outputObjectStack.append(set);
2406 MapData* mapData = set->mapData();
2407 mapDataStack.append(mapData);
2408 goto mapDataStartVisitEntry;
2409 }
2410 mapDataStartVisitEntry:
2411 case MapDataStartVisitEntry: {
2412 if (consumeMapDataTerminationIfPossible()) {
2413 mapDataStack.removeLast();
2414 goto objectStartVisitMember;
2415 }
2416 stateStack.append(MapDataEndVisitKey);
2417 goto stateUnknown;
2418 }
2419
2420 case MapDataEndVisitKey: {
2421 keyStack.append(outValue);
2422 stateStack.append(MapDataEndVisitValue);
2423 goto stateUnknown;
2424 }
2425
2426 case MapDataEndVisitValue: {
2427 mapDataStack.last()->set(m_exec, keyStack.last(), outValue);
2428 keyStack.removeLast();
2429 goto mapDataStartVisitEntry;
2430 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002431 stateUnknown:
2432 case StateUnknown:
2433 if (JSValue terminal = readTerminal()) {
2434 outValue = terminal;
2435 break;
2436 }
2437 SerializationTag tag = readTag();
2438 if (tag == ArrayTag)
2439 goto arrayStartState;
2440 if (tag == ObjectTag)
2441 goto objectStartState;
oliver@apple.com901740c2013-09-03 23:21:10 +00002442 if (tag == MapObjectTag)
2443 goto mapObjectStartState;
2444 if (tag == SetObjectTag)
2445 goto setObjectStartState;
oliver@apple.com8128fe12010-09-06 21:29:06 +00002446 goto error;
2447 }
2448 if (stateStack.isEmpty())
2449 break;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002450
oliver@apple.com8128fe12010-09-06 21:29:06 +00002451 state = stateStack.last();
2452 stateStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002453 }
2454 ASSERT(outValue);
2455 ASSERT(!m_failed);
andersca@apple.comff9adb82013-10-25 01:15:36 +00002456 return std::make_pair(outValue, SuccessfullyCompleted);
oliver@apple.com8128fe12010-09-06 21:29:06 +00002457error:
2458 fail();
andersca@apple.comff9adb82013-10-25 01:15:36 +00002459 return std::make_pair(JSValue(), ValidationError);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002460}
2461
oliver@apple.com8128fe12010-09-06 21:29:06 +00002462
2463
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002464SerializedScriptValue::~SerializedScriptValue()
2465{
2466}
2467
commit-queue@webkit.org7632ff22012-12-17 23:59:47 +00002468SerializedScriptValue::SerializedScriptValue(const Vector<uint8_t>& buffer)
2469 : m_data(buffer)
2470{
2471}
2472
oliver@apple.com8128fe12010-09-06 21:29:06 +00002473SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
2474{
2475 m_data.swap(buffer);
2476}
2477
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00002478SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs)
2479{
2480 m_data.swap(buffer);
2481 m_blobURLs.swap(blobURLs);
2482}
2483
2484SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002485 : m_arrayBufferContentsArray(arrayBufferContentsArray)
2486{
2487 m_data.swap(buffer);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00002488 m_blobURLs.swap(blobURLs);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002489}
2490
2491PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002492 ExecState* exec, ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002493{
2494 for (size_t i = 0; i < arrayBuffers.size(); i++) {
2495 if (arrayBuffers[i]->isNeutered()) {
2496 code = ValidationError;
2497 return nullptr;
2498 }
2499 }
2500
2501 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
weinig@apple.com8f716032013-10-02 17:03:09 +00002502 Vector<Ref<DOMWrapperWorld>> worlds;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002503 static_cast<WebCoreJSClientData*>(exec->vm().clientData)->getAllWorlds(worlds);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002504
oliver@apple.comdf606082013-08-05 22:11:50 +00002505 HashSet<JSC::ArrayBuffer*> visited;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002506 for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002507 if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002508 continue;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002509 visited.add(arrayBuffers[arrayBufferIndex].get());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002510
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +00002511 bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex));
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002512 if (!result) {
2513 code = ValidationError;
2514 return nullptr;
2515 }
2516 }
2517 return contents.release();
2518}
2519
2520
2521PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value,
2522 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
2523 SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00002524{
2525 Vector<uint8_t> buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00002526 Vector<String> blobURLs;
2527 SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, blobURLs, buffer);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002528
2529 OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
2530
2531 if (arrayBuffers && serializationDidCompleteSuccessfully(code))
fpizlo@apple.coma9188442013-08-01 22:14:28 +00002532 arrayBufferContentsArray = transferArrayBuffers(exec, *arrayBuffers, code);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002533
slewis@apple.comd0a103d2011-04-13 00:13:11 +00002534 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00002535 maybeThrowExceptionIfSerializationFailed(exec, code);
2536
2537 if (!serializationDidCompleteSuccessfully(code))
oliver@apple.com8128fe12010-09-06 21:29:06 +00002538 return 0;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002539
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00002540 return adoptRef(new SerializedScriptValue(buffer, blobURLs, arrayBufferContentsArray.release()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00002541}
2542
tony@chromium.org6b09aa62011-06-24 06:43:34 +00002543PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
oliver@apple.com8128fe12010-09-06 21:29:06 +00002544{
2545 Vector<uint8_t> buffer;
2546 if (!CloneSerializer::serialize(string, buffer))
2547 return 0;
2548 return adoptRef(new SerializedScriptValue(buffer));
2549}
2550
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00002551#if ENABLE(INDEXED_DATABASE)
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00002552PassRefPtr<SerializedScriptValue> SerializedScriptValue::numberValue(double value)
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00002553{
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00002554 Vector<uint8_t> buffer;
2555 CloneSerializer::serializeNumber(value, buffer);
2556 return adoptRef(new SerializedScriptValue(buffer));
2557}
2558
ap@apple.com3bd8fb62014-02-08 01:09:56 +00002559PassRefPtr<SerializedScriptValue> SerializedScriptValue::undefinedValue()
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00002560{
ap@apple.com3bd8fb62014-02-08 01:09:56 +00002561 Vector<uint8_t> buffer;
2562 CloneSerializer::serializeUndefined(buffer);
2563 return adoptRef(new SerializedScriptValue(buffer));
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00002564}
2565#endif
2566
ap@apple.com1005edd2014-02-09 01:21:32 +00002567PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002568{
2569 ExecState* exec = toJS(originContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00002570 APIEntryShim entryShim(exec);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002571 JSValue value = toJS(exec, apiValue);
ap@apple.com1005edd2014-02-09 01:21:32 +00002572 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, nullptr, nullptr);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002573 if (exec->hadException()) {
2574 if (exception)
2575 *exception = toRef(exec, exec->exception());
2576 exec->clearException();
2577 return 0;
2578 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002579 ASSERT(serializedValue);
levin@chromium.org550ac082011-08-22 23:30:10 +00002580 return serializedValue.release();
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002581}
2582
oliver@apple.com8128fe12010-09-06 21:29:06 +00002583String SerializedScriptValue::toString()
commit-queue@webkit.org72354062010-09-02 01:00:51 +00002584{
oliver@apple.com8128fe12010-09-06 21:29:06 +00002585 return CloneDeserializer::deserializeString(m_data);
2586}
2587
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002588JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00002589 MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00002590{
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002591 DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
2592 m_arrayBufferContentsArray.get(), m_data);
slewis@apple.comd0a103d2011-04-13 00:13:11 +00002593 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00002594 maybeThrowExceptionIfSerializationFailed(exec, result.second);
2595 return result.first;
commit-queue@webkit.org72354062010-09-02 01:00:51 +00002596}
2597
ap@apple.com1005edd2014-02-09 01:21:32 +00002598JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002599{
2600 ExecState* exec = toJS(destinationContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00002601 APIEntryShim entryShim(exec);
ap@apple.com1005edd2014-02-09 01:21:32 +00002602 JSValue value = deserialize(exec, exec->lexicalGlobalObject(), nullptr);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002603 if (exec->hadException()) {
2604 if (exception)
2605 *exception = toRef(exec, exec->exception());
2606 exec->clearException();
2607 return 0;
2608 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002609 ASSERT(value);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002610 return toRef(exec, value);
2611}
2612
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00002613PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
oliver@apple.com8128fe12010-09-06 21:29:06 +00002614{
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +00002615 Vector<uint8_t> buffer;
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +00002616 return adoptRef(new SerializedScriptValue(buffer));
2617}
2618
slewis@apple.comfc28de52011-04-12 21:50:04 +00002619void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
2620{
2621 if (code == SuccessfullyCompleted)
2622 return;
2623
2624 switch (code) {
2625 case StackOverflowError:
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00002626 exec->vm().throwException(exec, createStackOverflowError(exec));
slewis@apple.comfc28de52011-04-12 21:50:04 +00002627 break;
slewis@apple.comfc28de52011-04-12 21:50:04 +00002628 case ValidationError:
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00002629 exec->vm().throwException(exec, createTypeError(exec, "Unable to deserialize data."));
slewis@apple.comfc28de52011-04-12 21:50:04 +00002630 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +00002631 case DataCloneError:
2632 setDOMException(exec, DATA_CLONE_ERR);
2633 break;
slewis@apple.comfc28de52011-04-12 21:50:04 +00002634 case ExistingExceptionError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00002635 break;
2636 case UnspecifiedError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00002637 break;
2638 default:
2639 ASSERT_NOT_REACHED();
2640 }
2641}
2642
2643bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
2644{
2645 return (code == SuccessfullyCompleted);
2646}
2647
jsbell@chromium.org43d46eb2012-12-07 17:52:36 +00002648uint32_t SerializedScriptValue::wireFormatVersion()
2649{
2650 return CurrentVersion;
2651}
2652
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002653}