blob: 079da58c181d2728f449391486bdfbc4b8b2128e [file] [log] [blame]
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE 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"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000031#include "File.h"
oliver@apple.comcebc1862010-01-24 07:44:05 +000032#include "FileList.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000033#include "ImageData.h"
dslomov@google.coma3962422012-02-23 02:51:20 +000034#include "JSArrayBuffer.h"
35#include "JSArrayBufferView.h"
jianli@chromium.org51ceb752010-08-11 00:03:19 +000036#include "JSBlob.h"
dslomov@google.coma3962422012-02-23 02:51:20 +000037#include "JSDataView.h"
oliver@apple.com88ed9c12009-11-30 04:15:40 +000038#include "JSDOMGlobalObject.h"
39#include "JSFile.h"
40#include "JSFileList.h"
dslomov@google.coma3962422012-02-23 02:51:20 +000041#include "JSFloat32Array.h"
42#include "JSFloat64Array.h"
oliver@apple.com22ba59d2010-02-11 08:30:34 +000043#include "JSImageData.h"
dslomov@google.coma3962422012-02-23 02:51:20 +000044#include "JSInt16Array.h"
45#include "JSInt32Array.h"
46#include "JSInt8Array.h"
dslomov@google.comd60d08e2011-10-31 21:07:22 +000047#include "JSMessagePort.h"
slewis@apple.comfc28de52011-04-12 21:50:04 +000048#include "JSNavigator.h"
dslomov@google.coma3962422012-02-23 02:51:20 +000049#include "JSUint16Array.h"
50#include "JSUint32Array.h"
51#include "JSUint8Array.h"
52#include "JSUint8ClampedArray.h"
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +000053#include "NotImplemented.h"
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +000054#include "ScriptValue.h"
oliver@apple.com8128fe12010-09-06 21:29:06 +000055#include "SharedBuffer.h"
56#include <limits>
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +000057#include <JavaScriptCore/APICast.h>
timothy@apple.comf5a07a92011-03-03 18:28:29 +000058#include <JavaScriptCore/APIShims.h>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +000059#include <runtime/BooleanObject.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000060#include <runtime/DateInstance.h>
barraclough@apple.com9c099f92010-06-06 23:34:36 +000061#include <runtime/Error.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000062#include <runtime/ExceptionHelpers.h>
ggaren@apple.comc862eac2013-01-29 05:48:01 +000063#include <runtime/ObjectConstructor.h>
fpizlo@apple.coma4b4cbe2013-01-12 04:47:03 +000064#include <runtime/Operations.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000065#include <runtime/PropertyNameArray.h>
commit-queue@webkit.org7648c242010-09-08 00:33:15 +000066#include <runtime/RegExp.h>
67#include <runtime/RegExpObject.h>
dslomov@google.come2c8d4b2012-02-29 06:40:35 +000068#include <wtf/ArrayBuffer.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000069#include <wtf/HashTraits.h>
kbr@google.com1262e442012-04-24 03:43:31 +000070#include <wtf/Uint8ClampedArray.h>
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000071#include <wtf/Vector.h>
72
73using namespace JSC;
oliver@apple.com8128fe12010-09-06 21:29:06 +000074using namespace std;
75
oliver@apple.comf87795d2011-03-02 01:23:00 +000076#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
oliver@apple.com8128fe12010-09-06 21:29:06 +000077#define ASSUME_LITTLE_ENDIAN 0
78#else
79#define ASSUME_LITTLE_ENDIAN 1
80#endif
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000081
oliver@apple.comd83a9a22009-10-07 02:21:49 +000082namespace WebCore {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000083
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000084static const unsigned maximumFilterRecursion = 40000;
oliver@apple.com8128fe12010-09-06 21:29:06 +000085
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000086enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
87 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +000088
oliver@apple.com8128fe12010-09-06 21:29:06 +000089// These can't be reordered, and any new types must be added to the end of the list
90enum SerializationTag {
91 ArrayTag = 1,
92 ObjectTag = 2,
93 UndefinedTag = 3,
94 NullTag = 4,
95 IntTag = 5,
96 ZeroTag = 6,
97 OneTag = 7,
98 FalseTag = 8,
99 TrueTag = 9,
100 DoubleTag = 10,
101 DateTag = 11,
102 FileTag = 12,
103 FileListTag = 13,
104 ImageDataTag = 14,
105 BlobTag = 15,
106 StringTag = 16,
107 EmptyStringTag = 17,
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000108 RegExpTag = 18,
oliver@apple.come8641552010-12-20 22:40:37 +0000109 ObjectReferenceTag = 19,
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000110 MessagePortReferenceTag = 20,
dslomov@google.coma3962422012-02-23 02:51:20 +0000111 ArrayBufferTag = 21,
112 ArrayBufferViewTag = 22,
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000113 ArrayBufferTransferTag = 23,
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000114 TrueObjectTag = 24,
115 FalseObjectTag = 25,
116 StringObjectTag = 26,
117 EmptyStringObjectTag = 27,
118 NumberObjectTag = 28,
oliver@apple.com8128fe12010-09-06 21:29:06 +0000119 ErrorTag = 255
120};
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000121
dslomov@google.coma3962422012-02-23 02:51:20 +0000122enum ArrayBufferViewSubtag {
123 DataViewTag = 0,
124 Int8ArrayTag = 1,
125 Uint8ArrayTag = 2,
126 Uint8ClampedArrayTag = 3,
127 Int16ArrayTag = 4,
128 Uint16ArrayTag = 5,
129 Int32ArrayTag = 6,
130 Uint32ArrayTag = 7,
131 Float32ArrayTag = 8,
132 Float64ArrayTag = 9
133};
134
135static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag)
136{
137 switch (tag) {
138 case DataViewTag:
139 case Int8ArrayTag:
140 case Uint8ArrayTag:
141 case Uint8ClampedArrayTag:
142 return 1;
143 case Int16ArrayTag:
144 case Uint16ArrayTag:
145 return 2;
146 case Int32ArrayTag:
147 case Uint32ArrayTag:
148 case Float32ArrayTag:
149 return 4;
150 case Float64ArrayTag:
151 return 8;
152 default:
153 return 0;
154 }
155
156}
157
oliver@apple.come8641552010-12-20 22:40:37 +0000158/* CurrentVersion tracks the serialization version so that persistant stores
159 * are able to correctly bail out in the case of encountering newer formats.
160 *
161 * Initial version was 1.
162 * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000163 * Version 3. added the FalseObjectTag, TrueObjectTag, NumberObjectTag, StringObjectTag
164 * and EmptyStringObjectTag for serialization of Boolean, Number and String objects.
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000165 * Version 4. added support for serializing non-index properties of arrays.
oliver@apple.come8641552010-12-20 22:40:37 +0000166 */
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000167static const unsigned CurrentVersion = 4;
168static const unsigned TerminatorTag = 0xFFFFFFFF;
169static const unsigned StringPoolTag = 0xFFFFFFFE;
170static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000171
oliver@apple.com8128fe12010-09-06 21:29:06 +0000172/*
173 * Object serialization is performed according to the following grammar, all tags
174 * are recorded as a single uint8_t.
175 *
oliver@apple.come8641552010-12-20 22:40:37 +0000176 * IndexType (used for the object pool and StringData's constant pool) is the
177 * minimum sized unsigned integer type required to represent the maximum index
178 * in the constant pool.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000179 *
180 * SerializedValue :- <CurrentVersion:uint32_t> Value
181 * Value :- Array | Object | Terminal
182 *
183 * Array :-
184 * ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
185 *
186 * Object :-
187 * ObjectTag (<name:StringData><value:Value>)* TerminatorTag
188 *
189 * Terminal :-
190 * UndefinedTag
191 * | NullTag
192 * | IntTag <value:int32_t>
193 * | ZeroTag
194 * | OneTag
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000195 * | FalseTag
196 * | TrueTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000197 * | FalseObjectTag
198 * | TrueObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000199 * | DoubleTag <value:double>
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000200 * | NumberObjectTag <value:double>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000201 * | DateTag <value:double>
202 * | String
203 * | EmptyStringTag
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000204 * | EmptyStringObjectTag
oliver@apple.com8128fe12010-09-06 21:29:06 +0000205 * | File
206 * | FileList
207 * | ImageData
208 * | Blob
dslomov@google.coma3962422012-02-23 02:51:20 +0000209 * | ObjectReference
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000210 * | MessagePortReferenceTag <value:uint32_t>
dslomov@google.coma3962422012-02-23 02:51:20 +0000211 * | ArrayBuffer
212 * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLenght:uint32_t> (ArrayBuffer | ObjectReference)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000213 * | ArrayBufferTransferTag <value:uint32_t>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000214 *
215 * String :-
216 * EmptyStringTag
217 * StringTag StringData
218 *
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000219 * StringObject:
220 * EmptyStringObjectTag
221 * StringObjectTag StringData
222 *
oliver@apple.com8128fe12010-09-06 21:29:06 +0000223 * StringData :-
224 * StringPoolTag <cpIndex:IndexType>
225 * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
226 *
227 * File :-
228 * FileTag FileData
229 *
230 * FileData :-
231 * <path:StringData> <url:StringData> <type:StringData>
232 *
233 * FileList :-
234 * FileListTag <length:uint32_t>(<file:FileData>){length}
235 *
236 * ImageData :-
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000237 * ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000238 *
239 * Blob :-
240 * BlobTag <url:StringData><type:StringData><size:long long>
241 *
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000242 * RegExp :-
243 * RegExpTag <pattern:StringData><flags:StringData>
dslomov@google.coma3962422012-02-23 02:51:20 +0000244 *
245 * ObjectReference :-
246 * ObjectReferenceTag <opIndex:IndexType>
247 *
248 * ArrayBuffer :-
249 * ArrayBufferTag <length:uint32_t> <contents:byte{length}>
oliver@apple.com8128fe12010-09-06 21:29:06 +0000250 */
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000251
slewis@apple.comfc28de52011-04-12 21:50:04 +0000252typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
253
oliver@apple.com8128fe12010-09-06 21:29:06 +0000254class CloneBase {
255protected:
256 CloneBase(ExecState* exec)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000257 : m_exec(exec)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000258 , m_failed(false)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000259 , m_timeoutChecker(exec->globalData().timeoutChecker)
260 {
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000261 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000262
263 bool shouldTerminate()
264 {
265 return m_exec->hadException();
266 }
267
268 unsigned ticksUntilNextCheck()
269 {
270 return m_timeoutChecker.ticksUntilNextCheck();
271 }
272
273 bool didTimeOut()
274 {
275 return m_timeoutChecker.didTimeOut(m_exec);
276 }
277
278 void throwStackOverflow()
279 {
barraclough@apple.com9c099f92010-06-06 23:34:36 +0000280 throwError(m_exec, createStackOverflowError(m_exec));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000281 }
282
283 void throwInterruptedException()
284 {
barraclough@apple.com9c099f92010-06-06 23:34:36 +0000285 throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000286 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000287
weinig@apple.com21498652011-08-13 02:40:51 +0000288 NO_RETURN_DUE_TO_ASSERT
oliver@apple.com8128fe12010-09-06 21:29:06 +0000289 void fail()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000290 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000291 ASSERT_NOT_REACHED();
292 m_failed = true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000293 }
294
oliver@apple.com8128fe12010-09-06 21:29:06 +0000295 ExecState* m_exec;
296 bool m_failed;
297 TimeoutChecker m_timeoutChecker;
298 MarkedArgumentBuffer m_gcBuffer;
299};
300
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000301#if ASSUME_LITTLE_ENDIAN
302template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
303{
304 buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
305}
306#else
307template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
308{
309 for (unsigned i = 0; i < sizeof(T); i++) {
310 buffer.append(value & 0xFF);
311 value >>= 8;
312 }
313}
314#endif
315
cwzwarich@webkit.orgd0ef6552011-03-13 03:36:23 +0000316template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
cwzwarich@webkit.orgcb142e22011-03-13 03:18:37 +0000317{
318 buffer.append(value);
319}
320
321template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
322{
323 if (length > numeric_limits<uint32_t>::max() / sizeof(T))
324 return false;
325
326#if ASSUME_LITTLE_ENDIAN
327 buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
328#else
329 for (unsigned i = 0; i < length; i++) {
330 T value = values[i];
331 for (unsigned j = 0; j < sizeof(T); j++) {
332 buffer.append(static_cast<uint8_t>(value & 0xFF));
333 value >>= 8;
334 }
335 }
336#endif
337 return true;
338}
339
oliver@apple.com8128fe12010-09-06 21:29:06 +0000340class CloneSerializer : CloneBase {
341public:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000342 static SerializationReturnCode serialize(ExecState* exec, JSValue value,
343 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000344 Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000345 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000346 CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000347 return serializer.serialize(value);
348 }
349
tony@chromium.org6b09aa62011-06-24 06:43:34 +0000350 static bool serialize(const String& s, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000351 {
352 writeLittleEndian(out, CurrentVersion);
353 if (s.isEmpty()) {
354 writeLittleEndian<uint8_t>(out, EmptyStringTag);
355 return true;
356 }
357 writeLittleEndian<uint8_t>(out, StringTag);
358 writeLittleEndian(out, s.length());
359 return writeLittleEndian(out, s.impl()->characters(), s.length());
360 }
361
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +0000362 static void serializeUndefined(Vector<uint8_t>& out)
363 {
364 writeLittleEndian(out, CurrentVersion);
365 writeLittleEndian<uint8_t>(out, UndefinedTag);
366 }
367
368 static void serializeBoolean(bool value, Vector<uint8_t>& out)
369 {
370 writeLittleEndian(out, CurrentVersion);
371 writeLittleEndian<uint8_t>(out, value ? TrueTag : FalseTag);
372 }
373
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +0000374 static void serializeNumber(double value, Vector<uint8_t>& out)
375 {
376 writeLittleEndian(out, CurrentVersion);
377 writeLittleEndian<uint8_t>(out, DoubleTag);
378 union {
379 double d;
380 int64_t i;
381 } u;
382 u.d = value;
383 writeLittleEndian(out, u.i);
384 }
385
oliver@apple.com8128fe12010-09-06 21:29:06 +0000386private:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000387 typedef HashMap<JSObject*, uint32_t> ObjectPool;
388
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000389 CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000390 : CloneBase(exec)
391 , m_buffer(out)
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000392 , m_blobURLs(blobURLs)
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000393 , m_emptyIdentifier(exec, emptyString())
oliver@apple.com8128fe12010-09-06 21:29:06 +0000394 {
395 write(CurrentVersion);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000396 fillTransferMap(messagePorts, m_transferredMessagePorts);
397 fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
398 }
399
400 template <class T>
401 void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result)
402 {
403 if (!input)
404 return;
oliver@apple.comffe14422012-04-05 22:33:19 +0000405 JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000406 for (size_t i = 0; i < input->size(); i++) {
407 JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get());
408 JSC::JSObject* obj = value.getObject();
409 if (obj && !result.contains(obj))
410 result.add(obj, i);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000411 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000412 }
413
slewis@apple.comfc28de52011-04-12 21:50:04 +0000414 SerializationReturnCode serialize(JSValue in);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000415
416 bool isArray(JSValue value)
417 {
418 if (!value.isObject())
419 return false;
420 JSObject* object = asObject(value);
mhahnenberg@apple.comc58d54d2011-12-16 19:06:44 +0000421 return isJSArray(object) || object->inherits(&JSArray::s_info);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000422 }
423
dslomov@google.com6c31be52012-04-04 20:43:31 +0000424 bool checkForDuplicate(JSObject* object)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000425 {
oliver@apple.come8641552010-12-20 22:40:37 +0000426 // Record object for graph reconstruction
dslomov@google.comfd060da2012-04-12 19:16:49 +0000427 ObjectPool::const_iterator found = m_objectPool.find(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000428
oliver@apple.come8641552010-12-20 22:40:37 +0000429 // Handle duplicate references
dslomov@google.comfd060da2012-04-12 19:16:49 +0000430 if (found != m_objectPool.end()) {
oliver@apple.come8641552010-12-20 22:40:37 +0000431 write(ObjectReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000432 ASSERT(static_cast<int32_t>(found->value) < m_objectPool.size());
433 writeObjectIndex(found->value);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000434 return true;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000435 }
dslomov@google.com6c31be52012-04-04 20:43:31 +0000436
437 return false;
438 }
439
440 void recordObject(JSObject* object)
441 {
442 m_objectPool.add(object, m_objectPool.size());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000443 m_gcBuffer.append(object);
dslomov@google.com6c31be52012-04-04 20:43:31 +0000444 }
445
446 bool startObjectInternal(JSObject* object)
447 {
448 if (checkForDuplicate(object))
449 return false;
450 recordObject(object);
oliver@apple.come8641552010-12-20 22:40:37 +0000451 return true;
452 }
453
454 bool startObject(JSObject* object)
455 {
456 if (!startObjectInternal(object))
457 return false;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000458 write(ObjectTag);
459 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000460 }
461
oliver@apple.com8128fe12010-09-06 21:29:06 +0000462 bool startArray(JSArray* array)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000463 {
oliver@apple.come8641552010-12-20 22:40:37 +0000464 if (!startObjectInternal(array))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000465 return false;
oliver@apple.come8641552010-12-20 22:40:37 +0000466
oliver@apple.com8128fe12010-09-06 21:29:06 +0000467 unsigned length = array->length();
468 write(ArrayTag);
469 write(length);
470 return true;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000471 }
472
oliver@apple.come8641552010-12-20 22:40:37 +0000473 void endObject()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000474 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000475 write(TerminatorTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000476 }
477
oliver@apple.com8128fe12010-09-06 21:29:06 +0000478 JSValue getProperty(JSObject* object, const Identifier& propertyName)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000479 {
480 PropertySlot slot(object);
mhahnenberg@apple.com5c103b02011-10-26 17:55:34 +0000481 if (object->methodTable()->getOwnPropertySlot(object, m_exec, propertyName, slot))
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000482 return slot.getValue(m_exec, propertyName);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000483 return JSValue();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000484 }
485
oliver@apple.com8128fe12010-09-06 21:29:06 +0000486 void dumpImmediate(JSValue value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000487 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000488 if (value.isNull())
489 write(NullTag);
490 else if (value.isUndefined())
491 write(UndefinedTag);
492 else if (value.isNumber()) {
493 if (value.isInt32()) {
494 if (!value.asInt32())
495 write(ZeroTag);
496 else if (value.asInt32() == 1)
497 write(OneTag);
498 else {
499 write(IntTag);
500 write(static_cast<uint32_t>(value.asInt32()));
501 }
502 } else {
503 write(DoubleTag);
504 write(value.asDouble());
505 }
506 } else if (value.isBoolean()) {
507 if (value.isTrue())
508 write(TrueTag);
509 else
510 write(FalseTag);
511 }
512 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000513
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000514 void dumpString(String str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000515 {
516 if (str.isEmpty())
517 write(EmptyStringTag);
518 else {
519 write(StringTag);
520 write(str);
521 }
522 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000523
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000524 void dumpStringObject(String str)
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000525 {
526 if (str.isEmpty())
527 write(EmptyStringObjectTag);
528 else {
529 write(StringObjectTag);
530 write(str);
531 }
532 }
533
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000534 bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
dslomov@google.coma3962422012-02-23 02:51:20 +0000535 {
536 write(ArrayBufferViewTag);
537 if (obj->inherits(&JSDataView::s_info))
538 write(DataViewTag);
539 else if (obj->inherits(&JSUint8ClampedArray::s_info))
540 write(Uint8ClampedArrayTag);
541 else if (obj->inherits(&JSInt8Array::s_info))
542 write(Int8ArrayTag);
543 else if (obj->inherits(&JSUint8Array::s_info))
544 write(Uint8ArrayTag);
545 else if (obj->inherits(&JSInt16Array::s_info))
546 write(Int16ArrayTag);
547 else if (obj->inherits(&JSUint16Array::s_info))
548 write(Uint16ArrayTag);
549 else if (obj->inherits(&JSInt32Array::s_info))
550 write(Int32ArrayTag);
551 else if (obj->inherits(&JSUint32Array::s_info))
552 write(Uint32ArrayTag);
553 else if (obj->inherits(&JSFloat32Array::s_info))
554 write(Float32ArrayTag);
555 else if (obj->inherits(&JSFloat64Array::s_info))
556 write(Float64ArrayTag);
557 else
558 return false;
559
560 RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj);
561 write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
562 write(static_cast<uint32_t>(arrayBufferView->byteLength()));
563 RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000564 if (!arrayBuffer) {
565 code = ValidationError;
566 return true;
567 }
oliver@apple.comffe14422012-04-05 22:33:19 +0000568 JSValue bufferObj = toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get());
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000569 return dumpIfTerminal(bufferObj, code);
dslomov@google.coma3962422012-02-23 02:51:20 +0000570 }
571
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000572 bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000573 {
574 if (!value.isCell()) {
575 dumpImmediate(value);
576 return true;
577 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000578
oliver@apple.com8128fe12010-09-06 21:29:06 +0000579 if (value.isString()) {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000580 String str = asString(value)->value(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000581 dumpString(str);
582 return true;
583 }
584
585 if (value.isNumber()) {
586 write(DoubleTag);
ggaren@apple.com7831f0c2011-10-05 02:38:49 +0000587 write(value.asNumber());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000588 return true;
589 }
590
barraclough@apple.coma5540da2011-02-19 21:55:44 +0000591 if (value.isObject() && asObject(value)->inherits(&DateInstance::s_info)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000592 write(DateTag);
593 write(asDateInstance(value)->internalNumber());
594 return true;
595 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000596
597 if (isArray(value))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000598 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000599
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000600 if (value.isObject()) {
601 JSObject* obj = asObject(value);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000602 if (obj->inherits(&BooleanObject::s_info)) {
603 if (!startObjectInternal(obj)) // handle duplicates
604 return true;
mhahnenberg@apple.com3b9069c2012-08-23 23:00:31 +0000605 write(asBooleanObject(value)->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000606 return true;
607 }
608 if (obj->inherits(&StringObject::s_info)) {
609 if (!startObjectInternal(obj)) // handle duplicates
610 return true;
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000611 String str = asString(asStringObject(value)->internalValue())->value(m_exec);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +0000612 dumpStringObject(str);
613 return true;
614 }
615 if (obj->inherits(&NumberObject::s_info)) {
616 if (!startObjectInternal(obj)) // handle duplicates
617 return true;
618 write(NumberObjectTag);
619 NumberObject* obj = static_cast<NumberObject*>(asObject(value));
620 write(obj->internalValue().asNumber());
621 return true;
622 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000623 if (obj->inherits(&JSFile::s_info)) {
624 write(FileTag);
625 write(toFile(obj));
626 return true;
627 }
628 if (obj->inherits(&JSFileList::s_info)) {
629 FileList* list = toFileList(obj);
630 write(FileListTag);
631 unsigned length = list->length();
632 write(length);
633 for (unsigned i = 0; i < length; i++)
634 write(list->item(i));
635 return true;
636 }
637 if (obj->inherits(&JSBlob::s_info)) {
638 write(BlobTag);
639 Blob* blob = toBlob(obj);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000640 m_blobURLs.append(blob->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000641 write(blob->url());
642 write(blob->type());
643 write(blob->size());
644 return true;
645 }
646 if (obj->inherits(&JSImageData::s_info)) {
647 ImageData* data = toImageData(obj);
648 write(ImageDataTag);
649 write(data->width());
650 write(data->height());
651 write(data->data()->length());
kbr@google.com1262e442012-04-24 03:43:31 +0000652 write(data->data()->data(), data->data()->length());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000653 return true;
654 }
barraclough@apple.coma5540da2011-02-19 21:55:44 +0000655 if (obj->inherits(&RegExpObject::s_info)) {
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000656 RegExpObject* regExp = asRegExpObject(obj);
657 char flags[3];
658 int flagCount = 0;
659 if (regExp->regExp()->global())
660 flags[flagCount++] = 'g';
661 if (regExp->regExp()->ignoreCase())
662 flags[flagCount++] = 'i';
663 if (regExp->regExp()->multiline())
664 flags[flagCount++] = 'm';
665 write(RegExpTag);
666 write(regExp->regExp()->pattern());
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000667 write(String(flags, flagCount));
commit-queue@webkit.org7648c242010-09-08 00:33:15 +0000668 return true;
669 }
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000670 if (obj->inherits(&JSMessagePort::s_info)) {
671 ObjectPool::iterator index = m_transferredMessagePorts.find(obj);
672 if (index != m_transferredMessagePorts.end()) {
673 write(MessagePortReferenceTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000674 write(index->value);
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000675 return true;
676 }
commit-queue@webkit.orgd9ae4552012-05-31 02:58:48 +0000677 // MessagePort object could not be found in transferred message ports
678 code = ValidationError;
679 return true;
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000680 }
dslomov@google.coma3962422012-02-23 02:51:20 +0000681 if (obj->inherits(&JSArrayBuffer::s_info)) {
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000682 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(obj);
683 if (arrayBuffer->isNeutered()) {
684 code = ValidationError;
685 return true;
686 }
687 ObjectPool::iterator index = m_transferredArrayBuffers.find(obj);
688 if (index != m_transferredArrayBuffers.end()) {
689 write(ArrayBufferTransferTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000690 write(index->value);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000691 return true;
692 }
dslomov@google.coma3962422012-02-23 02:51:20 +0000693 if (!startObjectInternal(obj)) // handle duplicates
694 return true;
695 write(ArrayBufferTag);
dslomov@google.coma3962422012-02-23 02:51:20 +0000696 write(arrayBuffer->byteLength());
697 write(static_cast<const uint8_t *>(arrayBuffer->data()), arrayBuffer->byteLength());
698 return true;
699 }
700 if (obj->inherits(&JSArrayBufferView::s_info)) {
dslomov@google.com6c31be52012-04-04 20:43:31 +0000701 if (checkForDuplicate(obj))
dslomov@google.coma3962422012-02-23 02:51:20 +0000702 return true;
dslomov@google.com6c31be52012-04-04 20:43:31 +0000703 bool success = dumpArrayBufferView(obj, code);
704 recordObject(obj);
705 return success;
dslomov@google.coma3962422012-02-23 02:51:20 +0000706 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000707
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000708 return false;
oliver@apple.com88ed9c12009-11-30 04:15:40 +0000709 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000710 // Any other types are expected to serialize as null.
oliver@apple.com8128fe12010-09-06 21:29:06 +0000711 write(NullTag);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000712 return true;
713 }
714
oliver@apple.com8128fe12010-09-06 21:29:06 +0000715 void write(SerializationTag tag)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000716 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000717 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000718 }
719
dslomov@google.coma3962422012-02-23 02:51:20 +0000720 void write(ArrayBufferViewSubtag tag)
721 {
722 writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
723 }
724
oliver@apple.com8128fe12010-09-06 21:29:06 +0000725 void write(uint8_t c)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000726 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000727 writeLittleEndian(m_buffer, c);
728 }
729
oliver@apple.com8128fe12010-09-06 21:29:06 +0000730 void write(uint32_t i)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +0000731 {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000732 writeLittleEndian(m_buffer, i);
733 }
734
735 void write(double d)
736 {
737 union {
738 double d;
739 int64_t i;
740 } u;
741 u.d = d;
742 writeLittleEndian(m_buffer, u.i);
743 }
744
reni@webkit.orgfa0c6682011-01-06 16:50:45 +0000745 void write(int32_t i)
746 {
747 writeLittleEndian(m_buffer, i);
748 }
749
oliver@apple.com8128fe12010-09-06 21:29:06 +0000750 void write(unsigned long long i)
751 {
752 writeLittleEndian(m_buffer, i);
753 }
oliver@apple.coma9b47542010-09-06 22:53:32 +0000754
755 void write(uint16_t ch)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000756 {
oliver@apple.coma9b47542010-09-06 22:53:32 +0000757 writeLittleEndian(m_buffer, ch);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000758 }
759
760 void writeStringIndex(unsigned i)
761 {
oliver@apple.come8641552010-12-20 22:40:37 +0000762 writeConstantPoolIndex(m_constantPool, i);
763 }
764
765 void writeObjectIndex(unsigned i)
766 {
767 writeConstantPoolIndex(m_objectPool, i);
768 }
769
770 template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
771 {
772 ASSERT(static_cast<int32_t>(i) < constantPool.size());
773 if (constantPool.size() <= 0xFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000774 write(static_cast<uint8_t>(i));
oliver@apple.come8641552010-12-20 22:40:37 +0000775 else if (constantPool.size() <= 0xFFFF)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000776 write(static_cast<uint16_t>(i));
777 else
778 write(static_cast<uint32_t>(i));
779 }
780
781 void write(const Identifier& ident)
782 {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +0000783 const String& str = ident.string();
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000784 StringConstantPool::AddResult addResult = m_constantPool.add(str.impl(), m_constantPool.size());
785 if (!addResult.isNewEntry) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000786 write(StringPoolTag);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000787 writeStringIndex(addResult.iterator->value);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000788 return;
789 }
790
791 // This condition is unlikely to happen as they would imply an ~8gb
792 // string but we should guard against it anyway
793 if (str.length() >= StringPoolTag) {
794 fail();
795 return;
796 }
797
798 // Guard against overflow
799 if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
800 fail();
801 return;
802 }
803
804 writeLittleEndian<uint32_t>(m_buffer, str.length());
oliver@apple.com906a13c2010-09-06 23:31:09 +0000805 if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
oliver@apple.com8128fe12010-09-06 21:29:06 +0000806 fail();
807 }
808
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +0000809 void write(const String& str)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000810 {
811 if (str.isNull())
812 write(m_emptyIdentifier);
813 else
814 write(Identifier(m_exec, str));
815 }
816
oliver@apple.com8128fe12010-09-06 21:29:06 +0000817 void write(const File* file)
818 {
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000819 m_blobURLs.append(file->url());
oliver@apple.com8128fe12010-09-06 21:29:06 +0000820 write(file->path());
821 write(file->url());
822 write(file->type());
823 }
824
825 void write(const uint8_t* data, unsigned length)
826 {
827 m_buffer.append(data, length);
828 }
829
830 Vector<uint8_t>& m_buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +0000831 Vector<String>& m_blobURLs;
oliver@apple.come8641552010-12-20 22:40:37 +0000832 ObjectPool m_objectPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +0000833 ObjectPool m_transferredMessagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000834 ObjectPool m_transferredArrayBuffers;
oliver@apple.come8641552010-12-20 22:40:37 +0000835 typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
836 StringConstantPool m_constantPool;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000837 Identifier m_emptyIdentifier;
838};
839
slewis@apple.comfc28de52011-04-12 21:50:04 +0000840SerializationReturnCode CloneSerializer::serialize(JSValue in)
oliver@apple.com8128fe12010-09-06 21:29:06 +0000841{
842 Vector<uint32_t, 16> indexStack;
843 Vector<uint32_t, 16> lengthStack;
844 Vector<PropertyNameArray, 16> propertyStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000845 Vector<JSObject*, 32> inputObjectStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000846 Vector<WalkerState, 16> stateStack;
847 WalkerState state = StateUnknown;
848 JSValue inValue = in;
849 unsigned tickCount = ticksUntilNextCheck();
850 while (1) {
851 switch (state) {
852 arrayStartState:
853 case ArrayStartState: {
854 ASSERT(isArray(inValue));
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000855 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +0000856 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000857
858 JSArray* inArray = asArray(inValue);
859 unsigned length = inArray->length();
860 if (!startArray(inArray))
oliver@apple.come8641552010-12-20 22:40:37 +0000861 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000862 inputObjectStack.append(inArray);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000863 indexStack.append(0);
864 lengthStack.append(length);
865 // fallthrough
866 }
867 arrayStartVisitMember:
868 case ArrayStartVisitMember: {
869 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +0000870 if (didTimeOut())
871 return InterruptedExecutionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000872 tickCount = ticksUntilNextCheck();
873 }
874
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000875 JSObject* array = inputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000876 uint32_t index = indexStack.last();
877 if (index == lengthStack.last()) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000878 indexStack.removeLast();
879 lengthStack.removeLast();
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000880
881 propertyStack.append(PropertyNameArray(m_exec));
882 array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
883 if (propertyStack.last().size()) {
884 write(NonIndexPropertiesTag);
885 indexStack.append(0);
886 goto objectStartVisitMember;
887 }
888 propertyStack.removeLast();
889
890 endObject();
891 inputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000892 break;
893 }
fpizlo@apple.com7ebfaed2012-09-25 23:42:52 +0000894 inValue = array->getDirectIndex(m_exec, index);
895 if (!inValue) {
896 indexStack.last()++;
897 goto arrayStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000898 }
899
900 write(index);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000901 SerializationReturnCode terminalCode = SuccessfullyCompleted;
902 if (dumpIfTerminal(inValue, terminalCode)) {
903 if (terminalCode != SuccessfullyCompleted)
904 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000905 indexStack.last()++;
906 goto arrayStartVisitMember;
907 }
908 stateStack.append(ArrayEndVisitMember);
909 goto stateUnknown;
910 }
911 case ArrayEndVisitMember: {
912 indexStack.last()++;
913 goto arrayStartVisitMember;
914 }
915 objectStartState:
916 case ObjectStartState: {
917 ASSERT(inValue.isObject());
commit-queue@webkit.org811fb852013-01-07 19:03:44 +0000918 if (inputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +0000919 return StackOverflowError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000920 JSObject* inObject = asObject(inValue);
921 if (!startObject(inObject))
oliver@apple.come8641552010-12-20 22:40:37 +0000922 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +0000923 // At this point, all supported objects other than Object
924 // objects have been handled. If we reach this point and
925 // the input is not an Object object then we should throw
926 // a DataCloneError.
927 if (inObject->classInfo() != &JSFinalObject::s_info)
928 return DataCloneError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000929 inputObjectStack.append(inObject);
930 indexStack.append(0);
931 propertyStack.append(PropertyNameArray(m_exec));
mhahnenberg@apple.com57262382011-11-03 00:25:45 +0000932 inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
oliver@apple.com8128fe12010-09-06 21:29:06 +0000933 // fallthrough
934 }
935 objectStartVisitMember:
936 case ObjectStartVisitMember: {
937 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +0000938 if (didTimeOut())
939 return InterruptedExecutionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000940 tickCount = ticksUntilNextCheck();
941 }
942
943 JSObject* object = inputObjectStack.last();
944 uint32_t index = indexStack.last();
945 PropertyNameArray& properties = propertyStack.last();
946 if (index == properties.size()) {
oliver@apple.come8641552010-12-20 22:40:37 +0000947 endObject();
oliver@apple.com8128fe12010-09-06 21:29:06 +0000948 inputObjectStack.removeLast();
949 indexStack.removeLast();
950 propertyStack.removeLast();
951 break;
952 }
953 inValue = getProperty(object, properties[index]);
954 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000955 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000956
957 if (!inValue) {
958 // Property was removed during serialisation
959 indexStack.last()++;
960 goto objectStartVisitMember;
961 }
962 write(properties[index]);
963
964 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000965 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000966
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000967 SerializationReturnCode terminalCode = SuccessfullyCompleted;
968 if (!dumpIfTerminal(inValue, terminalCode)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +0000969 stateStack.append(ObjectEndVisitMember);
970 goto stateUnknown;
971 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000972 if (terminalCode != SuccessfullyCompleted)
973 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000974 // fallthrough
975 }
976 case ObjectEndVisitMember: {
977 if (shouldTerminate())
slewis@apple.comfc28de52011-04-12 21:50:04 +0000978 return ExistingExceptionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000979
980 indexStack.last()++;
981 goto objectStartVisitMember;
982 }
983 stateUnknown:
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000984 case StateUnknown: {
985 SerializationReturnCode terminalCode = SuccessfullyCompleted;
986 if (dumpIfTerminal(inValue, terminalCode)) {
987 if (terminalCode != SuccessfullyCompleted)
988 return terminalCode;
oliver@apple.com8128fe12010-09-06 21:29:06 +0000989 break;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000990 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000991
992 if (isArray(inValue))
993 goto arrayStartState;
994 goto objectStartState;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +0000995 }
oliver@apple.com8128fe12010-09-06 21:29:06 +0000996 }
997 if (stateStack.isEmpty())
998 break;
999
1000 state = stateStack.last();
1001 stateStack.removeLast();
1002
1003 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +00001004 if (didTimeOut())
1005 return InterruptedExecutionError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001006 tickCount = ticksUntilNextCheck();
1007 }
1008 }
1009 if (m_failed)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001010 return UnspecifiedError;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001011
slewis@apple.comfc28de52011-04-12 21:50:04 +00001012 return SuccessfullyCompleted;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001013}
1014
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001015typedef Vector<WTF::ArrayBufferContents> ArrayBufferContentsArray;
1016
oliver@apple.com8128fe12010-09-06 21:29:06 +00001017class CloneDeserializer : CloneBase {
1018public:
1019 static String deserializeString(const Vector<uint8_t>& buffer)
1020 {
1021 const uint8_t* ptr = buffer.begin();
1022 const uint8_t* end = buffer.end();
1023 uint32_t version;
1024 if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
1025 return String();
1026 uint8_t tag;
1027 if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
1028 return String();
1029 uint32_t length;
1030 if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
1031 return String();
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001032 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001033 if (!readString(ptr, end, str, length))
1034 return String();
1035 return String(str.impl());
1036 }
1037
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001038 static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
1039 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001040 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001041 {
1042 if (!buffer.size())
slewis@apple.comfc28de52011-04-12 21:50:04 +00001043 return make_pair(jsNull(), UnspecifiedError);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001044 CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
slewis@apple.comfc28de52011-04-12 21:50:04 +00001045 if (!deserializer.isValid())
1046 return make_pair(JSValue(), ValidationError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001047 return deserializer.deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001048 }
1049
1050private:
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001051 struct CachedString {
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001052 CachedString(const String& string)
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001053 : m_string(string)
1054 {
1055 }
1056
1057 JSValue jsString(ExecState* exec)
1058 {
1059 if (!m_jsString)
1060 m_jsString = JSC::jsString(exec, m_string);
1061 return m_jsString;
1062 }
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001063 const String& string() { return m_string; }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001064
1065 private:
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001066 String m_string;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001067 JSValue m_jsString;
1068 };
1069
oliver@apple.com86609602010-10-19 02:33:33 +00001070 struct CachedStringRef {
1071 CachedStringRef()
1072 : m_base(0)
1073 , m_index(0)
1074 {
1075 }
1076 CachedStringRef(Vector<CachedString>* base, size_t index)
1077 : m_base(base)
1078 , m_index(index)
1079 {
1080 }
1081
1082 CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
1083
1084 private:
1085 Vector<CachedString>* m_base;
1086 size_t m_index;
1087 };
1088
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001089 CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject,
1090 MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
1091 const Vector<uint8_t>& buffer)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001092 : CloneBase(exec)
oliver@apple.com5deb8d82010-01-28 04:47:07 +00001093 , m_globalObject(globalObject)
1094 , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001095 , m_ptr(buffer.data())
1096 , m_end(buffer.data() + buffer.size())
1097 , m_version(0xFFFFFFFF)
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001098 , m_messagePorts(messagePorts)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001099 , m_arrayBufferContents(arrayBufferContents)
1100 , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001101 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001102 if (!read(m_version))
1103 m_version = 0xFFFFFFFF;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001104 }
1105
slewis@apple.comfc28de52011-04-12 21:50:04 +00001106 DeserializationResult deserialize();
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001107
oliver@apple.com8128fe12010-09-06 21:29:06 +00001108 void throwValidationError()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001109 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001110 throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001111 }
1112
oliver@apple.com8128fe12010-09-06 21:29:06 +00001113 bool isValid() const { return m_version <= CurrentVersion; }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001114
oliver@apple.com8128fe12010-09-06 21:29:06 +00001115 template <typename T> bool readLittleEndian(T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001116 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001117 if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
1118 fail();
1119 return false;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001120 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001121 return true;
1122 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001123#if ASSUME_LITTLE_ENDIAN
1124 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001125 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001126 if (ptr > end - sizeof(value))
1127 return false;
1128
1129 if (sizeof(T) == 1)
1130 value = *ptr++;
1131 else {
commit-queue@webkit.orgbfe8ef62010-10-13 19:21:48 +00001132 value = *reinterpret_cast<const T*>(ptr);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001133 ptr += sizeof(T);
1134 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001135 return true;
1136 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001137#else
1138 template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001139 {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001140 if (ptr > end - sizeof(value))
1141 return false;
1142
1143 if (sizeof(T) == 1)
1144 value = *ptr++;
1145 else {
1146 value = 0;
1147 for (unsigned i = 0; i < sizeof(T); i++)
1148 value += ((T)*ptr++) << (i * 8);
1149 }
1150 return true;
1151 }
1152#endif
1153
1154 bool read(uint32_t& i)
1155 {
1156 return readLittleEndian(i);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001157 }
1158
oliver@apple.com8128fe12010-09-06 21:29:06 +00001159 bool read(int32_t& i)
1160 {
1161 return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
1162 }
1163
1164 bool read(uint16_t& i)
1165 {
1166 return readLittleEndian(i);
1167 }
1168
1169 bool read(uint8_t& i)
1170 {
1171 return readLittleEndian(i);
1172 }
1173
1174 bool read(double& d)
1175 {
1176 union {
1177 double d;
1178 uint64_t i64;
1179 } u;
1180 if (!readLittleEndian(u.i64))
1181 return false;
1182 d = u.d;
1183 return true;
1184 }
1185
1186 bool read(unsigned long long& i)
1187 {
1188 return readLittleEndian(i);
1189 }
1190
1191 bool readStringIndex(uint32_t& i)
1192 {
oliver@apple.come8641552010-12-20 22:40:37 +00001193 return readConstantPoolIndex(m_constantPool, i);
1194 }
1195
1196 template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
1197 {
1198 if (constantPool.size() <= 0xFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001199 uint8_t i8;
1200 if (!read(i8))
1201 return false;
1202 i = i8;
1203 return true;
1204 }
oliver@apple.come8641552010-12-20 22:40:37 +00001205 if (constantPool.size() <= 0xFFFF) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001206 uint16_t i16;
1207 if (!read(i16))
1208 return false;
1209 i = i16;
1210 return true;
1211 }
1212 return read(i);
1213 }
1214
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001215 static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001216 {
1217 if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
1218 return false;
1219
1220 unsigned size = length * sizeof(UChar);
1221 if ((end - ptr) < static_cast<int>(size))
1222 return false;
1223
1224#if ASSUME_LITTLE_ENDIAN
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001225 str = String(reinterpret_cast<const UChar*>(ptr), length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001226 ptr += length * sizeof(UChar);
1227#else
1228 Vector<UChar> buffer;
1229 buffer.reserveCapacity(length);
1230 for (unsigned i = 0; i < length; i++) {
1231 uint16_t ch;
1232 readLittleEndian(ptr, end, ch);
1233 buffer.append(ch);
1234 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001235 str = String::adopt(buffer);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001236#endif
1237 return true;
1238 }
1239
oliver@apple.com86609602010-10-19 02:33:33 +00001240 bool readStringData(CachedStringRef& cachedString)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001241 {
1242 bool scratch;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001243 return readStringData(cachedString, scratch);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001244 }
1245
oliver@apple.com86609602010-10-19 02:33:33 +00001246 bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001247 {
1248 if (m_failed)
1249 return false;
1250 uint32_t length = 0;
1251 if (!read(length))
1252 return false;
1253 if (length == TerminatorTag) {
1254 wasTerminator = true;
1255 return false;
1256 }
1257 if (length == StringPoolTag) {
1258 unsigned index = 0;
1259 if (!readStringIndex(index)) {
1260 fail();
1261 return false;
1262 }
1263 if (index >= m_constantPool.size()) {
1264 fail();
1265 return false;
1266 }
oliver@apple.com86609602010-10-19 02:33:33 +00001267 cachedString = CachedStringRef(&m_constantPool, index);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001268 return true;
1269 }
benjamin@webkit.orgcff06e42012-08-30 21:23:51 +00001270 String str;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001271 if (!readString(m_ptr, m_end, str, length)) {
1272 fail();
1273 return false;
1274 }
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001275 m_constantPool.append(str);
oliver@apple.com86609602010-10-19 02:33:33 +00001276 cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001277 return true;
1278 }
1279
1280 SerializationTag readTag()
1281 {
1282 if (m_ptr >= m_end)
1283 return ErrorTag;
1284 return static_cast<SerializationTag>(*m_ptr++);
1285 }
1286
dslomov@google.coma3962422012-02-23 02:51:20 +00001287 bool readArrayBufferViewSubtag(ArrayBufferViewSubtag& tag)
1288 {
1289 if (m_ptr >= m_end)
1290 return false;
1291 tag = static_cast<ArrayBufferViewSubtag>(*m_ptr++);
1292 return true;
1293 }
1294
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001295 void putProperty(JSObject* object, unsigned index, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001296 {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001297 object->putDirectIndex(m_exec, index, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001298 }
1299
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001300 void putProperty(JSObject* object, const Identifier& property, JSValue value)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001301 {
fpizlo@apple.com904bab82012-09-25 05:27:33 +00001302 object->putDirectMayBeIndex(m_exec, property, value);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001303 }
1304
1305 bool readFile(RefPtr<File>& file)
1306 {
oliver@apple.com86609602010-10-19 02:33:33 +00001307 CachedStringRef path;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001308 if (!readStringData(path))
1309 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001310 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001311 if (!readStringData(url))
1312 return 0;
oliver@apple.com86609602010-10-19 02:33:33 +00001313 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001314 if (!readStringData(type))
1315 return 0;
commit-queue@webkit.orgfa990e92010-09-10 16:19:57 +00001316 if (m_isDOMGlobalObject)
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001317 file = File::create(path->string(), KURL(KURL(), url->string()), type->string());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001318 return true;
1319 }
1320
dslomov@google.coma3962422012-02-23 02:51:20 +00001321 bool readArrayBuffer(RefPtr<ArrayBuffer>& arrayBuffer)
1322 {
1323 uint32_t length;
1324 if (!read(length))
1325 return false;
1326 if (m_ptr + length > m_end)
1327 return false;
1328 arrayBuffer = ArrayBuffer::create(m_ptr, length);
1329 m_ptr += length;
1330 return true;
1331 }
1332
1333 bool readArrayBufferView(JSValue& arrayBufferView)
1334 {
1335 ArrayBufferViewSubtag arrayBufferViewSubtag;
1336 if (!readArrayBufferViewSubtag(arrayBufferViewSubtag))
1337 return false;
1338 uint32_t byteOffset;
1339 if (!read(byteOffset))
1340 return false;
1341 uint32_t byteLength;
1342 if (!read(byteLength))
1343 return false;
1344 JSObject* arrayBufferObj = asObject(readTerminal());
1345 if (!arrayBufferObj || !arrayBufferObj->inherits(&JSArrayBuffer::s_info))
1346 return false;
1347
1348 unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag);
1349 if (!elementSize)
1350 return false;
1351 unsigned length = byteLength / elementSize;
1352 if (length * elementSize != byteLength)
1353 return false;
1354
1355 RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj);
1356 switch (arrayBufferViewSubtag) {
1357 case DataViewTag:
1358 arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get());
1359 return true;
1360 case Int8ArrayTag:
1361 arrayBufferView = getJSValue(Int8Array::create(arrayBuffer, byteOffset, length).get());
1362 return true;
1363 case Uint8ArrayTag:
1364 arrayBufferView = getJSValue(Uint8Array::create(arrayBuffer, byteOffset, length).get());
1365 return true;
1366 case Uint8ClampedArrayTag:
1367 arrayBufferView = getJSValue(Uint8ClampedArray::create(arrayBuffer, byteOffset, length).get());
1368 return true;
1369 case Int16ArrayTag:
1370 arrayBufferView = getJSValue(Int16Array::create(arrayBuffer, byteOffset, length).get());
1371 return true;
1372 case Uint16ArrayTag:
1373 arrayBufferView = getJSValue(Uint16Array::create(arrayBuffer, byteOffset, length).get());
1374 return true;
1375 case Int32ArrayTag:
1376 arrayBufferView = getJSValue(Int32Array::create(arrayBuffer, byteOffset, length).get());
1377 return true;
1378 case Uint32ArrayTag:
1379 arrayBufferView = getJSValue(Uint32Array::create(arrayBuffer, byteOffset, length).get());
1380 return true;
1381 case Float32ArrayTag:
1382 arrayBufferView = getJSValue(Float32Array::create(arrayBuffer, byteOffset, length).get());
1383 return true;
1384 case Float64ArrayTag:
1385 arrayBufferView = getJSValue(Float64Array::create(arrayBuffer, byteOffset, length).get());
1386 return true;
1387 default:
1388 return false;
1389 }
1390 }
1391
1392 template<class T>
1393 JSValue getJSValue(T* nativeObj)
1394 {
oliver@apple.comffe14422012-04-05 22:33:19 +00001395 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj);
dslomov@google.coma3962422012-02-23 02:51:20 +00001396 }
1397
oliver@apple.com8128fe12010-09-06 21:29:06 +00001398 JSValue readTerminal()
1399 {
1400 SerializationTag tag = readTag();
1401 switch (tag) {
1402 case UndefinedTag:
1403 return jsUndefined();
1404 case NullTag:
1405 return jsNull();
1406 case IntTag: {
1407 int32_t i;
1408 if (!read(i))
1409 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001410 return jsNumber(i);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001411 }
1412 case ZeroTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001413 return jsNumber(0);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001414 case OneTag:
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001415 return jsNumber(1);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001416 case FalseTag:
1417 return jsBoolean(false);
1418 case TrueTag:
1419 return jsBoolean(true);
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001420 case FalseObjectTag: {
1421 BooleanObject* obj = BooleanObject::create(m_exec->globalData(), m_globalObject->booleanObjectStructure());
1422 obj->setInternalValue(m_exec->globalData(), jsBoolean(false));
1423 m_gcBuffer.append(obj);
1424 return obj;
1425 }
1426 case TrueObjectTag: {
1427 BooleanObject* obj = BooleanObject::create(m_exec->globalData(), m_globalObject->booleanObjectStructure());
1428 obj->setInternalValue(m_exec->globalData(), jsBoolean(true));
1429 m_gcBuffer.append(obj);
1430 return obj;
1431 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001432 case DoubleTag: {
1433 double d;
1434 if (!read(d))
1435 return JSValue();
oliver@apple.com5b67d9e2010-10-25 22:40:53 +00001436 return jsNumber(d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001437 }
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001438 case NumberObjectTag: {
1439 double d;
1440 if (!read(d))
1441 return JSValue();
1442 NumberObject* obj = constructNumber(m_exec, m_globalObject, jsNumber(d));
1443 m_gcBuffer.append(obj);
1444 return obj;
1445 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001446 case DateTag: {
1447 double d;
1448 if (!read(d))
1449 return JSValue();
oliver@apple.comfcacd3c2011-07-18 17:47:13 +00001450 return DateInstance::create(m_exec, m_globalObject->dateStructure(), d);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001451 }
1452 case FileTag: {
1453 RefPtr<File> file;
1454 if (!readFile(file))
1455 return JSValue();
1456 if (!m_isDOMGlobalObject)
1457 return jsNull();
oliver@apple.comffe14422012-04-05 22:33:19 +00001458 return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001459 }
1460 case FileListTag: {
1461 unsigned length = 0;
1462 if (!read(length))
1463 return JSValue();
1464 RefPtr<FileList> result = FileList::create();
1465 for (unsigned i = 0; i < length; i++) {
1466 RefPtr<File> file;
1467 if (!readFile(file))
1468 return JSValue();
1469 if (m_isDOMGlobalObject)
1470 result->append(file.get());
1471 }
1472 if (!m_isDOMGlobalObject)
1473 return jsNull();
dslomov@google.coma3962422012-02-23 02:51:20 +00001474 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001475 }
1476 case ImageDataTag: {
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001477 int32_t width;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001478 if (!read(width))
1479 return JSValue();
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001480 int32_t height;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001481 if (!read(height))
1482 return JSValue();
1483 uint32_t length;
1484 if (!read(length))
1485 return JSValue();
1486 if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1487 fail();
1488 return JSValue();
1489 }
1490 if (!m_isDOMGlobalObject) {
1491 m_ptr += length;
1492 return jsNull();
1493 }
reni@webkit.orgfa0c6682011-01-06 16:50:45 +00001494 RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
kbr@google.com1262e442012-04-24 03:43:31 +00001495 memcpy(result->data()->data(), m_ptr, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001496 m_ptr += length;
dslomov@google.coma3962422012-02-23 02:51:20 +00001497 return getJSValue(result.get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001498 }
1499 case BlobTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001500 CachedStringRef url;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001501 if (!readStringData(url))
1502 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00001503 CachedStringRef type;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001504 if (!readStringData(type))
1505 return JSValue();
1506 unsigned long long size = 0;
1507 if (!read(size))
1508 return JSValue();
1509 if (!m_isDOMGlobalObject)
1510 return jsNull();
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001511 return getJSValue(Blob::create(KURL(KURL(), url->string()), type->string(), size).get());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001512 }
1513 case StringTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001514 CachedStringRef cachedString;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001515 if (!readStringData(cachedString))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001516 return JSValue();
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001517 return cachedString->jsString(m_exec);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001518 }
1519 case EmptyStringTag:
1520 return jsEmptyString(&m_exec->globalData());
commit-queue@webkit.org8ef2f562012-08-23 19:08:54 +00001521 case StringObjectTag: {
1522 CachedStringRef cachedString;
1523 if (!readStringData(cachedString))
1524 return JSValue();
1525 StringObject* obj = constructString(m_exec, m_globalObject, cachedString->jsString(m_exec));
1526 m_gcBuffer.append(obj);
1527 return obj;
1528 }
1529 case EmptyStringObjectTag: {
1530 StringObject* obj = constructString(m_exec, m_globalObject, jsEmptyString(&m_exec->globalData()));
1531 m_gcBuffer.append(obj);
1532 return obj;
1533 }
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001534 case RegExpTag: {
oliver@apple.com86609602010-10-19 02:33:33 +00001535 CachedStringRef pattern;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001536 if (!readStringData(pattern))
1537 return JSValue();
oliver@apple.com86609602010-10-19 02:33:33 +00001538 CachedStringRef flags;
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001539 if (!readStringData(flags))
1540 return JSValue();
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001541 RegExpFlags reFlags = regExpFlags(flags->string());
barraclough@apple.com12812932011-03-09 23:04:27 +00001542 ASSERT(reFlags != InvalidFlags);
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001543 RegExp* regExp = RegExp::create(m_exec->globalData(), pattern->string(), reFlags);
oliver@apple.comfcacd3c2011-07-18 17:47:13 +00001544 return RegExpObject::create(m_exec, m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp);
commit-queue@webkit.org7648c242010-09-08 00:33:15 +00001545 }
oliver@apple.come8641552010-12-20 22:40:37 +00001546 case ObjectReferenceTag: {
1547 unsigned index = 0;
1548 if (!readConstantPoolIndex(m_gcBuffer, index)) {
1549 fail();
1550 return JSValue();
1551 }
1552 return m_gcBuffer.at(index);
1553 }
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001554 case MessagePortReferenceTag: {
1555 uint32_t index;
1556 bool indexSuccessfullyRead = read(index);
1557 if (!indexSuccessfullyRead || !m_messagePorts || index >= m_messagePorts->size()) {
1558 fail();
1559 return JSValue();
1560 }
dslomov@google.coma3962422012-02-23 02:51:20 +00001561 return getJSValue(m_messagePorts->at(index).get());
1562 }
1563 case ArrayBufferTag: {
1564 RefPtr<ArrayBuffer> arrayBuffer;
1565 if (!readArrayBuffer(arrayBuffer)) {
1566 fail();
1567 return JSValue();
1568 }
1569 JSValue result = getJSValue(arrayBuffer.get());
1570 m_gcBuffer.append(result);
1571 return result;
1572 }
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001573 case ArrayBufferTransferTag: {
1574 uint32_t index;
1575 bool indexSuccessfullyRead = read(index);
1576 if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
1577 fail();
1578 return JSValue();
1579 }
1580
1581 if (!m_arrayBuffers[index])
1582 m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
1583
1584 return getJSValue(m_arrayBuffers[index].get());
1585 }
dslomov@google.coma3962422012-02-23 02:51:20 +00001586 case ArrayBufferViewTag: {
1587 JSValue arrayBufferView;
1588 if (!readArrayBufferView(arrayBufferView)) {
1589 fail();
1590 return JSValue();
1591 }
1592 m_gcBuffer.append(arrayBufferView);
1593 return arrayBufferView;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001594 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001595 default:
1596 m_ptr--; // Push the tag back
1597 return JSValue();
1598 }
1599 }
1600
oliver@apple.com02a5f152010-01-24 22:54:18 +00001601 JSGlobalObject* m_globalObject;
1602 bool m_isDOMGlobalObject;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001603 const uint8_t* m_ptr;
1604 const uint8_t* m_end;
1605 unsigned m_version;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001606 Vector<CachedString> m_constantPool;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001607 MessagePortArray* m_messagePorts;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001608 ArrayBufferContentsArray* m_arrayBufferContents;
1609 ArrayBufferArray m_arrayBuffers;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001610};
1611
slewis@apple.comfc28de52011-04-12 21:50:04 +00001612DeserializationResult CloneDeserializer::deserialize()
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001613{
oliver@apple.com8128fe12010-09-06 21:29:06 +00001614 Vector<uint32_t, 16> indexStack;
1615 Vector<Identifier, 16> propertyNameStack;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001616 Vector<JSObject*, 32> outputObjectStack;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001617 Vector<WalkerState, 16> stateStack;
1618 WalkerState state = StateUnknown;
1619 JSValue outValue;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001620
oliver@apple.com8128fe12010-09-06 21:29:06 +00001621 unsigned tickCount = ticksUntilNextCheck();
1622 while (1) {
1623 switch (state) {
1624 arrayStartState:
1625 case ArrayStartState: {
1626 uint32_t length;
1627 if (!read(length)) {
1628 fail();
1629 goto error;
1630 }
fpizlo@apple.com75c91a72012-11-08 22:28:25 +00001631 JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001632 m_gcBuffer.append(outArray);
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001633 outputObjectStack.append(outArray);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001634 // fallthrough
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001635 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001636 arrayStartVisitMember:
1637 case ArrayStartVisitMember: {
1638 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +00001639 if (didTimeOut())
1640 return make_pair(JSValue(), InterruptedExecutionError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001641 tickCount = ticksUntilNextCheck();
1642 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001643
oliver@apple.com8128fe12010-09-06 21:29:06 +00001644 uint32_t index;
1645 if (!read(index)) {
1646 fail();
1647 goto error;
1648 }
1649 if (index == TerminatorTag) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001650 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001651 outValue = outArray;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001652 outputObjectStack.removeLast();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001653 break;
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001654 } else if (index == NonIndexPropertiesTag) {
1655 goto objectStartVisitMember;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001656 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001657
oliver@apple.com8128fe12010-09-06 21:29:06 +00001658 if (JSValue terminal = readTerminal()) {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001659 putProperty(outputObjectStack.last(), index, terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001660 goto arrayStartVisitMember;
1661 }
1662 if (m_failed)
1663 goto error;
1664 indexStack.append(index);
1665 stateStack.append(ArrayEndVisitMember);
1666 goto stateUnknown;
1667 }
1668 case ArrayEndVisitMember: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001669 JSObject* outArray = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001670 putProperty(outArray, indexStack.last(), outValue);
1671 indexStack.removeLast();
1672 goto arrayStartVisitMember;
1673 }
1674 objectStartState:
1675 case ObjectStartState: {
commit-queue@webkit.org811fb852013-01-07 19:03:44 +00001676 if (outputObjectStack.size() > maximumFilterRecursion)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001677 return make_pair(JSValue(), StackOverflowError);
ggaren@apple.comc862eac2013-01-29 05:48:01 +00001678 JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype());
oliver@apple.com8128fe12010-09-06 21:29:06 +00001679 m_gcBuffer.append(outObject);
1680 outputObjectStack.append(outObject);
1681 // fallthrough
1682 }
1683 objectStartVisitMember:
1684 case ObjectStartVisitMember: {
1685 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +00001686 if (didTimeOut())
1687 return make_pair(JSValue(), InterruptedExecutionError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001688 tickCount = ticksUntilNextCheck();
1689 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001690
oliver@apple.com86609602010-10-19 02:33:33 +00001691 CachedStringRef cachedString;
oliver@apple.com8128fe12010-09-06 21:29:06 +00001692 bool wasTerminator = false;
oliver@apple.comaf02ea32010-09-10 19:52:53 +00001693 if (!readStringData(cachedString, wasTerminator)) {
oliver@apple.com8128fe12010-09-06 21:29:06 +00001694 if (!wasTerminator)
1695 goto error;
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001696
oliver@apple.com8128fe12010-09-06 21:29:06 +00001697 JSObject* outObject = outputObjectStack.last();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001698 outValue = outObject;
1699 outputObjectStack.removeLast();
1700 break;
1701 }
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001702
oliver@apple.com8128fe12010-09-06 21:29:06 +00001703 if (JSValue terminal = readTerminal()) {
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001704 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->string()), terminal);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001705 goto objectStartVisitMember;
1706 }
1707 stateStack.append(ObjectEndVisitMember);
benjamin@webkit.orgc9b7a202012-09-08 05:46:29 +00001708 propertyNameStack.append(Identifier(m_exec, cachedString->string()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00001709 goto stateUnknown;
1710 }
1711 case ObjectEndVisitMember: {
1712 putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1713 propertyNameStack.removeLast();
1714 goto objectStartVisitMember;
1715 }
1716 stateUnknown:
1717 case StateUnknown:
1718 if (JSValue terminal = readTerminal()) {
1719 outValue = terminal;
1720 break;
1721 }
1722 SerializationTag tag = readTag();
1723 if (tag == ArrayTag)
1724 goto arrayStartState;
1725 if (tag == ObjectTag)
1726 goto objectStartState;
1727 goto error;
1728 }
1729 if (stateStack.isEmpty())
1730 break;
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001731
oliver@apple.com8128fe12010-09-06 21:29:06 +00001732 state = stateStack.last();
1733 stateStack.removeLast();
1734
1735 if (!--tickCount) {
slewis@apple.comfc28de52011-04-12 21:50:04 +00001736 if (didTimeOut())
1737 return make_pair(JSValue(), InterruptedExecutionError);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001738 tickCount = ticksUntilNextCheck();
1739 }
1740 }
1741 ASSERT(outValue);
1742 ASSERT(!m_failed);
slewis@apple.comfc28de52011-04-12 21:50:04 +00001743 return make_pair(outValue, SuccessfullyCompleted);
oliver@apple.com8128fe12010-09-06 21:29:06 +00001744error:
1745 fail();
slewis@apple.comfc28de52011-04-12 21:50:04 +00001746 return make_pair(JSValue(), ValidationError);
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001747}
1748
oliver@apple.com8128fe12010-09-06 21:29:06 +00001749
1750
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001751SerializedScriptValue::~SerializedScriptValue()
1752{
1753}
1754
commit-queue@webkit.org7632ff22012-12-17 23:59:47 +00001755SerializedScriptValue::SerializedScriptValue(const Vector<uint8_t>& buffer)
1756 : m_data(buffer)
1757{
1758}
1759
oliver@apple.com8128fe12010-09-06 21:29:06 +00001760SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1761{
1762 m_data.swap(buffer);
1763}
1764
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001765SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs)
1766{
1767 m_data.swap(buffer);
1768 m_blobURLs.swap(blobURLs);
1769}
1770
1771SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray)
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001772 : m_arrayBufferContentsArray(arrayBufferContentsArray)
1773{
1774 m_data.swap(buffer);
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001775 m_blobURLs.swap(blobURLs);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001776}
1777
1778PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
1779 ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
1780{
1781 for (size_t i = 0; i < arrayBuffers.size(); i++) {
1782 if (arrayBuffers[i]->isNeutered()) {
1783 code = ValidationError;
1784 return nullptr;
1785 }
1786 }
1787
1788 OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
1789
1790 HashSet<WTF::ArrayBuffer*> visited;
1791 for (size_t i = 0; i < arrayBuffers.size(); i++) {
1792 Vector<RefPtr<ArrayBufferView> > neuteredViews;
1793
1794 if (visited.contains(arrayBuffers[i].get()))
1795 continue;
1796 visited.add(arrayBuffers[i].get());
1797
1798 bool result = arrayBuffers[i]->transfer(contents->at(i), neuteredViews);
1799 if (!result) {
1800 code = ValidationError;
1801 return nullptr;
1802 }
1803 }
1804 return contents.release();
1805}
1806
1807
1808PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value,
1809 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1810 SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001811{
1812 Vector<uint8_t> buffer;
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001813 Vector<String> blobURLs;
1814 SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, blobURLs, buffer);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001815
1816 OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
1817
1818 if (arrayBuffers && serializationDidCompleteSuccessfully(code))
1819 arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, code);
1820
slewis@apple.comd0a103d2011-04-13 00:13:11 +00001821 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001822 maybeThrowExceptionIfSerializationFailed(exec, code);
1823
1824 if (!serializationDidCompleteSuccessfully(code))
oliver@apple.com8128fe12010-09-06 21:29:06 +00001825 return 0;
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001826
jsbell@chromium.orgdfafc062012-03-16 19:26:00 +00001827 return adoptRef(new SerializedScriptValue(buffer, blobURLs, arrayBufferContentsArray.release()));
oliver@apple.com8128fe12010-09-06 21:29:06 +00001828}
1829
1830PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1831{
1832 Vector<uint8_t> buffer;
1833 return adoptRef(new SerializedScriptValue(buffer));
1834}
1835
tony@chromium.org6b09aa62011-06-24 06:43:34 +00001836PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001837{
1838 Vector<uint8_t> buffer;
1839 if (!CloneSerializer::serialize(string, buffer))
1840 return 0;
1841 return adoptRef(new SerializedScriptValue(buffer));
1842}
1843
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001844#if ENABLE(INDEXED_DATABASE)
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001845PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::ExecState* exec, JSC::JSValue value)
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001846{
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001847 return SerializedScriptValue::create(exec, value, 0, 0);
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001848}
1849
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001850PassRefPtr<SerializedScriptValue> SerializedScriptValue::numberValue(double value)
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001851{
charles.wei@torchmobile.com.cnfc41ada2012-06-06 05:51:34 +00001852 Vector<uint8_t> buffer;
1853 CloneSerializer::serializeNumber(value, buffer);
1854 return adoptRef(new SerializedScriptValue(buffer));
1855}
1856
1857JSValue SerializedScriptValue::deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
1858{
1859 return deserialize(exec, globalObject, 0);
commit-queue@webkit.orgc3ede632012-03-13 05:38:59 +00001860}
1861#endif
1862
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001863PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001864 MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
1865 JSValueRef* exception)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001866{
1867 ExecState* exec = toJS(originContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00001868 APIEntryShim entryShim(exec);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001869 JSValue value = toJS(exec, apiValue);
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001870 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts, arrayBuffers);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001871 if (exec->hadException()) {
1872 if (exception)
1873 *exception = toRef(exec, exec->exception());
1874 exec->clearException();
1875 return 0;
1876 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001877 ASSERT(serializedValue);
levin@chromium.org550ac082011-08-22 23:30:10 +00001878 return serializedValue.release();
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001879}
1880
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001881PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
1882 JSValueRef* exception)
1883{
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001884 return create(originContext, apiValue, 0, 0, exception);
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001885}
1886
oliver@apple.com8128fe12010-09-06 21:29:06 +00001887String SerializedScriptValue::toString()
commit-queue@webkit.org72354062010-09-02 01:00:51 +00001888{
oliver@apple.com8128fe12010-09-06 21:29:06 +00001889 return CloneDeserializer::deserializeString(m_data);
1890}
1891
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001892JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
dslomov@google.comd60d08e2011-10-31 21:07:22 +00001893 MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
oliver@apple.com8128fe12010-09-06 21:29:06 +00001894{
dslomov@google.come2c8d4b2012-02-29 06:40:35 +00001895 DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
1896 m_arrayBufferContentsArray.get(), m_data);
slewis@apple.comd0a103d2011-04-13 00:13:11 +00001897 if (throwExceptions == Throwing)
slewis@apple.comfc28de52011-04-12 21:50:04 +00001898 maybeThrowExceptionIfSerializationFailed(exec, result.second);
1899 return result.first;
commit-queue@webkit.org72354062010-09-02 01:00:51 +00001900}
1901
vsevik@chromium.org9fa045d2012-02-15 12:19:12 +00001902#if ENABLE(INSPECTOR)
1903ScriptValue SerializedScriptValue::deserializeForInspector(ScriptState* scriptState)
1904{
1905 JSValue value = deserialize(scriptState, scriptState->lexicalGlobalObject(), 0);
1906 return ScriptValue(scriptState->globalData(), value);
1907}
1908#endif
1909
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001910JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception, MessagePortArray* messagePorts)
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001911{
1912 ExecState* exec = toJS(destinationContext);
timothy@apple.comf5a07a92011-03-03 18:28:29 +00001913 APIEntryShim entryShim(exec);
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001914 JSValue value = deserialize(exec, exec->lexicalGlobalObject(), messagePorts);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001915 if (exec->hadException()) {
1916 if (exception)
1917 *exception = toRef(exec, exec->exception());
1918 exec->clearException();
1919 return 0;
1920 }
oliver@apple.com8128fe12010-09-06 21:29:06 +00001921 ASSERT(value);
oliver@apple.coma8ab0ca2009-11-20 21:32:03 +00001922 return toRef(exec, value);
1923}
1924
dslomov@google.com9386a8b2011-10-16 19:19:42 +00001925
1926JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
1927{
1928 return deserialize(destinationContext, exception, 0);
1929}
1930
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00001931PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
oliver@apple.com8128fe12010-09-06 21:29:06 +00001932{
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00001933 return SerializedScriptValue::create();
oliver@apple.com8128fe12010-09-06 21:29:06 +00001934}
1935
commit-queue@webkit.org2c08be82011-11-03 19:41:31 +00001936PassRefPtr<SerializedScriptValue> SerializedScriptValue::undefinedValue()
1937{
1938 Vector<uint8_t> buffer;
1939 CloneSerializer::serializeUndefined(buffer);
1940 return adoptRef(new SerializedScriptValue(buffer));
1941}
1942
1943PassRefPtr<SerializedScriptValue> SerializedScriptValue::booleanValue(bool value)
1944{
1945 Vector<uint8_t> buffer;
1946 CloneSerializer::serializeBoolean(value, buffer);
1947 return adoptRef(new SerializedScriptValue(buffer));
1948}
1949
slewis@apple.comfc28de52011-04-12 21:50:04 +00001950void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
1951{
1952 if (code == SuccessfullyCompleted)
1953 return;
1954
1955 switch (code) {
1956 case StackOverflowError:
1957 throwError(exec, createStackOverflowError(exec));
1958 break;
1959 case InterruptedExecutionError:
1960 throwError(exec, createInterruptedExecutionException(&exec->globalData()));
1961 break;
1962 case ValidationError:
1963 throwError(exec, createTypeError(exec, "Unable to deserialize data."));
1964 break;
commit-queue@webkit.org597f0812012-08-20 21:12:55 +00001965 case DataCloneError:
1966 setDOMException(exec, DATA_CLONE_ERR);
1967 break;
slewis@apple.comfc28de52011-04-12 21:50:04 +00001968 case ExistingExceptionError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00001969 break;
1970 case UnspecifiedError:
slewis@apple.comfc28de52011-04-12 21:50:04 +00001971 break;
1972 default:
1973 ASSERT_NOT_REACHED();
1974 }
1975}
1976
1977bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
1978{
1979 return (code == SuccessfullyCompleted);
1980}
1981
jsbell@chromium.org43d46eb2012-12-07 17:52:36 +00001982uint32_t SerializedScriptValue::wireFormatVersion()
1983{
1984 return CurrentVersion;
1985}
1986
oliver@apple.com0ef2c5b2009-10-07 02:06:03 +00001987}