• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
28 #include "SerializedScriptValue.h"
29 
30 #include "Blob.h"
31 #include "File.h"
32 #include "FileList.h"
33 #include "ImageData.h"
34 #include "JSBlob.h"
35 #include "JSDOMGlobalObject.h"
36 #include "JSFile.h"
37 #include "JSFileList.h"
38 #include "JSImageData.h"
39 #include "JSNavigator.h"
40 #include "SharedBuffer.h"
41 #include <limits>
42 #include <JavaScriptCore/APICast.h>
43 #include <JavaScriptCore/APIShims.h>
44 #include <runtime/DateInstance.h>
45 #include <runtime/Error.h>
46 #include <runtime/ExceptionHelpers.h>
47 #include <runtime/PropertyNameArray.h>
48 #include <runtime/RegExp.h>
49 #include <runtime/RegExpObject.h>
50 #include <wtf/ByteArray.h>
51 #include <wtf/HashTraits.h>
52 #include <wtf/Vector.h>
53 
54 using namespace JSC;
55 using namespace std;
56 
57 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) || CPU(NEEDS_ALIGNED_ACCESS)
58 #define ASSUME_LITTLE_ENDIAN 0
59 #else
60 #define ASSUME_LITTLE_ENDIAN 1
61 #endif
62 
63 namespace WebCore {
64 
65 static const unsigned maximumFilterRecursion = 40000;
66 
67 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
68     ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
69 
70 // These can't be reordered, and any new types must be added to the end of the list
71 enum SerializationTag {
72     ArrayTag = 1,
73     ObjectTag = 2,
74     UndefinedTag = 3,
75     NullTag = 4,
76     IntTag = 5,
77     ZeroTag = 6,
78     OneTag = 7,
79     FalseTag = 8,
80     TrueTag = 9,
81     DoubleTag = 10,
82     DateTag = 11,
83     FileTag = 12,
84     FileListTag = 13,
85     ImageDataTag = 14,
86     BlobTag = 15,
87     StringTag = 16,
88     EmptyStringTag = 17,
89     RegExpTag = 18,
90     ObjectReferenceTag = 19,
91     ErrorTag = 255
92 };
93 
94 /* CurrentVersion tracks the serialization version so that persistant stores
95  * are able to correctly bail out in the case of encountering newer formats.
96  *
97  * Initial version was 1.
98  * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
99  */
100 static const unsigned int CurrentVersion = 2;
101 static const unsigned int TerminatorTag = 0xFFFFFFFF;
102 static const unsigned int StringPoolTag = 0xFFFFFFFE;
103 
104 /*
105  * Object serialization is performed according to the following grammar, all tags
106  * are recorded as a single uint8_t.
107  *
108  * IndexType (used for the object pool and StringData's constant pool) is the
109  * minimum sized unsigned integer type required to represent the maximum index
110  * in the constant pool.
111  *
112  * SerializedValue :- <CurrentVersion:uint32_t> Value
113  * Value :- Array | Object | Terminal
114  *
115  * Array :-
116  *     ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
117  *
118  * Object :-
119  *     ObjectTag (<name:StringData><value:Value>)* TerminatorTag
120  *
121  * Terminal :-
122  *      UndefinedTag
123  *    | NullTag
124  *    | IntTag <value:int32_t>
125  *    | ZeroTag
126  *    | OneTag
127  *    | DoubleTag <value:double>
128  *    | DateTag <value:double>
129  *    | String
130  *    | EmptyStringTag
131  *    | File
132  *    | FileList
133  *    | ImageData
134  *    | Blob
135  *    | ObjectReferenceTag <opIndex:IndexType>
136  *
137  * String :-
138  *      EmptyStringTag
139  *      StringTag StringData
140  *
141  * StringData :-
142  *      StringPoolTag <cpIndex:IndexType>
143  *      (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
144  *
145  * File :-
146  *    FileTag FileData
147  *
148  * FileData :-
149  *    <path:StringData> <url:StringData> <type:StringData>
150  *
151  * FileList :-
152  *    FileListTag <length:uint32_t>(<file:FileData>){length}
153  *
154  * ImageData :-
155  *    ImageDataTag <width:int32_t><height:int32_t><length:uint32_t><data:uint8_t{length}>
156  *
157  * Blob :-
158  *    BlobTag <url:StringData><type:StringData><size:long long>
159  *
160  * RegExp :-
161  *    RegExpTag <pattern:StringData><flags:StringData>
162  */
163 
164 typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
165 
166 class CloneBase {
167 protected:
CloneBase(ExecState * exec)168     CloneBase(ExecState* exec)
169         : m_exec(exec)
170         , m_failed(false)
171         , m_timeoutChecker(exec->globalData().timeoutChecker)
172     {
173     }
174 
shouldTerminate()175     bool shouldTerminate()
176     {
177         return m_exec->hadException();
178     }
179 
ticksUntilNextCheck()180     unsigned ticksUntilNextCheck()
181     {
182         return m_timeoutChecker.ticksUntilNextCheck();
183     }
184 
didTimeOut()185     bool didTimeOut()
186     {
187         return m_timeoutChecker.didTimeOut(m_exec);
188     }
189 
throwStackOverflow()190     void throwStackOverflow()
191     {
192         throwError(m_exec, createStackOverflowError(m_exec));
193     }
194 
throwInterruptedException()195     void throwInterruptedException()
196     {
197         throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
198     }
199 
fail()200     void fail()
201     {
202         ASSERT_NOT_REACHED();
203         m_failed = true;
204     }
205 
206     ExecState* m_exec;
207     bool m_failed;
208     TimeoutChecker m_timeoutChecker;
209     MarkedArgumentBuffer m_gcBuffer;
210 };
211 
212 #if ASSUME_LITTLE_ENDIAN
writeLittleEndian(Vector<uint8_t> & buffer,T value)213 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
214 {
215     buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
216 }
217 #else
writeLittleEndian(Vector<uint8_t> & buffer,T value)218 template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
219 {
220     for (unsigned i = 0; i < sizeof(T); i++) {
221         buffer.append(value & 0xFF);
222         value >>= 8;
223     }
224 }
225 #endif
226 
writeLittleEndian(Vector<uint8_t> & buffer,uint8_t value)227 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
228 {
229     buffer.append(value);
230 }
231 
writeLittleEndian(Vector<uint8_t> & buffer,const T * values,uint32_t length)232 template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
233 {
234     if (length > numeric_limits<uint32_t>::max() / sizeof(T))
235         return false;
236 
237 #if ASSUME_LITTLE_ENDIAN
238     buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
239 #else
240     for (unsigned i = 0; i < length; i++) {
241         T value = values[i];
242         for (unsigned j = 0; j < sizeof(T); j++) {
243             buffer.append(static_cast<uint8_t>(value & 0xFF));
244             value >>= 8;
245         }
246     }
247 #endif
248     return true;
249 }
250 
251 class CloneSerializer : CloneBase {
252 public:
serialize(ExecState * exec,JSValue value,Vector<uint8_t> & out)253     static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out)
254     {
255         CloneSerializer serializer(exec, out);
256         return serializer.serialize(value);
257     }
258 
serialize(String s,Vector<uint8_t> & out)259     static bool serialize(String s, Vector<uint8_t>& out)
260     {
261         writeLittleEndian(out, CurrentVersion);
262         if (s.isEmpty()) {
263             writeLittleEndian<uint8_t>(out, EmptyStringTag);
264             return true;
265         }
266         writeLittleEndian<uint8_t>(out, StringTag);
267         writeLittleEndian(out, s.length());
268         return writeLittleEndian(out, s.impl()->characters(), s.length());
269     }
270 
271 private:
CloneSerializer(ExecState * exec,Vector<uint8_t> & out)272     CloneSerializer(ExecState* exec, Vector<uint8_t>& out)
273         : CloneBase(exec)
274         , m_buffer(out)
275         , m_emptyIdentifier(exec, UString("", 0))
276     {
277         write(CurrentVersion);
278     }
279 
280     SerializationReturnCode serialize(JSValue in);
281 
isArray(JSValue value)282     bool isArray(JSValue value)
283     {
284         if (!value.isObject())
285             return false;
286         JSObject* object = asObject(value);
287         return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::s_info);
288     }
289 
startObjectInternal(JSObject * object)290     bool startObjectInternal(JSObject* object)
291     {
292         // Record object for graph reconstruction
293         pair<ObjectPool::iterator, bool> iter = m_objectPool.add(object, m_objectPool.size());
294 
295         // Handle duplicate references
296         if (!iter.second) {
297             write(ObjectReferenceTag);
298             ASSERT(static_cast<int32_t>(iter.first->second) < m_objectPool.size());
299             writeObjectIndex(iter.first->second);
300             return false;
301         }
302 
303         m_gcBuffer.append(object);
304         return true;
305     }
306 
startObject(JSObject * object)307     bool startObject(JSObject* object)
308     {
309         if (!startObjectInternal(object))
310             return false;
311         write(ObjectTag);
312         return true;
313     }
314 
startArray(JSArray * array)315     bool startArray(JSArray* array)
316     {
317         if (!startObjectInternal(array))
318             return false;
319 
320         unsigned length = array->length();
321         write(ArrayTag);
322         write(length);
323         return true;
324     }
325 
endObject()326     void endObject()
327     {
328         write(TerminatorTag);
329     }
330 
getSparseIndex(JSArray * array,unsigned propertyName,bool & hasIndex)331     JSValue getSparseIndex(JSArray* array, unsigned propertyName, bool& hasIndex)
332     {
333         PropertySlot slot(array);
334         if (isJSArray(&m_exec->globalData(), array)) {
335             if (array->JSArray::getOwnPropertySlot(m_exec, propertyName, slot)) {
336                 hasIndex = true;
337                 return slot.getValue(m_exec, propertyName);
338             }
339         } else if (array->getOwnPropertySlot(m_exec, propertyName, slot)) {
340             hasIndex = true;
341             return slot.getValue(m_exec, propertyName);
342         }
343         hasIndex = false;
344         return jsNull();
345     }
346 
getProperty(JSObject * object,const Identifier & propertyName)347     JSValue getProperty(JSObject* object, const Identifier& propertyName)
348     {
349         PropertySlot slot(object);
350         if (object->getOwnPropertySlot(m_exec, propertyName, slot))
351             return slot.getValue(m_exec, propertyName);
352         return JSValue();
353     }
354 
dumpImmediate(JSValue value)355     void dumpImmediate(JSValue value)
356     {
357         if (value.isNull())
358             write(NullTag);
359         else if (value.isUndefined())
360             write(UndefinedTag);
361         else if (value.isNumber()) {
362             if (value.isInt32()) {
363                 if (!value.asInt32())
364                     write(ZeroTag);
365                 else if (value.asInt32() == 1)
366                     write(OneTag);
367                 else {
368                     write(IntTag);
369                     write(static_cast<uint32_t>(value.asInt32()));
370                 }
371             } else {
372                 write(DoubleTag);
373                 write(value.asDouble());
374             }
375         } else if (value.isBoolean()) {
376             if (value.isTrue())
377                 write(TrueTag);
378             else
379                 write(FalseTag);
380         }
381     }
382 
dumpString(UString str)383     void dumpString(UString str)
384     {
385         if (str.isEmpty())
386             write(EmptyStringTag);
387         else {
388             write(StringTag);
389             write(str);
390         }
391     }
392 
dumpIfTerminal(JSValue value)393     bool dumpIfTerminal(JSValue value)
394     {
395         if (!value.isCell()) {
396             dumpImmediate(value);
397             return true;
398         }
399 
400         if (value.isString()) {
401             UString str = asString(value)->value(m_exec);
402             dumpString(str);
403             return true;
404         }
405 
406         if (value.isNumber()) {
407             write(DoubleTag);
408             write(value.uncheckedGetNumber());
409             return true;
410         }
411 
412         if (value.isObject() && asObject(value)->inherits(&DateInstance::s_info)) {
413             write(DateTag);
414             write(asDateInstance(value)->internalNumber());
415             return true;
416         }
417 
418         if (isArray(value))
419             return false;
420 
421         // Object cannot be serialized because the act of walking the object creates new objects
422         if (value.isObject() && asObject(value)->inherits(&JSNavigator::s_info)) {
423             fail();
424             write(NullTag);
425             return true;
426         }
427 
428         if (value.isObject()) {
429             JSObject* obj = asObject(value);
430             if (obj->inherits(&JSFile::s_info)) {
431                 write(FileTag);
432                 write(toFile(obj));
433                 return true;
434             }
435             if (obj->inherits(&JSFileList::s_info)) {
436                 FileList* list = toFileList(obj);
437                 write(FileListTag);
438                 unsigned length = list->length();
439                 write(length);
440                 for (unsigned i = 0; i < length; i++)
441                     write(list->item(i));
442                 return true;
443             }
444             if (obj->inherits(&JSBlob::s_info)) {
445                 write(BlobTag);
446                 Blob* blob = toBlob(obj);
447                 write(blob->url());
448                 write(blob->type());
449                 write(blob->size());
450                 return true;
451             }
452             if (obj->inherits(&JSImageData::s_info)) {
453                 ImageData* data = toImageData(obj);
454                 write(ImageDataTag);
455                 write(data->width());
456                 write(data->height());
457                 write(data->data()->length());
458                 write(data->data()->data()->data(), data->data()->length());
459                 return true;
460             }
461             if (obj->inherits(&RegExpObject::s_info)) {
462                 RegExpObject* regExp = asRegExpObject(obj);
463                 char flags[3];
464                 int flagCount = 0;
465                 if (regExp->regExp()->global())
466                     flags[flagCount++] = 'g';
467                 if (regExp->regExp()->ignoreCase())
468                     flags[flagCount++] = 'i';
469                 if (regExp->regExp()->multiline())
470                     flags[flagCount++] = 'm';
471                 write(RegExpTag);
472                 write(regExp->regExp()->pattern());
473                 write(UString(flags, flagCount));
474                 return true;
475             }
476 
477             CallData unusedData;
478             if (getCallData(value, unusedData) == CallTypeNone)
479                 return false;
480         }
481         // Any other types are expected to serialize as null.
482         write(NullTag);
483         return true;
484     }
485 
write(SerializationTag tag)486     void write(SerializationTag tag)
487     {
488         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
489     }
490 
write(uint8_t c)491     void write(uint8_t c)
492     {
493         writeLittleEndian(m_buffer, c);
494     }
495 
write(uint32_t i)496     void write(uint32_t i)
497     {
498         writeLittleEndian(m_buffer, i);
499     }
500 
write(double d)501     void write(double d)
502     {
503         union {
504             double d;
505             int64_t i;
506         } u;
507         u.d = d;
508         writeLittleEndian(m_buffer, u.i);
509     }
510 
write(int32_t i)511     void write(int32_t i)
512     {
513         writeLittleEndian(m_buffer, i);
514     }
515 
write(unsigned long long i)516     void write(unsigned long long i)
517     {
518         writeLittleEndian(m_buffer, i);
519     }
520 
write(uint16_t ch)521     void write(uint16_t ch)
522     {
523         writeLittleEndian(m_buffer, ch);
524     }
525 
writeStringIndex(unsigned i)526     void writeStringIndex(unsigned i)
527     {
528         writeConstantPoolIndex(m_constantPool, i);
529     }
530 
writeObjectIndex(unsigned i)531     void writeObjectIndex(unsigned i)
532     {
533         writeConstantPoolIndex(m_objectPool, i);
534     }
535 
writeConstantPoolIndex(const T & constantPool,unsigned i)536     template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
537     {
538         ASSERT(static_cast<int32_t>(i) < constantPool.size());
539         if (constantPool.size() <= 0xFF)
540             write(static_cast<uint8_t>(i));
541         else if (constantPool.size() <= 0xFFFF)
542             write(static_cast<uint16_t>(i));
543         else
544             write(static_cast<uint32_t>(i));
545     }
546 
write(const Identifier & ident)547     void write(const Identifier& ident)
548     {
549         UString str = ident.ustring();
550         pair<StringConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
551         if (!iter.second) {
552             write(StringPoolTag);
553             writeStringIndex(iter.first->second);
554             return;
555         }
556 
557         // This condition is unlikely to happen as they would imply an ~8gb
558         // string but we should guard against it anyway
559         if (str.length() >= StringPoolTag) {
560             fail();
561             return;
562         }
563 
564         // Guard against overflow
565         if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
566             fail();
567             return;
568         }
569 
570         writeLittleEndian<uint32_t>(m_buffer, str.length());
571         if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.characters()), str.length()))
572             fail();
573     }
574 
write(const UString & str)575     void write(const UString& str)
576     {
577         if (str.isNull())
578             write(m_emptyIdentifier);
579         else
580             write(Identifier(m_exec, str));
581     }
582 
write(const String & str)583     void write(const String& str)
584     {
585         if (str.isEmpty())
586             write(m_emptyIdentifier);
587         else
588             write(Identifier(m_exec, str.impl()));
589     }
590 
write(const File * file)591     void write(const File* file)
592     {
593         write(file->path());
594         write(file->url());
595         write(file->type());
596     }
597 
write(const uint8_t * data,unsigned length)598     void write(const uint8_t* data, unsigned length)
599     {
600         m_buffer.append(data, length);
601     }
602 
603     Vector<uint8_t>& m_buffer;
604     typedef HashMap<JSObject*, uint32_t> ObjectPool;
605     ObjectPool m_objectPool;
606     typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
607     StringConstantPool m_constantPool;
608     Identifier m_emptyIdentifier;
609 };
610 
serialize(JSValue in)611 SerializationReturnCode CloneSerializer::serialize(JSValue in)
612 {
613     Vector<uint32_t, 16> indexStack;
614     Vector<uint32_t, 16> lengthStack;
615     Vector<PropertyNameArray, 16> propertyStack;
616     Vector<JSObject*, 16> inputObjectStack;
617     Vector<JSArray*, 16> inputArrayStack;
618     Vector<WalkerState, 16> stateStack;
619     WalkerState state = StateUnknown;
620     JSValue inValue = in;
621     unsigned tickCount = ticksUntilNextCheck();
622     while (1) {
623         switch (state) {
624             arrayStartState:
625             case ArrayStartState: {
626                 ASSERT(isArray(inValue));
627                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion)
628                     return StackOverflowError;
629 
630                 JSArray* inArray = asArray(inValue);
631                 unsigned length = inArray->length();
632                 if (!startArray(inArray))
633                     break;
634                 inputArrayStack.append(inArray);
635                 indexStack.append(0);
636                 lengthStack.append(length);
637                 // fallthrough
638             }
639             arrayStartVisitMember:
640             case ArrayStartVisitMember: {
641                 if (!--tickCount) {
642                     if (didTimeOut())
643                         return InterruptedExecutionError;
644                     tickCount = ticksUntilNextCheck();
645                 }
646 
647                 JSArray* array = inputArrayStack.last();
648                 uint32_t index = indexStack.last();
649                 if (index == lengthStack.last()) {
650                     endObject();
651                     inputArrayStack.removeLast();
652                     indexStack.removeLast();
653                     lengthStack.removeLast();
654                     break;
655                 }
656                 if (array->canGetIndex(index))
657                     inValue = array->getIndex(index);
658                 else {
659                     bool hasIndex = false;
660                     inValue = getSparseIndex(array, index, hasIndex);
661                     if (!hasIndex) {
662                         indexStack.last()++;
663                         goto arrayStartVisitMember;
664                     }
665                 }
666 
667                 write(index);
668                 if (dumpIfTerminal(inValue)) {
669                     indexStack.last()++;
670                     goto arrayStartVisitMember;
671                 }
672                 stateStack.append(ArrayEndVisitMember);
673                 goto stateUnknown;
674             }
675             case ArrayEndVisitMember: {
676                 indexStack.last()++;
677                 goto arrayStartVisitMember;
678             }
679             objectStartState:
680             case ObjectStartState: {
681                 ASSERT(inValue.isObject());
682                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion)
683                     return StackOverflowError;
684                 JSObject* inObject = asObject(inValue);
685                 if (!startObject(inObject))
686                     break;
687                 inputObjectStack.append(inObject);
688                 indexStack.append(0);
689                 propertyStack.append(PropertyNameArray(m_exec));
690                 inObject->getOwnPropertyNames(m_exec, propertyStack.last());
691                 // fallthrough
692             }
693             objectStartVisitMember:
694             case ObjectStartVisitMember: {
695                 if (!--tickCount) {
696                     if (didTimeOut())
697                         return InterruptedExecutionError;
698                     tickCount = ticksUntilNextCheck();
699                 }
700 
701                 JSObject* object = inputObjectStack.last();
702                 uint32_t index = indexStack.last();
703                 PropertyNameArray& properties = propertyStack.last();
704                 if (index == properties.size()) {
705                     endObject();
706                     inputObjectStack.removeLast();
707                     indexStack.removeLast();
708                     propertyStack.removeLast();
709                     break;
710                 }
711                 inValue = getProperty(object, properties[index]);
712                 if (shouldTerminate())
713                     return ExistingExceptionError;
714 
715                 if (!inValue) {
716                     // Property was removed during serialisation
717                     indexStack.last()++;
718                     goto objectStartVisitMember;
719                 }
720                 write(properties[index]);
721 
722                 if (shouldTerminate())
723                     return ExistingExceptionError;
724 
725                 if (!dumpIfTerminal(inValue)) {
726                     stateStack.append(ObjectEndVisitMember);
727                     goto stateUnknown;
728                 }
729                 // fallthrough
730             }
731             case ObjectEndVisitMember: {
732                 if (shouldTerminate())
733                     return ExistingExceptionError;
734 
735                 indexStack.last()++;
736                 goto objectStartVisitMember;
737             }
738             stateUnknown:
739             case StateUnknown:
740                 if (dumpIfTerminal(inValue))
741                     break;
742 
743                 if (isArray(inValue))
744                     goto arrayStartState;
745                 goto objectStartState;
746         }
747         if (stateStack.isEmpty())
748             break;
749 
750         state = stateStack.last();
751         stateStack.removeLast();
752 
753         if (!--tickCount) {
754             if (didTimeOut())
755                 return InterruptedExecutionError;
756             tickCount = ticksUntilNextCheck();
757         }
758     }
759     if (m_failed)
760         return UnspecifiedError;
761 
762     return SuccessfullyCompleted;
763 }
764 
765 class CloneDeserializer : CloneBase {
766 public:
deserializeString(const Vector<uint8_t> & buffer)767     static String deserializeString(const Vector<uint8_t>& buffer)
768     {
769         const uint8_t* ptr = buffer.begin();
770         const uint8_t* end = buffer.end();
771         uint32_t version;
772         if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
773             return String();
774         uint8_t tag;
775         if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
776             return String();
777         uint32_t length;
778         if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
779             return String();
780         UString str;
781         if (!readString(ptr, end, str, length))
782             return String();
783         return String(str.impl());
784     }
785 
deserialize(ExecState * exec,JSGlobalObject * globalObject,const Vector<uint8_t> & buffer)786     static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
787     {
788         if (!buffer.size())
789             return make_pair(jsNull(), UnspecifiedError);
790         CloneDeserializer deserializer(exec, globalObject, buffer);
791         if (!deserializer.isValid())
792             return make_pair(JSValue(), ValidationError);
793         return deserializer.deserialize();
794     }
795 
796 private:
797     struct CachedString {
CachedStringWebCore::CloneDeserializer::CachedString798         CachedString(const UString& string)
799             : m_string(string)
800         {
801         }
802 
jsStringWebCore::CloneDeserializer::CachedString803         JSValue jsString(ExecState* exec)
804         {
805             if (!m_jsString)
806                 m_jsString = JSC::jsString(exec, m_string);
807             return m_jsString;
808         }
ustringWebCore::CloneDeserializer::CachedString809         const UString& ustring() { return m_string; }
810 
811     private:
812         UString m_string;
813         JSValue m_jsString;
814     };
815 
816     struct CachedStringRef {
CachedStringRefWebCore::CloneDeserializer::CachedStringRef817         CachedStringRef()
818             : m_base(0)
819             , m_index(0)
820         {
821         }
CachedStringRefWebCore::CloneDeserializer::CachedStringRef822         CachedStringRef(Vector<CachedString>* base, size_t index)
823             : m_base(base)
824             , m_index(index)
825         {
826         }
827 
operator ->WebCore::CloneDeserializer::CachedStringRef828         CachedString* operator->() { ASSERT(m_base); return &m_base->at(m_index); }
829 
830     private:
831         Vector<CachedString>* m_base;
832         size_t m_index;
833     };
834 
CloneDeserializer(ExecState * exec,JSGlobalObject * globalObject,const Vector<uint8_t> & buffer)835     CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
836         : CloneBase(exec)
837         , m_globalObject(globalObject)
838         , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
839         , m_ptr(buffer.data())
840         , m_end(buffer.data() + buffer.size())
841         , m_version(0xFFFFFFFF)
842     {
843         if (!read(m_version))
844             m_version = 0xFFFFFFFF;
845     }
846 
847     DeserializationResult deserialize();
848 
throwValidationError()849     void throwValidationError()
850     {
851         throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
852     }
853 
isValid() const854     bool isValid() const { return m_version <= CurrentVersion; }
855 
readLittleEndian(T & value)856     template <typename T> bool readLittleEndian(T& value)
857     {
858         if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
859             fail();
860             return false;
861         }
862         return true;
863     }
864 #if ASSUME_LITTLE_ENDIAN
readLittleEndian(const uint8_t * & ptr,const uint8_t * end,T & value)865     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
866     {
867         if (ptr > end - sizeof(value))
868             return false;
869 
870         if (sizeof(T) == 1)
871             value = *ptr++;
872         else {
873             value = *reinterpret_cast<const T*>(ptr);
874             ptr += sizeof(T);
875         }
876         return true;
877     }
878 #else
readLittleEndian(const uint8_t * & ptr,const uint8_t * end,T & value)879     template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
880     {
881         if (ptr > end - sizeof(value))
882             return false;
883 
884         if (sizeof(T) == 1)
885             value = *ptr++;
886         else {
887             value = 0;
888             for (unsigned i = 0; i < sizeof(T); i++)
889                 value += ((T)*ptr++) << (i * 8);
890         }
891         return true;
892     }
893 #endif
894 
read(uint32_t & i)895     bool read(uint32_t& i)
896     {
897         return readLittleEndian(i);
898     }
899 
read(int32_t & i)900     bool read(int32_t& i)
901     {
902         return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
903     }
904 
read(uint16_t & i)905     bool read(uint16_t& i)
906     {
907         return readLittleEndian(i);
908     }
909 
read(uint8_t & i)910     bool read(uint8_t& i)
911     {
912         return readLittleEndian(i);
913     }
914 
read(double & d)915     bool read(double& d)
916     {
917         union {
918             double d;
919             uint64_t i64;
920         } u;
921         if (!readLittleEndian(u.i64))
922             return false;
923         d = u.d;
924         return true;
925     }
926 
read(unsigned long long & i)927     bool read(unsigned long long& i)
928     {
929         return readLittleEndian(i);
930     }
931 
readStringIndex(uint32_t & i)932     bool readStringIndex(uint32_t& i)
933     {
934         return readConstantPoolIndex(m_constantPool, i);
935     }
936 
readConstantPoolIndex(const T & constantPool,uint32_t & i)937     template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
938     {
939         if (constantPool.size() <= 0xFF) {
940             uint8_t i8;
941             if (!read(i8))
942                 return false;
943             i = i8;
944             return true;
945         }
946         if (constantPool.size() <= 0xFFFF) {
947             uint16_t i16;
948             if (!read(i16))
949                 return false;
950             i = i16;
951             return true;
952         }
953         return read(i);
954     }
955 
readString(const uint8_t * & ptr,const uint8_t * end,UString & str,unsigned length)956     static bool readString(const uint8_t*& ptr, const uint8_t* end, UString& str, unsigned length)
957     {
958         if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
959             return false;
960 
961         unsigned size = length * sizeof(UChar);
962         if ((end - ptr) < static_cast<int>(size))
963             return false;
964 
965 #if ASSUME_LITTLE_ENDIAN
966         str = UString(reinterpret_cast<const UChar*>(ptr), length);
967         ptr += length * sizeof(UChar);
968 #else
969         Vector<UChar> buffer;
970         buffer.reserveCapacity(length);
971         for (unsigned i = 0; i < length; i++) {
972             uint16_t ch;
973             readLittleEndian(ptr, end, ch);
974             buffer.append(ch);
975         }
976         str = UString::adopt(buffer);
977 #endif
978         return true;
979     }
980 
readStringData(CachedStringRef & cachedString)981     bool readStringData(CachedStringRef& cachedString)
982     {
983         bool scratch;
984         return readStringData(cachedString, scratch);
985     }
986 
readStringData(CachedStringRef & cachedString,bool & wasTerminator)987     bool readStringData(CachedStringRef& cachedString, bool& wasTerminator)
988     {
989         if (m_failed)
990             return false;
991         uint32_t length = 0;
992         if (!read(length))
993             return false;
994         if (length == TerminatorTag) {
995             wasTerminator = true;
996             return false;
997         }
998         if (length == StringPoolTag) {
999             unsigned index = 0;
1000             if (!readStringIndex(index)) {
1001                 fail();
1002                 return false;
1003             }
1004             if (index >= m_constantPool.size()) {
1005                 fail();
1006                 return false;
1007             }
1008             cachedString = CachedStringRef(&m_constantPool, index);
1009             return true;
1010         }
1011         UString str;
1012         if (!readString(m_ptr, m_end, str, length)) {
1013             fail();
1014             return false;
1015         }
1016         m_constantPool.append(str);
1017         cachedString = CachedStringRef(&m_constantPool, m_constantPool.size() - 1);
1018         return true;
1019     }
1020 
readTag()1021     SerializationTag readTag()
1022     {
1023         if (m_ptr >= m_end)
1024             return ErrorTag;
1025         return static_cast<SerializationTag>(*m_ptr++);
1026     }
1027 
putProperty(JSArray * array,unsigned index,JSValue value)1028     void putProperty(JSArray* array, unsigned index, JSValue value)
1029     {
1030         if (array->canSetIndex(index))
1031             array->setIndex(m_exec->globalData(), index, value);
1032         else
1033             array->put(m_exec, index, value);
1034     }
1035 
putProperty(JSObject * object,const Identifier & property,JSValue value)1036     void putProperty(JSObject* object, const Identifier& property, JSValue value)
1037     {
1038         object->putDirect(m_exec->globalData(), property, value);
1039     }
1040 
readFile(RefPtr<File> & file)1041     bool readFile(RefPtr<File>& file)
1042     {
1043         CachedStringRef path;
1044         if (!readStringData(path))
1045             return 0;
1046         CachedStringRef url;
1047         if (!readStringData(url))
1048             return 0;
1049         CachedStringRef type;
1050         if (!readStringData(type))
1051             return 0;
1052         if (m_isDOMGlobalObject)
1053             file = File::create(String(path->ustring().impl()), KURL(KURL(), String(url->ustring().impl())), String(type->ustring().impl()));
1054         return true;
1055     }
1056 
readTerminal()1057     JSValue readTerminal()
1058     {
1059         SerializationTag tag = readTag();
1060         switch (tag) {
1061         case UndefinedTag:
1062             return jsUndefined();
1063         case NullTag:
1064             return jsNull();
1065         case IntTag: {
1066             int32_t i;
1067             if (!read(i))
1068                 return JSValue();
1069             return jsNumber(i);
1070         }
1071         case ZeroTag:
1072             return jsNumber(0);
1073         case OneTag:
1074             return jsNumber(1);
1075         case FalseTag:
1076             return jsBoolean(false);
1077         case TrueTag:
1078             return jsBoolean(true);
1079         case DoubleTag: {
1080             double d;
1081             if (!read(d))
1082                 return JSValue();
1083             return jsNumber(d);
1084         }
1085         case DateTag: {
1086             double d;
1087             if (!read(d))
1088                 return JSValue();
1089             return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), d);
1090         }
1091         case FileTag: {
1092             RefPtr<File> file;
1093             if (!readFile(file))
1094                 return JSValue();
1095             if (!m_isDOMGlobalObject)
1096                 return jsNull();
1097             return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), file.get());
1098         }
1099         case FileListTag: {
1100             unsigned length = 0;
1101             if (!read(length))
1102                 return JSValue();
1103             RefPtr<FileList> result = FileList::create();
1104             for (unsigned i = 0; i < length; i++) {
1105                 RefPtr<File> file;
1106                 if (!readFile(file))
1107                     return JSValue();
1108                 if (m_isDOMGlobalObject)
1109                     result->append(file.get());
1110             }
1111             if (!m_isDOMGlobalObject)
1112                 return jsNull();
1113             return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1114         }
1115         case ImageDataTag: {
1116             int32_t width;
1117             if (!read(width))
1118                 return JSValue();
1119             int32_t height;
1120             if (!read(height))
1121                 return JSValue();
1122             uint32_t length;
1123             if (!read(length))
1124                 return JSValue();
1125             if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
1126                 fail();
1127                 return JSValue();
1128             }
1129             if (!m_isDOMGlobalObject) {
1130                 m_ptr += length;
1131                 return jsNull();
1132             }
1133             RefPtr<ImageData> result = ImageData::create(IntSize(width, height));
1134             memcpy(result->data()->data()->data(), m_ptr, length);
1135             m_ptr += length;
1136             return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
1137         }
1138         case BlobTag: {
1139             CachedStringRef url;
1140             if (!readStringData(url))
1141                 return JSValue();
1142             CachedStringRef type;
1143             if (!readStringData(type))
1144                 return JSValue();
1145             unsigned long long size = 0;
1146             if (!read(size))
1147                 return JSValue();
1148             if (!m_isDOMGlobalObject)
1149                 return jsNull();
1150             return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(KURL(KURL(), url->ustring().impl()), String(type->ustring().impl()), size));
1151         }
1152         case StringTag: {
1153             CachedStringRef cachedString;
1154             if (!readStringData(cachedString))
1155                 return JSValue();
1156             return cachedString->jsString(m_exec);
1157         }
1158         case EmptyStringTag:
1159             return jsEmptyString(&m_exec->globalData());
1160         case RegExpTag: {
1161             CachedStringRef pattern;
1162             if (!readStringData(pattern))
1163                 return JSValue();
1164             CachedStringRef flags;
1165             if (!readStringData(flags))
1166                 return JSValue();
1167             RegExpFlags reFlags = regExpFlags(flags->ustring());
1168             ASSERT(reFlags != InvalidFlags);
1169             RefPtr<RegExp> regExp = RegExp::create(&m_exec->globalData(), pattern->ustring(), reFlags);
1170             return new (m_exec) RegExpObject(m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp);
1171         }
1172         case ObjectReferenceTag: {
1173             unsigned index = 0;
1174             if (!readConstantPoolIndex(m_gcBuffer, index)) {
1175                 fail();
1176                 return JSValue();
1177             }
1178             return m_gcBuffer.at(index);
1179         }
1180         default:
1181             m_ptr--; // Push the tag back
1182             return JSValue();
1183         }
1184     }
1185 
1186     JSGlobalObject* m_globalObject;
1187     bool m_isDOMGlobalObject;
1188     const uint8_t* m_ptr;
1189     const uint8_t* m_end;
1190     unsigned m_version;
1191     Vector<CachedString> m_constantPool;
1192 };
1193 
deserialize()1194 DeserializationResult CloneDeserializer::deserialize()
1195 {
1196     Vector<uint32_t, 16> indexStack;
1197     Vector<Identifier, 16> propertyNameStack;
1198     Vector<JSObject*, 16> outputObjectStack;
1199     Vector<JSArray*, 16> outputArrayStack;
1200     Vector<WalkerState, 16> stateStack;
1201     WalkerState state = StateUnknown;
1202     JSValue outValue;
1203 
1204     unsigned tickCount = ticksUntilNextCheck();
1205     while (1) {
1206         switch (state) {
1207         arrayStartState:
1208         case ArrayStartState: {
1209             uint32_t length;
1210             if (!read(length)) {
1211                 fail();
1212                 goto error;
1213             }
1214             JSArray* outArray = constructEmptyArray(m_exec, m_globalObject);
1215             outArray->setLength(length);
1216             m_gcBuffer.append(outArray);
1217             outputArrayStack.append(outArray);
1218             // fallthrough
1219         }
1220         arrayStartVisitMember:
1221         case ArrayStartVisitMember: {
1222             if (!--tickCount) {
1223                 if (didTimeOut())
1224                     return make_pair(JSValue(), InterruptedExecutionError);
1225                 tickCount = ticksUntilNextCheck();
1226             }
1227 
1228             uint32_t index;
1229             if (!read(index)) {
1230                 fail();
1231                 goto error;
1232             }
1233             if (index == TerminatorTag) {
1234                 JSArray* outArray = outputArrayStack.last();
1235                 outValue = outArray;
1236                 outputArrayStack.removeLast();
1237                 break;
1238             }
1239 
1240             if (JSValue terminal = readTerminal()) {
1241                 putProperty(outputArrayStack.last(), index, terminal);
1242                 goto arrayStartVisitMember;
1243             }
1244             if (m_failed)
1245                 goto error;
1246             indexStack.append(index);
1247             stateStack.append(ArrayEndVisitMember);
1248             goto stateUnknown;
1249         }
1250         case ArrayEndVisitMember: {
1251             JSArray* outArray = outputArrayStack.last();
1252             putProperty(outArray, indexStack.last(), outValue);
1253             indexStack.removeLast();
1254             goto arrayStartVisitMember;
1255         }
1256         objectStartState:
1257         case ObjectStartState: {
1258             if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion)
1259                 return make_pair(JSValue(), StackOverflowError);
1260             JSObject* outObject = constructEmptyObject(m_exec, m_globalObject);
1261             m_gcBuffer.append(outObject);
1262             outputObjectStack.append(outObject);
1263             // fallthrough
1264         }
1265         objectStartVisitMember:
1266         case ObjectStartVisitMember: {
1267             if (!--tickCount) {
1268                 if (didTimeOut())
1269                     return make_pair(JSValue(), InterruptedExecutionError);
1270                 tickCount = ticksUntilNextCheck();
1271             }
1272 
1273             CachedStringRef cachedString;
1274             bool wasTerminator = false;
1275             if (!readStringData(cachedString, wasTerminator)) {
1276                 if (!wasTerminator)
1277                     goto error;
1278                 JSObject* outObject = outputObjectStack.last();
1279                 outValue = outObject;
1280                 outputObjectStack.removeLast();
1281                 break;
1282             }
1283 
1284             if (JSValue terminal = readTerminal()) {
1285                 putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->ustring()), terminal);
1286                 goto objectStartVisitMember;
1287             }
1288             stateStack.append(ObjectEndVisitMember);
1289             propertyNameStack.append(Identifier(m_exec, cachedString->ustring()));
1290             goto stateUnknown;
1291         }
1292         case ObjectEndVisitMember: {
1293             putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
1294             propertyNameStack.removeLast();
1295             goto objectStartVisitMember;
1296         }
1297         stateUnknown:
1298         case StateUnknown:
1299             if (JSValue terminal = readTerminal()) {
1300                 outValue = terminal;
1301                 break;
1302             }
1303             SerializationTag tag = readTag();
1304             if (tag == ArrayTag)
1305                 goto arrayStartState;
1306             if (tag == ObjectTag)
1307                 goto objectStartState;
1308             goto error;
1309         }
1310         if (stateStack.isEmpty())
1311             break;
1312 
1313         state = stateStack.last();
1314         stateStack.removeLast();
1315 
1316         if (!--tickCount) {
1317             if (didTimeOut())
1318                 return make_pair(JSValue(), InterruptedExecutionError);
1319             tickCount = ticksUntilNextCheck();
1320         }
1321     }
1322     ASSERT(outValue);
1323     ASSERT(!m_failed);
1324     return make_pair(outValue, SuccessfullyCompleted);
1325 error:
1326     fail();
1327     return make_pair(JSValue(), ValidationError);
1328 }
1329 
1330 
1331 
~SerializedScriptValue()1332 SerializedScriptValue::~SerializedScriptValue()
1333 {
1334 }
1335 
SerializedScriptValue(Vector<uint8_t> & buffer)1336 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
1337 {
1338     m_data.swap(buffer);
1339 }
1340 
create(ExecState * exec,JSValue value,SerializationErrorMode throwExceptions)1341 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value, SerializationErrorMode throwExceptions)
1342 {
1343     Vector<uint8_t> buffer;
1344     SerializationReturnCode code = CloneSerializer::serialize(exec, value, buffer);
1345     if (throwExceptions == Throwing)
1346         maybeThrowExceptionIfSerializationFailed(exec, code);
1347 
1348     if (!serializationDidCompleteSuccessfully(code))
1349         return 0;
1350 
1351     return adoptRef(new SerializedScriptValue(buffer));
1352 }
1353 
create()1354 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
1355 {
1356     Vector<uint8_t> buffer;
1357     return adoptRef(new SerializedScriptValue(buffer));
1358 }
1359 
create(String string)1360 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(String string)
1361 {
1362     Vector<uint8_t> buffer;
1363     if (!CloneSerializer::serialize(string, buffer))
1364         return 0;
1365     return adoptRef(new SerializedScriptValue(buffer));
1366 }
1367 
create(JSContextRef originContext,JSValueRef apiValue,JSValueRef * exception)1368 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
1369 {
1370     ExecState* exec = toJS(originContext);
1371     APIEntryShim entryShim(exec);
1372     JSValue value = toJS(exec, apiValue);
1373     PassRefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value);
1374     if (exec->hadException()) {
1375         if (exception)
1376             *exception = toRef(exec, exec->exception());
1377         exec->clearException();
1378         return 0;
1379     }
1380     ASSERT(serializedValue);
1381     return serializedValue;
1382 }
1383 
toString()1384 String SerializedScriptValue::toString()
1385 {
1386     return CloneDeserializer::deserializeString(m_data);
1387 }
1388 
deserialize(ExecState * exec,JSGlobalObject * globalObject,SerializationErrorMode throwExceptions)1389 JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions)
1390 {
1391     DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, m_data);
1392     if (throwExceptions == Throwing)
1393         maybeThrowExceptionIfSerializationFailed(exec, result.second);
1394     return result.first;
1395 }
1396 
deserialize(JSContextRef destinationContext,JSValueRef * exception)1397 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
1398 {
1399     ExecState* exec = toJS(destinationContext);
1400     APIEntryShim entryShim(exec);
1401     JSValue value = deserialize(exec, exec->lexicalGlobalObject());
1402     if (exec->hadException()) {
1403         if (exception)
1404             *exception = toRef(exec, exec->exception());
1405         exec->clearException();
1406         return 0;
1407     }
1408     ASSERT(value);
1409     return toRef(exec, value);
1410 }
1411 
nullValue()1412 SerializedScriptValue* SerializedScriptValue::nullValue()
1413 {
1414     DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, emptyValue, (SerializedScriptValue::create()));
1415     return emptyValue.get();
1416 }
1417 
maybeThrowExceptionIfSerializationFailed(ExecState * exec,SerializationReturnCode code)1418 void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code)
1419 {
1420     if (code == SuccessfullyCompleted)
1421         return;
1422 
1423     switch (code) {
1424     case StackOverflowError:
1425         throwError(exec, createStackOverflowError(exec));
1426         break;
1427     case InterruptedExecutionError:
1428         throwError(exec, createInterruptedExecutionException(&exec->globalData()));
1429         break;
1430     case ValidationError:
1431         throwError(exec, createTypeError(exec, "Unable to deserialize data."));
1432         break;
1433     case ExistingExceptionError:
1434         break;
1435     case UnspecifiedError:
1436         break;
1437     default:
1438         ASSERT_NOT_REACHED();
1439     }
1440 }
1441 
serializationDidCompleteSuccessfully(SerializationReturnCode code)1442 bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
1443 {
1444     return (code == SuccessfullyCompleted);
1445 }
1446 
1447 }
1448