Home | History | Annotate | Download | only in js
      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:
    168     CloneBase(ExecState* exec)
    169         : m_exec(exec)
    170         , m_failed(false)
    171         , m_timeoutChecker(exec->globalData().timeoutChecker)
    172     {
    173     }
    174 
    175     bool shouldTerminate()
    176     {
    177         return m_exec->hadException();
    178     }
    179 
    180     unsigned ticksUntilNextCheck()
    181     {
    182         return m_timeoutChecker.ticksUntilNextCheck();
    183     }
    184 
    185     bool didTimeOut()
    186     {
    187         return m_timeoutChecker.didTimeOut(m_exec);
    188     }
    189 
    190     void throwStackOverflow()
    191     {
    192         throwError(m_exec, createStackOverflowError(m_exec));
    193     }
    194 
    195     void throwInterruptedException()
    196     {
    197         throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
    198     }
    199 
    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
    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
    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 
    227 template <> void writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, uint8_t value)
    228 {
    229     buffer.append(value);
    230 }
    231 
    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:
    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 
    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:
    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 
    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 
    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 
    307     bool startObject(JSObject* object)
    308     {
    309         if (!startObjectInternal(object))
    310             return false;
    311         write(ObjectTag);
    312         return true;
    313     }
    314 
    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 
    326     void endObject()
    327     {
    328         write(TerminatorTag);
    329     }
    330 
    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 
    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 
    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 
    383     void dumpString(UString str)
    384     {
    385         if (str.isEmpty())
    386             write(EmptyStringTag);
    387         else {
    388             write(StringTag);
    389             write(str);
    390         }
    391     }
    392 
    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 
    486     void write(SerializationTag tag)
    487     {
    488         writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
    489     }
    490 
    491     void write(uint8_t c)
    492     {
    493         writeLittleEndian(m_buffer, c);
    494     }
    495 
    496     void write(uint32_t i)
    497     {
    498         writeLittleEndian(m_buffer, i);
    499     }
    500 
    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 
    511     void write(int32_t i)
    512     {
    513         writeLittleEndian(m_buffer, i);
    514     }
    515 
    516     void write(unsigned long long i)
    517     {
    518         writeLittleEndian(m_buffer, i);
    519     }
    520 
    521     void write(uint16_t ch)
    522     {
    523         writeLittleEndian(m_buffer, ch);
    524     }
    525 
    526     void writeStringIndex(unsigned i)
    527     {
    528         writeConstantPoolIndex(m_constantPool, i);
    529     }
    530 
    531     void writeObjectIndex(unsigned i)
    532     {
    533         writeConstantPoolIndex(m_objectPool, i);
    534     }
    535 
    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 
    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 
    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 
    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 
    591     void write(const File* file)
    592     {
    593         write(file->path());
    594         write(file->url());
    595         write(file->type());
    596     }
    597 
    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 
    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:
    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 
    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 {
    798         CachedString(const UString& string)
    799             : m_string(string)
    800         {
    801         }
    802 
    803         JSValue jsString(ExecState* exec)
    804         {
    805             if (!m_jsString)
    806                 m_jsString = JSC::jsString(exec, m_string);
    807             return m_jsString;
    808         }
    809         const UString& ustring() { return m_string; }
    810 
    811     private:
    812         UString m_string;
    813         JSValue m_jsString;
    814     };
    815 
    816     struct CachedStringRef {
    817         CachedStringRef()
    818             : m_base(0)
    819             , m_index(0)
    820         {
    821         }
    822         CachedStringRef(Vector<CachedString>* base, size_t index)
    823             : m_base(base)
    824             , m_index(index)
    825         {
    826         }
    827 
    828         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 
    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 
    849     void throwValidationError()
    850     {
    851         throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
    852     }
    853 
    854     bool isValid() const { return m_version <= CurrentVersion; }
    855 
    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
    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
    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 
    895     bool read(uint32_t& i)
    896     {
    897         return readLittleEndian(i);
    898     }
    899 
    900     bool read(int32_t& i)
    901     {
    902         return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
    903     }
    904 
    905     bool read(uint16_t& i)
    906     {
    907         return readLittleEndian(i);
    908     }
    909 
    910     bool read(uint8_t& i)
    911     {
    912         return readLittleEndian(i);
    913     }
    914 
    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 
    927     bool read(unsigned long long& i)
    928     {
    929         return readLittleEndian(i);
    930     }
    931 
    932     bool readStringIndex(uint32_t& i)
    933     {
    934         return readConstantPoolIndex(m_constantPool, i);
    935     }
    936 
    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 
    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 
    981     bool readStringData(CachedStringRef& cachedString)
    982     {
    983         bool scratch;
    984         return readStringData(cachedString, scratch);
    985     }
    986 
    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 
   1021     SerializationTag readTag()
   1022     {
   1023         if (m_ptr >= m_end)
   1024             return ErrorTag;
   1025         return static_cast<SerializationTag>(*m_ptr++);
   1026     }
   1027 
   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 
   1036     void putProperty(JSObject* object, const Identifier& property, JSValue value)
   1037     {
   1038         object->putDirect(m_exec->globalData(), property, value);
   1039     }
   1040 
   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 
   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 
   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 
   1332 SerializedScriptValue::~SerializedScriptValue()
   1333 {
   1334 }
   1335 
   1336 SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
   1337 {
   1338     m_data.swap(buffer);
   1339 }
   1340 
   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 
   1354 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
   1355 {
   1356     Vector<uint8_t> buffer;
   1357     return adoptRef(new SerializedScriptValue(buffer));
   1358 }
   1359 
   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 
   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 
   1384 String SerializedScriptValue::toString()
   1385 {
   1386     return CloneDeserializer::deserializeString(m_data);
   1387 }
   1388 
   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 
   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 
   1412 SerializedScriptValue* SerializedScriptValue::nullValue()
   1413 {
   1414     DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, emptyValue, (SerializedScriptValue::create()));
   1415     return emptyValue.get();
   1416 }
   1417 
   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 
   1442 bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code)
   1443 {
   1444     return (code == SuccessfullyCompleted);
   1445 }
   1446 
   1447 }
   1448