blob: 24196150e69795e19235425c57e8bebb8b0de568 [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"
akling@apple.comb15671a2013-02-24 13:01:06 +000031#include "ExceptionCode.h"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000032#include "File.h"
oliver@apple.comcebc1862010-01-24 07:44:05 +000033#include "FileList.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000034#include "ImageData.h"
jianli@chromium.org51ceb752010-08-11 00:03:19 +000035#include "JSBlob.h"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000036#include "JSDOMGlobalObject.h"
37#include "JSFile.h"
38#include "JSFileList.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000039#include "JSImageData.h"
dslomov@google.comd60d08e2011-10-31 21:07:22 +000040#include "JSMessagePort.h"
slewis@apple.comfc28de52011-04-12 21:50:04 +000041#include "JSNavigator.h"
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +000042#include "NotImplemented.h"
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +000043#include "ScriptValue.h"
oliver@apple.com8128fe12010-09-06 21:29:06 +000044#include "SharedBuffer.h"
fpizlo@apple.coma9188442013-08-01 22:14:28 +000045#include "WebCoreJSClientData.h"
oliver@apple.com8128fe12010-09-06 21:29:06 +000046#include <limits>
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +000047#include <JavaScriptCore/APICast.h>
timothy@apple.comf5a07a92011-03-03 18:28:29 +000048#include <JavaScriptCore/APIShims.h>
oliver@apple.comdf606082013-08-05 22:11:50 +000049#include <runtime/ArrayBuffer.h>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +000050#include <runtime/BooleanObject.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000051#include <runtime/DateInstance.h>
barraclough@apple.com9c099f92010-06-06 23:34:36 +000052#include <runtime/Error.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000053#include <runtime/ExceptionHelpers.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000054#include <runtime/JSArrayBuffer.h>
55#include <runtime/JSArrayBufferView.h>
56#include <runtime/JSDataView.h>
oliver@apple.com901740c2013-09-03 23:21:10 +000057#include <runtime/JSMap.h>
58#include <runtime/JSSet.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000059#include <runtime/JSTypedArrays.h>
oliver@apple.com901740c2013-09-03 23:21:10 +000060#include <runtime/MapData.h>
ggaren@apple.comc862eac2013-01-29 05:48:01 +000061#include <runtime/ObjectConstructor.h>
fpizlo@apple.coma4b4cbe2013-01-12 04:47:03 +000062#include <runtime/Operations.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000063#include <runtime/PropertyNameArray.h>
commit-queue@webkit.org7648c242010-09-08 00:33:15 +000064#include <runtime/RegExp.h>
65#include <runtime/RegExpObject.h>
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +000066#include <runtime/TypedArrayInlines.h>
67#include <runtime/TypedArrays.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000068#include <wtf/HashTraits.h>
69#include <wtf/Vector.h>
70
71using namespace JSC;
oliver@apple.com8128fe12010-09-06 21:29:06 +000072using namespace std;
73
oliver@apple.comf87795d2011-03-02 01:23:00 +000074#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
oliver@apple.com8128fe12010-09-06 21:29:06 +000075#define ASSUME_LITTLE_ENDIAN 0
76#else
77#define ASSUME_LITTLE_ENDIAN 1
78#endif
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000079
oliver@apple.comd83a9a22009-10-07 02:21:49 +000080namespace WebCore {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000081
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000082static const unsigned maximumFilterRecursion = 40000;
oliver@apple.com8128fe12010-09-06 21:29:06 +000083
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000084enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
oliver@apple.com901740c2013-09-03 23:21:10 +000085 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember,
86 MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue };
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000087
oliver@apple.com8128fe12010-09-06 21:29:06 +000088// These can't be reordered, and any new types must be added to the end of the list
89enum SerializationTag {
90 ArrayTag = 1,
91 ObjectTag = 2,
92 UndefinedTag = 3,
93 NullTag = 4,
94 IntTag = 5,
95 ZeroTag = 6,
96 OneTag = 7,
97 FalseTag = 8,
98 TrueTag = 9,
99 DoubleTag = 10,
100 DateTag = 11,
101 FileTag = 12,
102 FileListTag = 13,
103 ImageDataTag = 14,
104 BlobTag = 15,
105 StringTag = 16,
106 EmptyStringTag = 17,
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000107 RegExpTag = 18,
oliver@apple.come8641552010-12-20 22:40:37 +0000108 ObjectReferenceTag = 19,
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000109 MessagePortReferenceTag = 20,
dslomov@google.coma3962422012-02-23 02:51:20 +0000110 ArrayBufferTag = 21,
111 ArrayBufferViewTag = 22,
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000112 ArrayBufferTransferTag = 23,
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000113 TrueObjectTag = 24,
114 FalseObjectTag = 25,
115 StringObjectTag = 26,
116 EmptyStringObjectTag = 27,
117 NumberObjectTag = 28,
oliver@apple.com901740c2013-09-03 23:21:10 +0000118 SetObjectTag = 29,
119 MapObjectTag = 30,
120 NonMapPropertiesTag = 31,
oliver@apple.com8128fe12010-09-06 21:29:06 +0000121 ErrorTag = 255
122};
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000123
dslomov@google.coma3962422012-02-23 02:51:20 +0000124enum ArrayBufferViewSubtag {
125 DataViewTag = 0,
126 Int8ArrayTag = 1,
127 Uint8ArrayTag = 2,
128 Uint8ClampedArrayTag = 3,
129 Int16ArrayTag = 4,
130 Uint16ArrayTag = 5,
131 Int32ArrayTag = 6,
132 Uint32ArrayTag = 7,
133 Float32ArrayTag = 8,
134 Float64ArrayTag = 9
135};
136
137static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
138{
139 switch (tag) {
140 case DataViewTag:
141 case Int8ArrayTag:
142 case Uint8ArrayTag:
143 case Uint8ClampedArrayTag:
144 return 1;
145 case Int16ArrayTag:
146 case Uint16ArrayTag:
147 return 2;
148 case Int32ArrayTag:
149 case Uint32ArrayTag:
150 case Float32ArrayTag:
151 return 4;
152 case Float64ArrayTag:
153 return 8;
154 default:
155 return 0;
156 }
157
158}
159
oliver@apple.come8641552010-12-20 22:40:37 +0000160/* CurrentVersion tracks the serialization version so that persistant stores
161 * are able to correctly bail out in the case of encountering newer formats.
162 *
163 * Initial version was 1.
164 * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000165 * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
166 * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000167 * Version 4. added support for serializing non-index properties of arrays.
oliver@apple.com901740c2013-09-03 23:21:10 +0000168 * Version 5. added support for Map and Set types.
oliver@apple.come8641552010-12-20 22:40:37 +0000169 */
oliver@apple.com901740c2013-09-03 23:21:10 +0000170static const unsigned CurrentVersion = 5;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000171static const unsigned TerminatorTag = 0xFFFFFFFF;
172static const unsigned StringPoolTag = 0xFFFFFFFE;
173static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000174
oliver@apple.com8128fe12010-09-06 21:29:06 +0000175/*
176 * Object serialization is performed according to the following grammar, all tags
177 * are recorded as a single uint8_t.
178 *
oliver@apple.come8641552010-12-20 22:40:37 +0000179 * IndexType (used for the object pool and StringData's constant pool) is the
180 * minimum sized unsigned integer type required to represent the maximum index
181 * in the constant pool.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000182 *
183 * SerializedValue :- <CurrentVersion:uint32_t> Value
oliver@apple.com901740c2013-09-03 23:21:10 +0000184 * Value :- Array | Object | Map | Set | Terminal
oliver@apple.com8128fe12010-09-06 21:29:06 +0000185 *
186 * Array :-
187 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
188 *
189 * Object :-
190 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
191 *
oliver@apple.com901740c2013-09-03 23:21:10 +0000192 * Map :- MapObjectTag MapData
193 *
194 * Set :- SetObjectTag MapData
195 *
196 * MapData :- (<key:Value><value:Value>) NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag
197 *
oliver@apple.com8128fe12010-09-06 21:29:06 +0000198 * Terminal :-
199 * UndefinedTag
200 * | NullTag
201 * | IntTag <value:int32_t>
202 * | ZeroTag
203 * | OneTag
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000204 * | FalseTag
205 * | TrueTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000206 * | FalseObjectTag
207 * | TrueObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000208 * | DoubleTag <value:double>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000209 * | NumberObjectTag <value:double>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000210 * | DateTag <value:double>
211 * | String
212 * | EmptyStringTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000213 * | EmptyStringObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000214 * | File
215 * | FileList
216 * | ImageData
217 * | Blob
dslomov@google.coma3962422012-02-23 02:51:20 +0000218 * | ObjectReference
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000219 * | MessagePortReferenceTag <value:uint32_t>
dslomov@google.coma3962422012-02-23 02:51:20 +0000220 * | ArrayBuffer
221 * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLenght:uint32_t> (ArrayBuffer | ObjectReference)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000222 * | ArrayBufferTransferTag <value:uint32_t>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000223 *
224 * String :-
225 * EmptyStringTag
226 * StringTag StringData
227 *
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000228 * StringObject:
229 * EmptyStringObjectTag
230 * StringObjectTag StringData
231 *
oliver@apple.com8128fe12010-09-06 21:29:06 +0000232 * StringData :-
233 * StringPoolTag <cpIndex:IndexType>
234 * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
235 *
236 * File :-
237 * FileTag FileData
238 *
239 * FileData :-
240 * <path:StringData> <url:StringData> <type:StringData>
241 *
242 * FileList :-
243 * FileListTag <length:uint32_t>(<file:FileData>){length}
244 *
245 * ImageData :-
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000246 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000247 *
248 * Blob :-
249 * BlobTag <url:StringData><type:StringData><size:long long>
250 *
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000251 * RegExp :-
252 * RegExpTag <pattern:StringData><flags:StringData>
dslomov@google.coma3962422012-02-23 02:51:20 +0000253 *
254 * ObjectReference :-
255 * ObjectReferenceTag <opIndex:IndexType>
256 *
257 * ArrayBuffer :-
258 * ArrayBufferTag <length:uint32_t> <contents:byte{length}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000259 */
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000260
slewis@apple.comfc28de52011-04-12 21:50:04 +0000261typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
262
oliver@apple.com8128fe12010-09-06 21:29:06 +0000263class CloneBase {
264protected:
265 CloneBase(ExecState* exec)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000266 : m_exec(exec)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000267 , m_failed(false)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000268 {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000269 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000270
271 bool shouldTerminate()
272 {
273 return m_exec->hadException();
274 }
275
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000276 void throwStackOverflow()
277 {
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +0000278 m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000279 }
280
weinig@apple.com21498652011-08-13 02:40:51 +0000281 NO_RETURN_DUE_TO_ASSERT
oliver@apple.com8128fe12010-09-06 21:29:06 +0000282 void fail()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000283 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000284 ASSERT_NOT_REACHED();
285 m_failed = true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000286 }
287
oliver@apple.com8128fe12010-09-06 21:29:06 +0000288 ExecState* m_exec;
289 bool m_failed;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000290 MarkedArgumentBuffer m_gcBuffer;
291};
292
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000293#if ASSUME_LITTLE_ENDIAN
294template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
295{
296 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
297}
298#else
299template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
300{
301 for (unsigned i = 0; i < sizeof(T); i++) {
302 buffer.append(value & 0xFF);
303 value >>= 8;
304 }
305}
306#endif
307
cwzwarich@webkit.orgd0ef6552011-03-13 03:36:23 +0000308template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000309{
310 buffer.append(value);
311}
312
313template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
314{
315 if (length > numeric_limits<uint32_t>::max() / sizeof(T))
316 return false;
317
318#if ASSUME_LITTLE_ENDIAN
319 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
320#else
321 for (unsigned i = 0; i < length; i++) {
322 T value = values[i];
323 for (unsigned j = 0; j < sizeof(T); j++) {
324 buffer.append(static_cast<uint8_t>(value & 0xFF));
325 value >>= 8;
326 }
327 }
328#endif
329 return true;
330}
331
oliver@apple.com8128fe12010-09-06 21:29:06 +0000332class CloneSerializer : CloneBase {
333public:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000334 static SerializationReturnCode serialize(ExecState* exec, JSValue value,
335 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000336 Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000337 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000338 CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000339 return serializer.serialize(value);
340 }
341
tony@chromium.org6b09aa62011-06-24 06:43:34 +0000342 static bool serialize(const String& s, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000343 {
344 writeLittleEndian(out, CurrentVersion);
345 if (s.isEmpty()) {
346 writeLittleEndian<uint8_t>(out, EmptyStringTag);
347 return true;
348 }
349 writeLittleEndian<uint8_t>(out, StringTag);
350 writeLittleEndian(out, s.length());
351 return writeLittleEndian(out, s.impl()->characters(), s.length());
352 }
353
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000354 static void serializeUndefined(Vector<uint8_t>& out)
355 {
356 writeLittleEndian(out, CurrentVersion);
357 writeLittleEndian<uint8_t>(out, UndefinedTag);
358 }
359
360 static void serializeBoolean(bool value, Vector<uint8_t>& out)
361 {
362 writeLittleEndian(out, CurrentVersion);
363 writeLittleEndian<uint8_t>(out, value ? TrueTag : FalseTag);
364 }
365
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +0000366 static void serializeNumber(double value, Vector<uint8_t>& out)
367 {
368 writeLittleEndian(out, CurrentVersion);
369 writeLittleEndian<uint8_t>(out, DoubleTag);
370 union {
371 double d;
372 int64_t i;
373 } u;
374 u.d = value;
375 writeLittleEndian(out, u.i);
376 }
377
oliver@apple.com8128fe12010-09-06 21:29:06 +0000378private:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000379 typedef HashMap<JSObject*, uint32_t> ObjectPool;
380
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000381 CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000382 : CloneBase(exec)
383 , m_buffer(out)
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000384 , m_blobURLs(blobURLs)
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000385 , m_emptyIdentifier(exec, emptyString())
oliver@apple.com8128fe12010-09-06 21:29:06 +0000386 {
387 write(CurrentVersion);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000388 fillTransferMap(messagePorts, m_transferredMessagePorts);
389 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
390 }
391
392 template <class T>
393 void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result)
394 {
395 if (!input)
396 return;
oliver@apple.comffe14422012-04-05 22:33:19 +0000397 JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000398 for (size_t i = 0; i < input->size(); i++) {
399 JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get());
400 JSC::JSObject* obj = value.getObject();
401 if (obj && !result.contains(obj))
402 result.add(obj, i);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000403 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000404 }
405
slewis@apple.comfc28de52011-04-12 21:50:04 +0000406 SerializationReturnCode serialize(JSValue in);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000407
408 bool isArray(JSValue value)
409 {
410 if (!value.isObject())
411 return false;
412 JSObject* object = asObject(value);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000413 return isJSArray(object) || object->inherits(JSArray::info());
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000414 }
415
oliver@apple.com901740c2013-09-03 23:21:10 +0000416 bool isMap(JSValue value)
417 {
418 if (!value.isObject())
419 return false;
420 JSObject* object = asObject(value);
421 return object->inherits(JSMap::info());
422 }
423 bool isSet(JSValue value)
424 {
425 if (!value.isObject())
426 return false;
427 JSObject* object = asObject(value);
428 return object->inherits(JSSet::info());
429 }
430
dslomov@google.com6c31be52012-04-04 20:43:31 +0000431 bool checkForDuplicate(JSObject* object)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000432 {
oliver@apple.come8641552010-12-20 22:40:37 +0000433 // Record object for graph reconstruction
dslomov@google.comfd060da2012-04-12 19:16:49 +0000434 ObjectPool::const_iterator found = m_objectPool.find(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000435
oliver@apple.come8641552010-12-20 22:40:37 +0000436 // Handle duplicate references
dslomov@google.comfd060da2012-04-12 19:16:49 +0000437 if (found != m_objectPool.end()) {
oliver@apple.come8641552010-12-20 22:40:37 +0000438 write(ObjectReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000439 ASSERT(static_cast<int32_t>(found->value) < m_objectPool.size());
440 writeObjectIndex(found->value);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000441 return true;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000442 }
dslomov@google.com6c31be52012-04-04 20:43:31 +0000443
444 return false;
445 }
446
447 void recordObject(JSObject* object)
448 {
449 m_objectPool.add(object, m_objectPool.size());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000450 m_gcBuffer.append(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000451 }
452
453 bool startObjectInternal(JSObject* object)
454 {
455 if (checkForDuplicate(object))
456 return false;
457 recordObject(object);
oliver@apple.come8641552010-12-20 22:40:37 +0000458 return true;
459 }
460
461 bool startObject(JSObject* object)
462 {
463 if (!startObjectInternal(object))
464 return false;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000465 write(ObjectTag);
466 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000467 }
468
oliver@apple.com8128fe12010-09-06 21:29:06 +0000469 bool startArray(JSArray* array)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000470 {
oliver@apple.come8641552010-12-20 22:40:37 +0000471 if (!startObjectInternal(array))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000472 return false;
oliver@apple.come8641552010-12-20 22:40:37 +0000473
oliver@apple.com8128fe12010-09-06 21:29:06 +0000474 unsigned length = array->length();
475 write(ArrayTag);
476 write(length);
477 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000478 }
479
oliver@apple.com901740c2013-09-03 23:21:10 +0000480 bool startSet(JSSet* set)
481 {
482 if (!startObjectInternal(set))
483 return false;
484
485 write(SetObjectTag);
486 return true;
487 }
488
489 bool startMap(JSMap* map)
490 {
491 if (!startObjectInternal(map))
492 return false;
493
494 write(MapObjectTag);
495 return true;
496 }
497
oliver@apple.come8641552010-12-20 22:40:37 +0000498 void endObject()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000499 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000500 write(TerminatorTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000501 }
502
oliver@apple.com8128fe12010-09-06 21:29:06 +0000503 JSValue getProperty(JSObject* object, const Identifier& propertyName)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000504 {
505 PropertySlot slot(object);
mhahnenberg@apple.com5c103b02011-10-26 17:55:34 +0000506 if (object->methodTable()->getOwnPropertySlot(object, m_exec, propertyName, slot))
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000507 return slot.getValue(m_exec, propertyName);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000508 return JSValue();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000509 }
510
oliver@apple.com8128fe12010-09-06 21:29:06 +0000511 void dumpImmediate(JSValue value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000512 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000513 if (value.isNull())
514 write(NullTag);
515 else if (value.isUndefined())
516 write(UndefinedTag);
517 else if (value.isNumber()) {
518 if (value.isInt32()) {
519 if (!value.asInt32())
520 write(ZeroTag);
521 else if (value.asInt32() == 1)
522 write(OneTag);
523 else {
524 write(IntTag);
525 write(static_cast<uint32_t>(value.asInt32()));
526 }
527 } else {
528 write(DoubleTag);
529 write(value.asDouble());
530 }
531 } else if (value.isBoolean()) {
532 if (value.isTrue())
533 write(TrueTag);
534 else
535 write(FalseTag);
536 }
537 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000538
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000539 void dumpString(String str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000540 {
541 if (str.isEmpty())
542 write(EmptyStringTag);
543 else {
544 write(StringTag);
545 write(str);
546 }
547 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000548
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000549 void dumpStringObject(String str)
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000550 {
551 if (str.isEmpty())
552 write(EmptyStringObjectTag);
553 else {
554 write(StringObjectTag);
555 write(str);
556 }
557 }
558
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000559 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
dslomov@google.coma3962422012-02-23 02:51:20 +0000560 {
561 write(ArrayBufferViewTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000562 if (obj->inherits(JSDataView::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000563 write(DataViewTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000564 else if (obj->inherits(JSUint8ClampedArray::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000565 write(Uint8ClampedArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000566 else if (obj->inherits(JSInt8Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000567 write(Int8ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000568 else if (obj->inherits(JSUint8Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000569 write(Uint8ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000570 else if (obj->inherits(JSInt16Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000571 write(Int16ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000572 else if (obj->inherits(JSUint16Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000573 write(Uint16ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000574 else if (obj->inherits(JSInt32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000575 write(Int32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000576 else if (obj->inherits(JSUint32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000577 write(Uint32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000578 else if (obj->inherits(JSFloat32Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000579 write(Float32ArrayTag);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000580 else if (obj->inherits(JSFloat64Array::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +0000581 write(Float64ArrayTag);
582 else
583 return false;
584
585 RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj);
586 write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
587 write(static_cast<uint32_t>(arrayBufferView->byteLength()));
588 RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000589 if (!arrayBuffer) {
590 code = ValidationError;
591 return true;
592 }
oliver@apple.comffe14422012-04-05 22:33:19 +0000593 JSValue bufferObj = toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000594 return dumpIfTerminal(bufferObj, code);
dslomov@google.coma3962422012-02-23 02:51:20 +0000595 }
596
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000597 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000598 {
599 if (!value.isCell()) {
600 dumpImmediate(value);
601 return true;
602 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000603
oliver@apple.com8128fe12010-09-06 21:29:06 +0000604 if (value.isString()) {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000605 String str = asString(value)->value(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000606 dumpString(str);
607 return true;
608 }
609
610 if (value.isNumber()) {
611 write(DoubleTag);
ggaren@apple.com7831f0c2011-10-05 02:38:49 +0000612 write(value.asNumber());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000613 return true;
614 }
615
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000616 if (value.isObject() && asObject(value)->inherits(DateInstance::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000617 write(DateTag);
618 write(asDateInstance(value)->internalNumber());
619 return true;
620 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000621
622 if (isArray(value))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000623 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000624
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000625 if (value.isObject()) {
626 JSObject* obj = asObject(value);
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000627 if (obj->inherits(BooleanObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000628 if (!startObjectInternal(obj)) // handle duplicates
629 return true;
mhahnenberg@apple.com3b9069c2012-08-23 23:00:31 +0000630 write(asBooleanObject(value)->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000631 return true;
632 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000633 if (obj->inherits(StringObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000634 if (!startObjectInternal(obj)) // handle duplicates
635 return true;
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000636 String str = asString(asStringObject(value)->internalValue())->value(m_exec);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000637 dumpStringObject(str);
638 return true;
639 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000640 if (obj->inherits(NumberObject::info())) {
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000641 if (!startObjectInternal(obj)) // handle duplicates
642 return true;
643 write(NumberObjectTag);
644 NumberObject* obj = static_cast<NumberObject*>(asObject(value));
645 write(obj->internalValue().asNumber());
646 return true;
647 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000648 if (obj->inherits(JSFile::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000649 write(FileTag);
650 write(toFile(obj));
651 return true;
652 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000653 if (obj->inherits(JSFileList::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000654 FileList* list = toFileList(obj);
655 write(FileListTag);
656 unsigned length = list->length();
657 write(length);
658 for (unsigned i = 0; i < length; i++)
659 write(list->item(i));
660 return true;
661 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000662 if (obj->inherits(JSBlob::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000663 write(BlobTag);
664 Blob* blob = toBlob(obj);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000665 m_blobURLs.append(blob->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000666 write(blob->url());
667 write(blob->type());
668 write(blob->size());
669 return true;
670 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000671 if (obj->inherits(JSImageData::info())) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000672 ImageData* data = toImageData(obj);
673 write(ImageDataTag);
674 write(data->width());
675 write(data->height());
676 write(data->data()->length());
kbr@google.com1262e442012-04-24 03:43:31 +0000677 write(data->data()->data(), data->data()->length());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000678 return true;
679 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000680 if (obj->inherits(RegExpObject::info())) {
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000681 RegExpObject* regExp = asRegExpObject(obj);
682 char flags[3];
683 int flagCount = 0;
684 if (regExp->regExp()->global())
685 flags[flagCount++] = 'g';
686 if (regExp->regExp()->ignoreCase())
687 flags[flagCount++] = 'i';
688 if (regExp->regExp()->multiline())
689 flags[flagCount++] = 'm';
690 write(RegExpTag);
691 write(regExp->regExp()->pattern());
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000692 write(String(flags, flagCount));
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000693 return true;
694 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000695 if (obj->inherits(JSMessagePort::info())) {
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000696 ObjectPool::iterator index = m_transferredMessagePorts.find(obj);
697 if (index != m_transferredMessagePorts.end()) {
698 write(MessagePortReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000699 write(index->value);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000700 return true;
701 }
commit-queue@webkit.orgd9ae4552012-05-31 02:58:48 +0000702 // MessagePort object could not be found in transferred message ports
703 code = ValidationError;
704 return true;
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000705 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000706 if (obj->inherits(JSArrayBuffer::info())) {
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000707 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(obj);
708 if (arrayBuffer->isNeutered()) {
709 code = ValidationError;
710 return true;
711 }
712 ObjectPool::iterator index = m_transferredArrayBuffers.find(obj);
713 if (index != m_transferredArrayBuffers.end()) {
714 write(ArrayBufferTransferTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000715 write(index->value);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000716 return true;
717 }
dslomov@google.coma3962422012-02-23 02:51:20 +0000718 if (!startObjectInternal(obj)) // handle duplicates
719 return true;
720 write(ArrayBufferTag);
dslomov@google.coma3962422012-02-23 02:51:20 +0000721 write(arrayBuffer->byteLength());
722 write(static_cast<const uint8_t *>(arrayBuffer->data()), arrayBuffer->byteLength());
723 return true;
724 }
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000725 if (obj->inherits(JSArrayBufferView::info())) {
dslomov@google.com6c31be52012-04-04 20:43:31 +0000726 if (checkForDuplicate(obj))
dslomov@google.coma3962422012-02-23 02:51:20 +0000727 return true;
dslomov@google.com6c31be52012-04-04 20:43:31 +0000728 bool success = dumpArrayBufferView(obj, code);
729 recordObject(obj);
730 return success;
dslomov@google.coma3962422012-02-23 02:51:20 +0000731 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000732
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000733 return false;
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000734 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000735 // Any other types are expected to serialize as null.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000736 write(NullTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000737 return true;
738 }
739
oliver@apple.com8128fe12010-09-06 21:29:06 +0000740 void write(SerializationTag tag)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000741 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000742 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000743 }
744
dslomov@google.coma3962422012-02-23 02:51:20 +0000745 void write(ArrayBufferViewSubtag tag)
746 {
747 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
748 }
749
oliver@apple.com8128fe12010-09-06 21:29:06 +0000750 void write(uint8_t c)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000751 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000752 writeLittleEndian(m_buffer, c);
753 }
754
oliver@apple.com8128fe12010-09-06 21:29:06 +0000755 void write(uint32_t i)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000756 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000757 writeLittleEndian(m_buffer, i);
758 }
759
760 void write(double d)
761 {
762 union {
763 double d;
764 int64_t i;
765 } u;
766 u.d = d;
767 writeLittleEndian(m_buffer, u.i);
768 }
769
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000770 void write(int32_t i)
771 {
772 writeLittleEndian(m_buffer, i);
773 }
774
oliver@apple.com8128fe12010-09-06 21:29:06 +0000775 void write(unsigned long long i)
776 {
777 writeLittleEndian(m_buffer, i);
778 }
oliver@apple.coma9b47542010-09-06 22:53:32 +0000779
780 void write(uint16_t ch)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000781 {
oliver@apple.coma9b47542010-09-06 22:53:32 +0000782 writeLittleEndian(m_buffer, ch);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000783 }
784
785 void writeStringIndex(unsigned i)
786 {
oliver@apple.come8641552010-12-20 22:40:37 +0000787 writeConstantPoolIndex(m_constantPool, i);
788 }
789
790 void writeObjectIndex(unsigned i)
791 {
792 writeConstantPoolIndex(m_objectPool, i);
793 }
794
795 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
796 {
797 ASSERT(static_cast<int32_t>(i) < constantPool.size());
798 if (constantPool.size() <= 0xFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000799 write(static_cast<uint8_t>(i));
oliver@apple.come8641552010-12-20 22:40:37 +0000800 else if (constantPool.size() <= 0xFFFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000801 write(static_cast<uint16_t>(i));
802 else
803 write(static_cast<uint32_t>(i));
804 }
805
806 void write(const Identifier& ident)
807 {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +0000808 const String& str = ident.string();
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000809 StringConstantPool::AddResult addResult = m_constantPool.add(str.impl(), m_constantPool.size());
810 if (!addResult.isNewEntry) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000811 write(StringPoolTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000812 writeStringIndex(addResult.iterator->value);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000813 return;
814 }
815
816 // This condition is unlikely to happen as they would imply an ~8gb
817 // string but we should guard against it anyway
818 if (str.length() >= StringPoolTag) {
819 fail();
820 return;
821 }
822
823 // Guard against overflow
824 if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
825 fail();
826 return;
827 }
828
829 writeLittleEndian<uint32_t>(m_buffer, str.length());
oliver@apple.com906a13c2010-09-06 23:31:09 +0000830 if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000831 fail();
832 }
833
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000834 void write(const String& str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000835 {
836 if (str.isNull())
837 write(m_emptyIdentifier);
838 else
839 write(Identifier(m_exec, str));
840 }
841
oliver@apple.com8128fe12010-09-06 21:29:06 +0000842 void write(const File* file)
843 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000844 m_blobURLs.append(file->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000845 write(file->path());
846 write(file->url());
847 write(file->type());
848 }
849
850 void write(const uint8_t* data, unsigned length)
851 {
852 m_buffer.append(data, length);
853 }
854
855 Vector<uint8_t>& m_buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000856 Vector<String>& m_blobURLs;
oliver@apple.come8641552010-12-20 22:40:37 +0000857 ObjectPool m_objectPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000858 ObjectPool m_transferredMessagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000859 ObjectPool m_transferredArrayBuffers;
oliver@apple.come8641552010-12-20 22:40:37 +0000860 typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
861 StringConstantPool m_constantPool;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000862 Identifier m_emptyIdentifier;
863};
864
slewis@apple.comfc28de52011-04-12 21:50:04 +0000865SerializationReturnCode CloneSerializer::serialize(JSValue in)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000866{
867 Vector<uint32_t, 16> indexStack;
868 Vector<uint32_t, 16> lengthStack;
869 Vector<PropertyNameArray, 16> propertyStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000870 Vector<JSObject*, 32> inputObjectStack;
oliver@apple.com901740c2013-09-03 23:21:10 +0000871 Vector<MapData*, 4> mapDataStack;
872 Vector<MapData::const_iterator, 4> iteratorStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000873 Vector<WalkerState, 16> stateStack;
874 WalkerState state = StateUnknown;
875 JSValue inValue = in;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000876 while (1) {
877 switch (state) {
878 arrayStartState:
879 case ArrayStartState: {
880 ASSERT(isArray(inValue));
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000881 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +0000882 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000883
884 JSArray* inArray = asArray(inValue);
885 unsigned length = inArray->length();
886 if (!startArray(inArray))
oliver@apple.come8641552010-12-20 22:40:37 +0000887 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000888 inputObjectStack.append(inArray);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000889 indexStack.append(0);
890 lengthStack.append(length);
891 // fallthrough
892 }
893 arrayStartVisitMember:
894 case ArrayStartVisitMember: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000895 JSObject* array = inputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000896 uint32_t index = indexStack.last();
897 if (index == lengthStack.last()) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000898 indexStack.removeLast();
899 lengthStack.removeLast();
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000900
901 propertyStack.append(PropertyNameArray(m_exec));
902 array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
903 if (propertyStack.last().size()) {
904 write(NonIndexPropertiesTag);
905 indexStack.append(0);
906 goto objectStartVisitMember;
907 }
908 propertyStack.removeLast();
909
910 endObject();
911 inputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000912 break;
913 }
fpizlo@apple.com7ebfaed2012-09-25 23:42:52 +0000914 inValue = array->getDirectIndex(m_exec, index);
915 if (!inValue) {
916 indexStack.last()++;
917 goto arrayStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000918 }
919
920 write(index);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000921 SerializationReturnCode terminalCode = SuccessfullyCompleted;
922 if (dumpIfTerminal(inValue, terminalCode)) {
923 if (terminalCode != SuccessfullyCompleted)
924 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000925 indexStack.last()++;
926 goto arrayStartVisitMember;
927 }
928 stateStack.append(ArrayEndVisitMember);
929 goto stateUnknown;
930 }
931 case ArrayEndVisitMember: {
932 indexStack.last()++;
933 goto arrayStartVisitMember;
934 }
935 objectStartState:
936 case ObjectStartState: {
937 ASSERT(inValue.isObject());
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000938 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +0000939 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000940 JSObject* inObject = asObject(inValue);
941 if (!startObject(inObject))
oliver@apple.come8641552010-12-20 22:40:37 +0000942 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000943 // At this point, all supported objects other than Object
944 // objects have been handled. If we reach this point and
945 // the input is not an Object object then we should throw
946 // a DataCloneError.
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +0000947 if (inObject->classInfo() != JSFinalObject::info())
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000948 return DataCloneError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000949 inputObjectStack.append(inObject);
950 indexStack.append(0);
951 propertyStack.append(PropertyNameArray(m_exec));
mhahnenberg@apple.com57262382011-11-03 00:25:45 +0000952 inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000953 // fallthrough
954 }
955 objectStartVisitMember:
956 case ObjectStartVisitMember: {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000957 JSObject* object = inputObjectStack.last();
958 uint32_t index = indexStack.last();
959 PropertyNameArray& properties = propertyStack.last();
960 if (index == properties.size()) {
oliver@apple.come8641552010-12-20 22:40:37 +0000961 endObject();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000962 inputObjectStack.removeLast();
963 indexStack.removeLast();
964 propertyStack.removeLast();
965 break;
966 }
967 inValue = getProperty(object, properties[index]);
968 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000969 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000970
971 if (!inValue) {
972 // Property was removed during serialisation
973 indexStack.last()++;
974 goto objectStartVisitMember;
975 }
976 write(properties[index]);
977
978 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000979 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000980
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000981 SerializationReturnCode terminalCode = SuccessfullyCompleted;
982 if (!dumpIfTerminal(inValue, terminalCode)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000983 stateStack.append(ObjectEndVisitMember);
984 goto stateUnknown;
985 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000986 if (terminalCode != SuccessfullyCompleted)
987 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000988 // fallthrough
989 }
990 case ObjectEndVisitMember: {
991 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000992 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000993
994 indexStack.last()++;
995 goto objectStartVisitMember;
996 }
oliver@apple.com901740c2013-09-03 23:21:10 +0000997 mapStartState: {
998 ASSERT(inValue.isObject());
999 if (inputObjectStack.size() > maximumFilterRecursion)
1000 return StackOverflowError;
1001 JSMap* inMap = jsCast<JSMap*>(inValue);
1002 if (!startMap(inMap))
1003 break;
1004 MapData* mapData = inMap->mapData();
1005 m_gcBuffer.append(mapData);
1006 mapDataStack.append(mapData);
1007 iteratorStack.append(mapData->begin());
1008 inputObjectStack.append(inMap);
1009 goto mapDataStartVisitEntry;
1010 }
1011 setStartState: {
1012 ASSERT(inValue.isObject());
1013 if (inputObjectStack.size() > maximumFilterRecursion)
1014 return StackOverflowError;
1015 JSSet* inSet = jsCast<JSSet*>(inValue);
1016 if (!startSet(inSet))
1017 break;
1018 MapData* mapData = inSet->mapData();
1019 m_gcBuffer.append(mapData);
1020 mapDataStack.append(mapData);
1021 iteratorStack.append(mapData->begin());
1022 inputObjectStack.append(inSet);
1023 goto mapDataStartVisitEntry;
1024 }
1025 mapDataStartVisitEntry:
1026 case MapDataStartVisitEntry: {
1027 MapData::const_iterator& ptr = iteratorStack.last();
1028 MapData* mapData = mapDataStack.last();
1029 if (ptr == mapData->end()) {
1030 iteratorStack.removeLast();
1031 mapDataStack.removeLast();
1032 JSObject* object = inputObjectStack.last();
1033 ASSERT(jsDynamicCast<JSSet*>(object) || jsDynamicCast<JSMap*>(object));
1034 propertyStack.append(PropertyNameArray(m_exec));
1035 object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
1036 write(NonMapPropertiesTag);
1037 indexStack.append(0);
1038 goto objectStartVisitMember;
1039 }
1040 inValue = ptr.key();
1041 stateStack.append(MapDataEndVisitKey);
1042 goto stateUnknown;
1043 }
1044 case MapDataEndVisitKey: {
1045 inValue = iteratorStack.last().value();
1046 stateStack.append(MapDataEndVisitValue);
1047 goto stateUnknown;
1048 }
1049 case MapDataEndVisitValue: {
1050 ++iteratorStack.last();
1051 goto mapDataStartVisitEntry;
1052 }
1053
oliver@apple.com8128fe12010-09-06 21:29:06 +00001054 stateUnknown:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001055 case StateUnknown: {
1056 SerializationReturnCode terminalCode = SuccessfullyCompleted;
1057 if (dumpIfTerminal(inValue, terminalCode)) {
1058 if (terminalCode != SuccessfullyCompleted)
1059 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001060 break;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001061 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001062
1063 if (isArray(inValue))
1064 goto arrayStartState;
oliver@apple.com901740c2013-09-03 23:21:10 +00001065 if (isMap(inValue))
1066 goto mapStartState;
1067 if (isSet(inValue))
1068 goto setStartState;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001069 goto objectStartState;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001070 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001071 }
1072 if (stateStack.isEmpty())
1073 break;
1074
1075 state = stateStack.last();
1076 stateStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001077 }
1078 if (m_failed)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001079 return UnspecifiedError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001080
slewis@apple.comfc28de52011-04-12 21:50:04 +00001081 return SuccessfullyCompleted;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001082}
1083
oliver@apple.comdf606082013-08-05 22:11:50 +00001084typedef Vector<JSC::ArrayBufferContents> ArrayBufferContentsArray;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001085
oliver@apple.com8128fe12010-09-06 21:29:06 +00001086class CloneDeserializer : CloneBase {
1087public:
1088 static String deserializeString(const Vector<uint8_t>& buffer)
1089 {
1090 const uint8_t* ptr = buffer.begin();
1091 const uint8_t* end = buffer.end();
1092 uint32_t version;
1093 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1094 return String();
1095 uint8_t tag;
1096 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1097 return String();
1098 uint32_t length;
1099 if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
1100 return String();
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001101 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001102 if (!readString(ptr, end, str, length))
1103 return String();
1104 return String(str.impl());
1105 }
1106
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001107 static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
1108 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001109 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001110 {
1111 if (!buffer.size())
slewis@apple.comfc28de52011-04-12 21:50:04 +00001112 return make_pair(jsNull(), UnspecifiedError);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001113 CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
slewis@apple.comfc28de52011-04-12 21:50:04 +00001114 if (!deserializer.isValid())
1115 return make_pair(JSValue(), ValidationError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001116 return deserializer.deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001117 }
1118
1119private:
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001120 struct CachedString {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001121 CachedString(const String& string)
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001122 : m_string(string)
1123 {
1124 }
1125
1126 JSValue jsString(ExecState* exec)
1127 {
1128 if (!m_jsString)
1129 m_jsString = JSC::jsString(exec, m_string);
1130 return m_jsString;
1131 }
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001132 const String& string() { return m_string; }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001133
1134 private:
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001135 String m_string;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001136 JSValue m_jsString;
1137 };
1138
oliver@apple.com86609602010-10-19 02:33:33 +00001139 struct CachedStringRef {
1140 CachedStringRef()
1141 : m_base(0)
1142 , m_index(0)
1143 {
1144 }
1145 CachedStringRef(Vector<CachedString>* base, size_t index)
1146 : m_base(base)
1147 , m_index(index)
1148 {
1149 }
1150
1151 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1152
1153 private:
1154 Vector<CachedString>* m_base;
1155 size_t m_index;
1156 };
1157
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001158 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject,
1159 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
1160 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001161 : CloneBase(exec)
oliver@apple.com5deb8d82010-01-28 04:47:07 +00001162 , m_globalObject(globalObject)
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +00001163 , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info()))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001164 , m_ptr(buffer.data())
1165 , m_end(buffer.data() + buffer.size())
1166 , m_version(0xFFFFFFFF)
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001167 , m_messagePorts(messagePorts)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001168 , m_arrayBufferContents(arrayBufferContents)
1169 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001170 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001171 if (!read(m_version))
1172 m_version = 0xFFFFFFFF;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001173 }
1174
slewis@apple.comfc28de52011-04-12 21:50:04 +00001175 DeserializationResult deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001176
oliver@apple.com8128fe12010-09-06 21:29:06 +00001177 void throwValidationError()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001178 {
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00001179 m_exec->vm().throwException(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001180 }
1181
oliver@apple.com8128fe12010-09-06 21:29:06 +00001182 bool isValid() const { return m_version <= CurrentVersion; }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001183
oliver@apple.com8128fe12010-09-06 21:29:06 +00001184 template <typename T> bool readLittleEndian(T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001185 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001186 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1187 fail();
1188 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001189 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001190 return true;
1191 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001192#if ASSUME_LITTLE_ENDIAN
1193 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001194 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001195 if (ptr > end - sizeof(value))
1196 return false;
1197
1198 if (sizeof(T) == 1)
1199 value = *ptr++;
1200 else {
commit-queue@webkit.orgbfe8ef62010-10-13 19:21:48 +00001201 value = *reinterpret_cast<const T*>(ptr);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001202 ptr += sizeof(T);
1203 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001204 return true;
1205 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001206#else
1207 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001208 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001209 if (ptr > end - sizeof(value))
1210 return false;
1211
1212 if (sizeof(T) == 1)
1213 value = *ptr++;
1214 else {
1215 value = 0;
1216 for (unsigned i = 0; i < sizeof(T); i++)
1217 value += ((T)*ptr++) << (i * 8);
1218 }
1219 return true;
1220 }
1221#endif
1222
1223 bool read(uint32_t& i)
1224 {
1225 return readLittleEndian(i);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001226 }
1227
oliver@apple.com8128fe12010-09-06 21:29:06 +00001228 bool read(int32_t& i)
1229 {
1230 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1231 }
1232
1233 bool read(uint16_t& i)
1234 {
1235 return readLittleEndian(i);
1236 }
1237
1238 bool read(uint8_t& i)
1239 {
1240 return readLittleEndian(i);
1241 }
1242
1243 bool read(double& d)
1244 {
1245 union {
1246 double d;
1247 uint64_t i64;
1248 } u;
1249 if (!readLittleEndian(u.i64))
1250 return false;
1251 d = u.d;
1252 return true;
1253 }
1254
1255 bool read(unsigned long long& i)
1256 {
1257 return readLittleEndian(i);
1258 }
1259
1260 bool readStringIndex(uint32_t& i)
1261 {
oliver@apple.come8641552010-12-20 22:40:37 +00001262 return readConstantPoolIndex(m_constantPool, i);
1263 }
1264
1265 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1266 {
1267 if (constantPool.size() <= 0xFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001268 uint8_t i8;
1269 if (!read(i8))
1270 return false;
1271 i = i8;
1272 return true;
1273 }
oliver@apple.come8641552010-12-20 22:40:37 +00001274 if (constantPool.size() <= 0xFFFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001275 uint16_t i16;
1276 if (!read(i16))
1277 return false;
1278 i = i16;
1279 return true;
1280 }
1281 return read(i);
1282 }
1283
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001284 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001285 {
1286 if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
1287 return false;
1288
1289 unsigned size = length * sizeof(UChar);
1290 if ((end - ptr) < static_cast<int>(size))
1291 return false;
1292
1293#if ASSUME_LITTLE_ENDIAN
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001294 str = String(reinterpret_cast<const UChar*>(ptr), length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001295 ptr += length * sizeof(UChar);
1296#else
1297 Vector<UChar> buffer;
1298 buffer.reserveCapacity(length);
1299 for (unsigned i = 0; i < length; i++) {
1300 uint16_t ch;
1301 readLittleEndian(ptr, end, ch);
1302 buffer.append(ch);
1303 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001304 str = String::adopt(buffer);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001305#endif
1306 return true;
1307 }
1308
oliver@apple.com86609602010-10-19 02:33:33 +00001309 bool readStringData(CachedStringRef& cachedString)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001310 {
1311 bool scratch;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001312 return readStringData(cachedString, scratch);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001313 }
1314
oliver@apple.com86609602010-10-19 02:33:33 +00001315 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001316 {
1317 if (m_failed)
1318 return false;
1319 uint32_t length = 0;
1320 if (!read(length))
1321 return false;
1322 if (length == TerminatorTag) {
1323 wasTerminator = true;
1324 return false;
1325 }
1326 if (length == StringPoolTag) {
1327 unsigned index = 0;
1328 if (!readStringIndex(index)) {
1329 fail();
1330 return false;
1331 }
1332 if (index >= m_constantPool.size()) {
1333 fail();
1334 return false;
1335 }
oliver@apple.com86609602010-10-19 02:33:33 +00001336 cachedString = CachedStringRef(&m_constantPool, index);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001337 return true;
1338 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001339 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001340 if (!readString(m_ptr, m_end, str, length)) {
1341 fail();
1342 return false;
1343 }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001344 m_constantPool.append(str);
oliver@apple.com86609602010-10-19 02:33:33 +00001345 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001346 return true;
1347 }
1348
1349 SerializationTag readTag()
1350 {
1351 if (m_ptr >= m_end)
1352 return ErrorTag;
1353 return static_cast<SerializationTag>(*m_ptr++);
1354 }
1355
dslomov@google.coma3962422012-02-23 02:51:20 +00001356 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
1357 {
1358 if (m_ptr >= m_end)
1359 return false;
1360 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
1361 return true;
1362 }
1363
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001364 void putProperty(JSObject* object, unsigned index, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001365 {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001366 object->putDirectIndex(m_exec, index, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001367 }
1368
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001369 void putProperty(JSObject* object, const Identifier& property, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001370 {
fpizlo@apple.com904bab82012-09-25 05:27:33 +00001371 object->putDirectMayBeIndex(m_exec, property, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001372 }
1373
1374 bool readFile(RefPtr<File>& file)
1375 {
oliver@apple.com86609602010-10-19 02:33:33 +00001376 CachedStringRef path;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001377 if (!readStringData(path))
1378 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001379 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001380 if (!readStringData(url))
1381 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001382 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001383 if (!readStringData(type))
1384 return 0;
commit-queue@webkit.orgfa990e92010-09-10 16:19:57 +00001385 if (m_isDOMGlobalObject)
darin@apple.com5ffbb5c2013-09-27 16:39:41 +00001386 file = File::create(path->string(), URL(URL(), url->string()), type->string());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001387 return true;
1388 }
1389
dslomov@google.coma3962422012-02-23 02:51:20 +00001390 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
1391 {
1392 uint32_t length;
1393 if (!read(length))
1394 return false;
1395 if (m_ptr + length > m_end)
1396 return false;
1397 arrayBuffer = ArrayBuffer::create(m_ptr, length);
1398 m_ptr += length;
1399 return true;
1400 }
1401
1402 bool readArrayBufferView(JSValue& arrayBufferView)
1403 {
1404 ArrayBufferViewSubtag arrayBufferViewSubtag;
1405 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
1406 return false;
1407 uint32_t byteOffset;
1408 if (!read(byteOffset))
1409 return false;
1410 uint32_t byteLength;
1411 if (!read(byteLength))
1412 return false;
1413 JSObject* arrayBufferObj = asObject(readTerminal());
fpizlo@apple.com10ae2d02013-08-14 02:41:47 +00001414 if (!arrayBufferObj || !arrayBufferObj->inherits(JSArrayBuffer::info()))
dslomov@google.coma3962422012-02-23 02:51:20 +00001415 return false;
1416
1417 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
1418 if (!elementSize)
1419 return false;
1420 unsigned length = byteLength / elementSize;
1421 if (length * elementSize != byteLength)
1422 return false;
1423
1424 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj);
1425 switch (arrayBufferViewSubtag) {
1426 case DataViewTag:
1427 arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get());
1428 return true;
1429 case Int8ArrayTag:
1430 arrayBufferView = getJSValue(Int8Array::create(arrayBuffer, byteOffset, length).get());
1431 return true;
1432 case Uint8ArrayTag:
1433 arrayBufferView = getJSValue(Uint8Array::create(arrayBuffer, byteOffset, length).get());
1434 return true;
1435 case Uint8ClampedArrayTag:
1436 arrayBufferView = getJSValue(Uint8ClampedArray::create(arrayBuffer, byteOffset, length).get());
1437 return true;
1438 case Int16ArrayTag:
1439 arrayBufferView = getJSValue(Int16Array::create(arrayBuffer, byteOffset, length).get());
1440 return true;
1441 case Uint16ArrayTag:
1442 arrayBufferView = getJSValue(Uint16Array::create(arrayBuffer, byteOffset, length).get());
1443 return true;
1444 case Int32ArrayTag:
1445 arrayBufferView = getJSValue(Int32Array::create(arrayBuffer, byteOffset, length).get());
1446 return true;
1447 case Uint32ArrayTag:
1448 arrayBufferView = getJSValue(Uint32Array::create(arrayBuffer, byteOffset, length).get());
1449 return true;
1450 case Float32ArrayTag:
1451 arrayBufferView = getJSValue(Float32Array::create(arrayBuffer, byteOffset, length).get());
1452 return true;
1453 case Float64ArrayTag:
1454 arrayBufferView = getJSValue(Float64Array::create(arrayBuffer, byteOffset, length).get());
1455 return true;
1456 default:
1457 return false;
1458 }
1459 }
1460
1461 template<class T>
1462 JSValue getJSValue(T* nativeObj)
1463 {
oliver@apple.comffe14422012-04-05 22:33:19 +00001464 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
dslomov@google.coma3962422012-02-23 02:51:20 +00001465 }
1466
oliver@apple.com8128fe12010-09-06 21:29:06 +00001467 JSValue readTerminal()
1468 {
1469 SerializationTag tag = readTag();
1470 switch (tag) {
1471 case UndefinedTag:
1472 return jsUndefined();
1473 case NullTag:
1474 return jsNull();
1475 case IntTag: {
1476 int32_t i;
1477 if (!read(i))
1478 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001479 return jsNumber(i);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001480 }
1481 case ZeroTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001482 return jsNumber(0);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001483 case OneTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001484 return jsNumber(1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001485 case FalseTag:
1486 return jsBoolean(false);
1487 case TrueTag:
1488 return jsBoolean(true);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001489 case FalseObjectTag: {
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00001490 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
1491 obj->setInternalValue(m_exec->vm(), jsBoolean(false));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001492 m_gcBuffer.append(obj);
1493 return obj;
1494 }
1495 case TrueObjectTag: {
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00001496 BooleanObject* obj = BooleanObject::create(m_exec->vm(), m_globalObject->booleanObjectStructure());
1497 obj->setInternalValue(m_exec->vm(), jsBoolean(true));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001498 m_gcBuffer.append(obj);
1499 return obj;
1500 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001501 case DoubleTag: {
1502 double d;
1503 if (!read(d))
1504 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001505 return jsNumber(d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001506 }
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001507 case NumberObjectTag: {
1508 double d;
1509 if (!read(d))
1510 return JSValue();
1511 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
1512 m_gcBuffer.append(obj);
1513 return obj;
1514 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001515 case DateTag: {
1516 double d;
1517 if (!read(d))
1518 return JSValue();
akling@apple.comb34659a2013-09-29 22:20:26 +00001519 return DateInstance::create(m_exec->vm(), m_globalObject->dateStructure(), d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001520 }
1521 case FileTag: {
1522 RefPtr<File> file;
1523 if (!readFile(file))
1524 return JSValue();
1525 if (!m_isDOMGlobalObject)
1526 return jsNull();
oliver@apple.comffe14422012-04-05 22:33:19 +00001527 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001528 }
1529 case FileListTag: {
1530 unsigned length = 0;
1531 if (!read(length))
1532 return JSValue();
1533 RefPtr<FileList> result = FileList::create();
1534 for (unsigned i = 0; i < length; i++) {
1535 RefPtr<File> file;
1536 if (!readFile(file))
1537 return JSValue();
1538 if (m_isDOMGlobalObject)
1539 result->append(file.get());
1540 }
1541 if (!m_isDOMGlobalObject)
1542 return jsNull();
dslomov@google.coma3962422012-02-23 02:51:20 +00001543 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001544 }
1545 case ImageDataTag: {
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001546 int32_t width;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001547 if (!read(width))
1548 return JSValue();
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001549 int32_t height;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001550 if (!read(height))
1551 return JSValue();
1552 uint32_t length;
1553 if (!read(length))
1554 return JSValue();
1555 if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1556 fail();
1557 return JSValue();
1558 }
1559 if (!m_isDOMGlobalObject) {
1560 m_ptr += length;
1561 return jsNull();
1562 }
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001563 RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
kbr@google.com1262e442012-04-24 03:43:31 +00001564 memcpy(result->data()->data(), m_ptr, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001565 m_ptr += length;
dslomov@google.coma3962422012-02-23 02:51:20 +00001566 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001567 }
1568 case BlobTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001569 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001570 if (!readStringData(url))
1571 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00001572 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001573 if (!readStringData(type))
1574 return JSValue();
1575 unsigned long long size = 0;
1576 if (!read(size))
1577 return JSValue();
1578 if (!m_isDOMGlobalObject)
1579 return jsNull();
darin@apple.com5ffbb5c2013-09-27 16:39:41 +00001580 return getJSValue(Blob::create(URL(URL(), url->string()), type->string(), size).get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001581 }
1582 case StringTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001583 CachedStringRef cachedString;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001584 if (!readStringData(cachedString))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001585 return JSValue();
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001586 return cachedString->jsString(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001587 }
1588 case EmptyStringTag:
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00001589 return jsEmptyString(&m_exec->vm());
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001590 case StringObjectTag: {
1591 CachedStringRef cachedString;
1592 if (!readStringData(cachedString))
1593 return JSValue();
1594 StringObject* obj = constructString(m_exec, m_globalObject, cachedString->jsString(m_exec));
1595 m_gcBuffer.append(obj);
1596 return obj;
1597 }
1598 case EmptyStringObjectTag: {
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00001599 StringObject* obj = constructString(m_exec, m_globalObject, jsEmptyString(&m_exec->vm()));
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001600 m_gcBuffer.append(obj);
1601 return obj;
1602 }
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001603 case RegExpTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001604 CachedStringRef pattern;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001605 if (!readStringData(pattern))
1606 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00001607 CachedStringRef flags;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001608 if (!readStringData(flags))
1609 return JSValue();
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001610 RegExpFlags reFlags = regExpFlags(flags->string());
barraclough@apple.com12812932011-03-09 23:04:27 +00001611 ASSERT(reFlags != InvalidFlags);
akling@apple.com8662c392013-09-30 18:58:51 +00001612 VM& vm = m_exec->vm();
1613 RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags);
1614 return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001615 }
oliver@apple.come8641552010-12-20 22:40:37 +00001616 case ObjectReferenceTag: {
1617 unsigned index = 0;
1618 if (!readConstantPoolIndex(m_gcBuffer, index)) {
1619 fail();
1620 return JSValue();
1621 }
1622 return m_gcBuffer.at(index);
1623 }
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001624 case MessagePortReferenceTag: {
1625 uint32_t index;
1626 bool indexSuccessfullyRead = read(index);
1627 if (!indexSuccessfullyRead || !m_messagePorts || index >= m_messagePorts->size()) {
1628 fail();
1629 return JSValue();
1630 }
dslomov@google.coma3962422012-02-23 02:51:20 +00001631 return getJSValue(m_messagePorts->at(index).get());
1632 }
1633 case ArrayBufferTag: {
1634 RefPtr<ArrayBuffer> arrayBuffer;
1635 if (!readArrayBuffer(arrayBuffer)) {
1636 fail();
1637 return JSValue();
1638 }
1639 JSValue result = getJSValue(arrayBuffer.get());
1640 m_gcBuffer.append(result);
1641 return result;
1642 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001643 case ArrayBufferTransferTag: {
1644 uint32_t index;
1645 bool indexSuccessfullyRead = read(index);
1646 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
1647 fail();
1648 return JSValue();
1649 }
1650
1651 if (!m_arrayBuffers[index])
1652 m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
1653
1654 return getJSValue(m_arrayBuffers[index].get());
1655 }
dslomov@google.coma3962422012-02-23 02:51:20 +00001656 case ArrayBufferViewTag: {
1657 JSValue arrayBufferView;
1658 if (!readArrayBufferView(arrayBufferView)) {
1659 fail();
1660 return JSValue();
1661 }
1662 m_gcBuffer.append(arrayBufferView);
1663 return arrayBufferView;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001664 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001665 default:
1666 m_ptr--; // Push the tag back
1667 return JSValue();
1668 }
1669 }
1670
oliver@apple.com901740c2013-09-03 23:21:10 +00001671 bool consumeMapDataTerminationIfPossible()
1672 {
1673 if (readTag() == NonMapPropertiesTag)
1674 return true;
1675 m_ptr--;
1676 return false;
1677 }
1678
oliver@apple.com02a5f152010-01-24 22:54:18 +00001679 JSGlobalObject* m_globalObject;
1680 bool m_isDOMGlobalObject;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001681 const uint8_t* m_ptr;
1682 const uint8_t* m_end;
1683 unsigned m_version;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001684 Vector<CachedString> m_constantPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001685 MessagePortArray* m_messagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001686 ArrayBufferContentsArray* m_arrayBufferContents;
1687 ArrayBufferArray m_arrayBuffers;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001688};
1689
slewis@apple.comfc28de52011-04-12 21:50:04 +00001690DeserializationResult CloneDeserializer::deserialize()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001691{
oliver@apple.com8128fe12010-09-06 21:29:06 +00001692 Vector<uint32_t, 16> indexStack;
1693 Vector<Identifier, 16> propertyNameStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001694 Vector<JSObject*, 32> outputObjectStack;
oliver@apple.com901740c2013-09-03 23:21:10 +00001695 Vector<JSValue, 4> keyStack;
1696 Vector<MapData*, 4> mapDataStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001697 Vector<WalkerState, 16> stateStack;
1698 WalkerState state = StateUnknown;
1699 JSValue outValue;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001700
oliver@apple.com8128fe12010-09-06 21:29:06 +00001701 while (1) {
1702 switch (state) {
1703 arrayStartState:
1704 case ArrayStartState: {
1705 uint32_t length;
1706 if (!read(length)) {
1707 fail();
1708 goto error;
1709 }
fpizlo@apple.com75c91a72012-11-08 22:28:25 +00001710 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001711 m_gcBuffer.append(outArray);
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001712 outputObjectStack.append(outArray);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001713 // fallthrough
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001714 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001715 arrayStartVisitMember:
1716 case ArrayStartVisitMember: {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001717 uint32_t index;
1718 if (!read(index)) {
1719 fail();
1720 goto error;
1721 }
1722 if (index == TerminatorTag) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001723 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001724 outValue = outArray;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001725 outputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001726 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001727 } else if (index == NonIndexPropertiesTag) {
1728 goto objectStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001729 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001730
oliver@apple.com8128fe12010-09-06 21:29:06 +00001731 if (JSValue terminal = readTerminal()) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001732 putProperty(outputObjectStack.last(), index, terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001733 goto arrayStartVisitMember;
1734 }
1735 if (m_failed)
1736 goto error;
1737 indexStack.append(index);
1738 stateStack.append(ArrayEndVisitMember);
1739 goto stateUnknown;
1740 }
1741 case ArrayEndVisitMember: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001742 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001743 putProperty(outArray, indexStack.last(), outValue);
1744 indexStack.removeLast();
1745 goto arrayStartVisitMember;
1746 }
1747 objectStartState:
1748 case ObjectStartState: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001749 if (outputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001750 return make_pair(JSValue(), StackOverflowError);
ggaren@apple.comc862eac2013-01-29 05:48:01 +00001751 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001752 m_gcBuffer.append(outObject);
1753 outputObjectStack.append(outObject);
1754 // fallthrough
1755 }
1756 objectStartVisitMember:
1757 case ObjectStartVisitMember: {
oliver@apple.com86609602010-10-19 02:33:33 +00001758 CachedStringRef cachedString;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001759 bool wasTerminator = false;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001760 if (!readStringData(cachedString, wasTerminator)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001761 if (!wasTerminator)
1762 goto error;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001763
oliver@apple.com8128fe12010-09-06 21:29:06 +00001764 JSObject* outObject = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001765 outValue = outObject;
1766 outputObjectStack.removeLast();
1767 break;
1768 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001769
oliver@apple.com8128fe12010-09-06 21:29:06 +00001770 if (JSValue terminal = readTerminal()) {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001771 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->string()), terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001772 goto objectStartVisitMember;
1773 }
1774 stateStack.append(ObjectEndVisitMember);
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001775 propertyNameStack.append(Identifier(m_exec, cachedString->string()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00001776 goto stateUnknown;
1777 }
1778 case ObjectEndVisitMember: {
1779 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1780 propertyNameStack.removeLast();
1781 goto objectStartVisitMember;
1782 }
oliver@apple.com901740c2013-09-03 23:21:10 +00001783 mapObjectStartState: {
1784 if (outputObjectStack.size() > maximumFilterRecursion)
1785 return make_pair(JSValue(), StackOverflowError);
1786 JSMap* map = JSMap::create(m_exec->vm(), m_globalObject->mapStructure());
1787 m_gcBuffer.append(map);
1788 outputObjectStack.append(map);
1789 MapData* mapData = map->mapData();
1790 mapDataStack.append(mapData);
1791 goto mapDataStartVisitEntry;
1792 }
1793 setObjectStartState: {
1794 if (outputObjectStack.size() > maximumFilterRecursion)
1795 return make_pair(JSValue(), StackOverflowError);
1796 JSSet* set = JSSet::create(m_exec->vm(), m_globalObject->setStructure());
1797 m_gcBuffer.append(set);
1798 outputObjectStack.append(set);
1799 MapData* mapData = set->mapData();
1800 mapDataStack.append(mapData);
1801 goto mapDataStartVisitEntry;
1802 }
1803 mapDataStartVisitEntry:
1804 case MapDataStartVisitEntry: {
1805 if (consumeMapDataTerminationIfPossible()) {
1806 mapDataStack.removeLast();
1807 goto objectStartVisitMember;
1808 }
1809 stateStack.append(MapDataEndVisitKey);
1810 goto stateUnknown;
1811 }
1812
1813 case MapDataEndVisitKey: {
1814 keyStack.append(outValue);
1815 stateStack.append(MapDataEndVisitValue);
1816 goto stateUnknown;
1817 }
1818
1819 case MapDataEndVisitValue: {
1820 mapDataStack.last()->set(m_exec, keyStack.last(), outValue);
1821 keyStack.removeLast();
1822 goto mapDataStartVisitEntry;
1823 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001824 stateUnknown:
1825 case StateUnknown:
1826 if (JSValue terminal = readTerminal()) {
1827 outValue = terminal;
1828 break;
1829 }
1830 SerializationTag tag = readTag();
1831 if (tag == ArrayTag)
1832 goto arrayStartState;
1833 if (tag == ObjectTag)
1834 goto objectStartState;
oliver@apple.com901740c2013-09-03 23:21:10 +00001835 if (tag == MapObjectTag)
1836 goto mapObjectStartState;
1837 if (tag == SetObjectTag)
1838 goto setObjectStartState;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001839 goto error;
1840 }
1841 if (stateStack.isEmpty())
1842 break;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001843
oliver@apple.com8128fe12010-09-06 21:29:06 +00001844 state = stateStack.last();
1845 stateStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001846 }
1847 ASSERT(outValue);
1848 ASSERT(!m_failed);
slewis@apple.comfc28de52011-04-12 21:50:04 +00001849 return make_pair(outValue, SuccessfullyCompleted);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001850error:
1851 fail();
slewis@apple.comfc28de52011-04-12 21:50:04 +00001852 return make_pair(JSValue(), ValidationError);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001853}
1854
oliver@apple.com8128fe12010-09-06 21:29:06 +00001855
1856
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001857SerializedScriptValue::~SerializedScriptValue()
1858{
1859}
1860
commit-queue@webkit.org7632ff22012-12-17 23:59:47 +00001861SerializedScriptValue::SerializedScriptValue(const Vector<uint8_t>& buffer)
1862 : m_data(buffer)
1863{
1864}
1865
oliver@apple.com8128fe12010-09-06 21:29:06 +00001866SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1867{
1868 m_data.swap(buffer);
1869}
1870
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001871SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs)
1872{
1873 m_data.swap(buffer);
1874 m_blobURLs.swap(blobURLs);
1875}
1876
1877SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001878 : m_arrayBufferContentsArray(arrayBufferContentsArray)
1879{
1880 m_data.swap(buffer);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001881 m_blobURLs.swap(blobURLs);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001882}
1883
1884PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001885 ExecState* exec, ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001886{
1887 for (size_t i = 0; i < arrayBuffers.size(); i++) {
1888 if (arrayBuffers[i]->isNeutered()) {
1889 code = ValidationError;
1890 return nullptr;
1891 }
1892 }
1893
1894 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
weinig@apple.com8f716032013-10-02 17:03:09 +00001895 Vector<Ref<DOMWrapperWorld>> worlds;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001896 static_cast<WebCoreJSClientData*>(exec->vm().clientData)->getAllWorlds(worlds);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001897
oliver@apple.comdf606082013-08-05 22:11:50 +00001898 HashSet<JSC::ArrayBuffer*> visited;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001899 for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001900 if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001901 continue;
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001902 visited.add(arrayBuffers[arrayBufferIndex].get());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001903
fpizlo@apple.com0e0d9312013-08-15 20:43:06 +00001904 bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex));
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001905 if (!result) {
1906 code = ValidationError;
1907 return nullptr;
1908 }
1909 }
1910 return contents.release();
1911}
1912
1913
1914PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value,
1915 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1916 SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001917{
1918 Vector<uint8_t> buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001919 Vector<String> blobURLs;
1920 SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, blobURLs, buffer);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001921
1922 OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
1923
1924 if (arrayBuffers && serializationDidCompleteSuccessfully(code))
fpizlo@apple.coma9188442013-08-01 22:14:28 +00001925 arrayBufferContentsArray = transferArrayBuffers(exec, *arrayBuffers, code);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001926
slewis@apple.comd0a103d2011-04-13 00:13:11 +00001927 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001928 maybeThrowExceptionIfSerializationFailed(exec, code);
1929
1930 if (!serializationDidCompleteSuccessfully(code))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001931 return 0;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001932
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001933 return adoptRef(new SerializedScriptValue(buffer, blobURLs, arrayBufferContentsArray.release()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00001934}
1935
1936PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1937{
1938 Vector<uint8_t> buffer;
1939 return adoptRef(new SerializedScriptValue(buffer));
1940}
1941
tony@chromium.org6b09aa62011-06-24 06:43:34 +00001942PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001943{
1944 Vector<uint8_t> buffer;
1945 if (!CloneSerializer::serialize(string, buffer))
1946 return 0;
1947 return adoptRef(new SerializedScriptValue(buffer));
1948}
1949
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001950#if ENABLE(INDEXED_DATABASE)
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001951PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::ExecState* exec, JSC::JSValue value)
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001952{
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001953 return SerializedScriptValue::create(exec, value, 0, 0);
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001954}
1955
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001956PassRefPtr<SerializedScriptValue> SerializedScriptValue::numberValue(double value)
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001957{
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001958 Vector<uint8_t> buffer;
1959 CloneSerializer::serializeNumber(value, buffer);
1960 return adoptRef(new SerializedScriptValue(buffer));
1961}
1962
1963JSValue SerializedScriptValue::deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
1964{
1965 return deserialize(exec, globalObject, 0);
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001966}
1967#endif
1968
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001969PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001970 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1971 JSValueRef* exception)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001972{
1973 ExecState* exec = toJS(originContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00001974 APIEntryShim entryShim(exec);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001975 JSValue value = toJS(exec, apiValue);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001976 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts, arrayBuffers);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001977 if (exec->hadException()) {
1978 if (exception)
1979 *exception = toRef(exec, exec->exception());
1980 exec->clearException();
1981 return 0;
1982 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001983 ASSERT(serializedValue);
levin@chromium.org550ac082011-08-22 23:30:10 +00001984 return serializedValue.release();
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001985}
1986
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001987PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
1988 JSValueRef* exception)
1989{
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001990 return create(originContext, apiValue, 0, 0, exception);
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001991}
1992
oliver@apple.com8128fe12010-09-06 21:29:06 +00001993String SerializedScriptValue::toString()
commit-queue@webkit.org72354062010-09-02 01:00:51 +00001994{
oliver@apple.com8128fe12010-09-06 21:29:06 +00001995 return CloneDeserializer::deserializeString(m_data);
1996}
1997
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001998JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001999 MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00002000{
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00002001 DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
2002 m_arrayBufferContentsArray.get(), m_data);
slewis@apple.comd0a103d2011-04-13 00:13:11 +00002003 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00002004 maybeThrowExceptionIfSerializationFailed(exec, result.second);
2005 return result.first;
commit-queue@webkit.org72354062010-09-02 01:00:51 +00002006}
2007
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +00002008#if ENABLE(INSPECTOR)
weinig@apple.com4da3e8d2013-09-14 01:30:06 +00002009ScriptValue SerializedScriptValue::deserializeForInspector(JSC::ExecState* scriptState)
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +00002010{
2011 JSValue value = deserialize(scriptState, scriptState->lexicalGlobalObject(), 0);
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +00002012 return ScriptValue(scriptState->vm(), value);
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +00002013}
2014#endif
2015
dslomov@google.com9386a8b2011-10-16 19:19:42 +00002016JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception, MessagePortArray* messagePorts)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002017{
2018 ExecState* exec = toJS(destinationContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00002019 APIEntryShim entryShim(exec);
dslomov@google.com9386a8b2011-10-16 19:19:42 +00002020 JSValue value = deserialize(exec, exec->lexicalGlobalObject(), messagePorts);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002021 if (exec->hadException()) {
2022 if (exception)
2023 *exception = toRef(exec, exec->exception());
2024 exec->clearException();
2025 return 0;
2026 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00002027 ASSERT(value);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00002028 return toRef(exec, value);
2029}
2030
dslomov@google.com9386a8b2011-10-16 19:19:42 +00002031
2032JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
2033{
2034 return deserialize(destinationContext, exception, 0);
2035}
2036
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00002037PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
oliver@apple.com8128fe12010-09-06 21:29:06 +00002038{
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00002039 return SerializedScriptValue::create();
oliver@apple.com8128fe12010-09-06 21:29:06 +00002040}
2041
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +00002042PassRefPtr<SerializedScriptValue> SerializedScriptValue::undefinedValue()
2043{
2044 Vector<uint8_t> buffer;
2045 CloneSerializer::serializeUndefined(buffer);
2046 return adoptRef(new SerializedScriptValue(buffer));
2047}
2048
2049PassRefPtr<SerializedScriptValue> SerializedScriptValue::booleanValue(bool value)
2050{
2051 Vector<uint8_t> buffer;
2052 CloneSerializer::serializeBoolean(value, buffer);
2053 return adoptRef(new SerializedScriptValue(buffer));
2054}
2055
slewis@apple.comfc28de52011-04-12 21:50:04 +00002056void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
2057{
2058 if (code == SuccessfullyCompleted)
2059 return;
2060
2061 switch (code) {
2062 case StackOverflowError:
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00002063 exec->vm().throwException(exec, createStackOverflowError(exec));
slewis@apple.comfc28de52011-04-12 21:50:04 +00002064 break;
slewis@apple.comfc28de52011-04-12 21:50:04 +00002065 case ValidationError:
commit-queue@webkit.org3f922f92013-08-29 00:28:42 +00002066 exec->vm().throwException(exec, createTypeError(exec, "Unable to deserialize data."));
slewis@apple.comfc28de52011-04-12 21:50:04 +00002067 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +00002068 case DataCloneError:
2069 setDOMException(exec, DATA_CLONE_ERR);
2070 break;
slewis@apple.comfc28de52011-04-12 21:50:04 +00002071 case ExistingExceptionError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00002072 break;
2073 case UnspecifiedError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00002074 break;
2075 default:
2076 ASSERT_NOT_REACHED();
2077 }
2078}
2079
2080bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
2081{
2082 return (code == SuccessfullyCompleted);
2083}
2084
jsbell@chromium.org43d46eb2012-12-07 17:52:36 +00002085uint32_t SerializedScriptValue::wireFormatVersion()
2086{
2087 return CurrentVersion;
2088}
2089
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00002090}