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 "File.h"
     31 #include "FileList.h"
     32 #include "ImageData.h"
     33 #include "JSDOMGlobalObject.h"
     34 #include "JSFile.h"
     35 #include "JSFileList.h"
     36 #include "JSImageData.h"
     37 #include <JavaScriptCore/APICast.h>
     38 #include <runtime/DateInstance.h>
     39 #include <runtime/ExceptionHelpers.h>
     40 #include <runtime/JSLock.h>
     41 #include <runtime/PropertyNameArray.h>
     42 #include <wtf/ByteArray.h>
     43 #include <wtf/HashTraits.h>
     44 #include <wtf/Vector.h>
     45 
     46 using namespace JSC;
     47 
     48 namespace WebCore {
     49 
     50 class SerializedObject : public SharedSerializedData
     51 {
     52 public:
     53     typedef Vector<RefPtr<StringImpl> > PropertyNameList;
     54     typedef Vector<SerializedScriptValueData> ValueList;
     55 
     56     void set(const Identifier& propertyName, const SerializedScriptValueData& value)
     57     {
     58         ASSERT(m_names.size() == m_values.size());
     59         m_names.append(String(propertyName.ustring()).crossThreadString().impl());
     60         m_values.append(value);
     61     }
     62 
     63     PropertyNameList& names() { return m_names; }
     64 
     65     ValueList& values() { return m_values; }
     66 
     67     static PassRefPtr<SerializedObject> create()
     68     {
     69         return adoptRef(new SerializedObject);
     70     }
     71 
     72     void clear()
     73     {
     74         m_names.clear();
     75         m_values.clear();
     76     }
     77 
     78 private:
     79     SerializedObject() { }
     80     PropertyNameList m_names;
     81     ValueList m_values;
     82 };
     83 
     84 class SerializedArray : public SharedSerializedData
     85 {
     86     typedef HashMap<unsigned, SerializedScriptValueData, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > SparseMap;
     87 public:
     88     void setIndex(unsigned index, const SerializedScriptValueData& value)
     89     {
     90         ASSERT(index < m_length);
     91         if (index == m_compactStorage.size())
     92             m_compactStorage.append(value);
     93         else
     94             m_sparseStorage.set(index, value);
     95     }
     96 
     97     bool canDoFastRead(unsigned index) const
     98     {
     99         ASSERT(index < m_length);
    100         return index < m_compactStorage.size();
    101     }
    102 
    103     const SerializedScriptValueData& getIndex(unsigned index)
    104     {
    105         ASSERT(index < m_compactStorage.size());
    106         return m_compactStorage[index];
    107     }
    108 
    109     SerializedScriptValueData getSparseIndex(unsigned index, bool& hasIndex)
    110     {
    111         ASSERT(index >= m_compactStorage.size());
    112         ASSERT(index < m_length);
    113         SparseMap::iterator iter = m_sparseStorage.find(index);
    114         if (iter == m_sparseStorage.end()) {
    115             hasIndex = false;
    116             return SerializedScriptValueData();
    117         }
    118         hasIndex = true;
    119         return iter->second;
    120     }
    121 
    122     unsigned length() const
    123     {
    124         return m_length;
    125     }
    126 
    127     static PassRefPtr<SerializedArray> create(unsigned length)
    128     {
    129         return adoptRef(new SerializedArray(length));
    130     }
    131 
    132     void clear()
    133     {
    134         m_compactStorage.clear();
    135         m_sparseStorage.clear();
    136         m_length = 0;
    137     }
    138 private:
    139     SerializedArray(unsigned length)
    140         : m_length(length)
    141     {
    142     }
    143 
    144     Vector<SerializedScriptValueData> m_compactStorage;
    145     SparseMap m_sparseStorage;
    146     unsigned m_length;
    147 };
    148 
    149 class SerializedFileList : public SharedSerializedData {
    150 public:
    151     static PassRefPtr<SerializedFileList> create(const FileList* list)
    152     {
    153         return adoptRef(new SerializedFileList(list));
    154     }
    155 
    156     unsigned length() const { return m_files.size(); }
    157     const String& item(unsigned idx) { return m_files[idx]; }
    158 
    159 private:
    160     SerializedFileList(const FileList* list)
    161     {
    162         unsigned length = list->length();
    163         m_files.reserveCapacity(length);
    164         for (unsigned i = 0; i < length; i++)
    165             m_files.append(list->item(i)->path().crossThreadString());
    166     }
    167 
    168     Vector<String> m_files;
    169 };
    170 
    171 class SerializedImageData : public SharedSerializedData {
    172 public:
    173     static PassRefPtr<SerializedImageData> create(const ImageData* imageData)
    174     {
    175         return adoptRef(new SerializedImageData(imageData));
    176     }
    177 
    178     unsigned width() const { return m_width; }
    179     unsigned height() const { return m_height; }
    180     WTF::ByteArray* data() const { return m_storage.get(); }
    181 private:
    182     SerializedImageData(const ImageData* imageData)
    183         : m_width(imageData->width())
    184         , m_height(imageData->height())
    185     {
    186         WTF::ByteArray* array = imageData->data()->data();
    187         m_storage = WTF::ByteArray::create(array->length());
    188         memcpy(m_storage->data(), array->data(), array->length());
    189     }
    190     unsigned m_width;
    191     unsigned m_height;
    192     RefPtr<WTF::ByteArray> m_storage;
    193 };
    194 
    195 SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedObject> data)
    196     : m_type(ObjectType)
    197     , m_sharedData(data)
    198 {
    199 }
    200 
    201 SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedArray> data)
    202     : m_type(ArrayType)
    203     , m_sharedData(data)
    204 {
    205 }
    206 
    207 SerializedScriptValueData::SerializedScriptValueData(const FileList* fileList)
    208     : m_type(FileListType)
    209     , m_sharedData(SerializedFileList::create(fileList))
    210 {
    211 }
    212 
    213 SerializedScriptValueData::SerializedScriptValueData(const ImageData* imageData)
    214     : m_type(ImageDataType)
    215     , m_sharedData(SerializedImageData::create(imageData))
    216 {
    217 }
    218 
    219 SerializedScriptValueData::SerializedScriptValueData(const File* file)
    220     : m_type(FileType)
    221     , m_string(file->path().crossThreadString())
    222 {
    223 }
    224 
    225 SerializedArray* SharedSerializedData::asArray()
    226 {
    227     return static_cast<SerializedArray*>(this);
    228 }
    229 
    230 SerializedObject* SharedSerializedData::asObject()
    231 {
    232     return static_cast<SerializedObject*>(this);
    233 }
    234 
    235 SerializedFileList* SharedSerializedData::asFileList()
    236 {
    237     return static_cast<SerializedFileList*>(this);
    238 }
    239 
    240 SerializedImageData* SharedSerializedData::asImageData()
    241 {
    242     return static_cast<SerializedImageData*>(this);
    243 }
    244 
    245 static const unsigned maximumFilterRecursion = 40000;
    246 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
    247     ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
    248 template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker& context, typename TreeWalker::InputType in)
    249 {
    250     typedef typename TreeWalker::InputObject InputObject;
    251     typedef typename TreeWalker::InputArray InputArray;
    252     typedef typename TreeWalker::OutputObject OutputObject;
    253     typedef typename TreeWalker::OutputArray OutputArray;
    254     typedef typename TreeWalker::InputType InputType;
    255     typedef typename TreeWalker::OutputType OutputType;
    256     typedef typename TreeWalker::PropertyList PropertyList;
    257 
    258     Vector<uint32_t, 16> indexStack;
    259     Vector<uint32_t, 16> lengthStack;
    260     Vector<PropertyList, 16> propertyStack;
    261     Vector<InputObject, 16> inputObjectStack;
    262     Vector<InputArray, 16> inputArrayStack;
    263     Vector<OutputObject, 16> outputObjectStack;
    264     Vector<OutputArray, 16> outputArrayStack;
    265     Vector<WalkerState, 16> stateStack;
    266     WalkerState state = StateUnknown;
    267     InputType inValue = in;
    268     OutputType outValue = context.null();
    269 
    270     unsigned tickCount = context.ticksUntilNextCheck();
    271     while (1) {
    272         switch (state) {
    273             arrayStartState:
    274             case ArrayStartState: {
    275                 ASSERT(context.isArray(inValue));
    276                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
    277                     context.throwStackOverflow();
    278                     return context.null();
    279                 }
    280 
    281                 InputArray inArray = context.asInputArray(inValue);
    282                 unsigned length = context.length(inArray);
    283                 OutputArray outArray = context.createOutputArray(length);
    284                 if (!context.startArray(inArray, outArray))
    285                     return context.null();
    286                 inputArrayStack.append(inArray);
    287                 outputArrayStack.append(outArray);
    288                 indexStack.append(0);
    289                 lengthStack.append(length);
    290                 // fallthrough
    291             }
    292             arrayStartVisitMember:
    293             case ArrayStartVisitMember: {
    294                 if (!--tickCount) {
    295                     if (context.didTimeOut()) {
    296                         context.throwInterruptedException();
    297                         return context.null();
    298                     }
    299                     tickCount = context.ticksUntilNextCheck();
    300                 }
    301 
    302                 InputArray array = inputArrayStack.last();
    303                 uint32_t index = indexStack.last();
    304                 if (index == lengthStack.last()) {
    305                     InputArray inArray = inputArrayStack.last();
    306                     OutputArray outArray = outputArrayStack.last();
    307                     context.endArray(inArray, outArray);
    308                     outValue = outArray;
    309                     inputArrayStack.removeLast();
    310                     outputArrayStack.removeLast();
    311                     indexStack.removeLast();
    312                     lengthStack.removeLast();
    313                     break;
    314                 }
    315                 if (context.canDoFastRead(array, index))
    316                     inValue = context.getIndex(array, index);
    317                 else {
    318                     bool hasIndex = false;
    319                     inValue = context.getSparseIndex(array, index, hasIndex);
    320                     if (!hasIndex) {
    321                         indexStack.last()++;
    322                         goto arrayStartVisitMember;
    323                     }
    324                 }
    325 
    326                 if (OutputType transformed = context.convertIfTerminal(inValue))
    327                     outValue = transformed;
    328                 else {
    329                     stateStack.append(ArrayEndVisitMember);
    330                     goto stateUnknown;
    331                 }
    332                 // fallthrough
    333             }
    334             case ArrayEndVisitMember: {
    335                 OutputArray outArray = outputArrayStack.last();
    336                 context.putProperty(outArray, indexStack.last(), outValue);
    337                 indexStack.last()++;
    338                 goto arrayStartVisitMember;
    339             }
    340             objectStartState:
    341             case ObjectStartState: {
    342                 ASSERT(context.isObject(inValue));
    343                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
    344                     context.throwStackOverflow();
    345                     return context.null();
    346                 }
    347                 InputObject inObject = context.asInputObject(inValue);
    348                 OutputObject outObject = context.createOutputObject();
    349                 if (!context.startObject(inObject, outObject))
    350                     return context.null();
    351                 inputObjectStack.append(inObject);
    352                 outputObjectStack.append(outObject);
    353                 indexStack.append(0);
    354                 context.getPropertyNames(inObject, propertyStack);
    355                 // fallthrough
    356             }
    357             objectStartVisitMember:
    358             case ObjectStartVisitMember: {
    359                 if (!--tickCount) {
    360                     if (context.didTimeOut()) {
    361                         context.throwInterruptedException();
    362                         return context.null();
    363                     }
    364                     tickCount = context.ticksUntilNextCheck();
    365                 }
    366 
    367                 InputObject object = inputObjectStack.last();
    368                 uint32_t index = indexStack.last();
    369                 PropertyList& properties = propertyStack.last();
    370                 if (index == properties.size()) {
    371                     InputObject inObject = inputObjectStack.last();
    372                     OutputObject outObject = outputObjectStack.last();
    373                     context.endObject(inObject, outObject);
    374                     outValue = outObject;
    375                     inputObjectStack.removeLast();
    376                     outputObjectStack.removeLast();
    377                     indexStack.removeLast();
    378                     propertyStack.removeLast();
    379                     break;
    380                 }
    381                 inValue = context.getProperty(object, properties[index], index);
    382 
    383                 if (context.shouldTerminate())
    384                     return context.null();
    385 
    386                 if (OutputType transformed = context.convertIfTerminal(inValue))
    387                     outValue = transformed;
    388                 else {
    389                     stateStack.append(ObjectEndVisitMember);
    390                     goto stateUnknown;
    391                 }
    392                 // fallthrough
    393             }
    394             case ObjectEndVisitMember: {
    395                 context.putProperty(outputObjectStack.last(), propertyStack.last()[indexStack.last()], outValue);
    396                 if (context.shouldTerminate())
    397                     return context.null();
    398 
    399                 indexStack.last()++;
    400                 goto objectStartVisitMember;
    401             }
    402             stateUnknown:
    403             case StateUnknown:
    404                 if (OutputType transformed = context.convertIfTerminal(inValue)) {
    405                     outValue = transformed;
    406                     break;
    407                 }
    408                 if (context.isArray(inValue))
    409                     goto arrayStartState;
    410                 goto objectStartState;
    411         }
    412         if (stateStack.isEmpty())
    413             break;
    414 
    415         state = stateStack.last();
    416         stateStack.removeLast();
    417 
    418         if (!--tickCount) {
    419             if (context.didTimeOut()) {
    420                 context.throwInterruptedException();
    421                 return context.null();
    422             }
    423             tickCount = context.ticksUntilNextCheck();
    424         }
    425     }
    426     return outValue;
    427 }
    428 
    429 struct BaseWalker {
    430     BaseWalker(ExecState* exec)
    431         : m_exec(exec)
    432         , m_timeoutChecker(exec->globalData().timeoutChecker)
    433     {
    434         m_timeoutChecker.reset();
    435     }
    436     ExecState* m_exec;
    437     TimeoutChecker m_timeoutChecker;
    438     MarkedArgumentBuffer m_gcBuffer;
    439 
    440     bool shouldTerminate()
    441     {
    442         return m_exec->hadException();
    443     }
    444 
    445     unsigned ticksUntilNextCheck()
    446     {
    447         return m_timeoutChecker.ticksUntilNextCheck();
    448     }
    449 
    450     bool didTimeOut()
    451     {
    452         return m_timeoutChecker.didTimeOut(m_exec);
    453     }
    454 
    455     void throwStackOverflow()
    456     {
    457         m_exec->setException(createStackOverflowError(m_exec));
    458     }
    459 
    460     void throwInterruptedException()
    461     {
    462         m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
    463     }
    464 };
    465 
    466 struct SerializingTreeWalker : public BaseWalker {
    467     typedef JSValue InputType;
    468     typedef JSArray* InputArray;
    469     typedef JSObject* InputObject;
    470     typedef SerializedScriptValueData OutputType;
    471     typedef RefPtr<SerializedArray> OutputArray;
    472     typedef RefPtr<SerializedObject> OutputObject;
    473     typedef PropertyNameArray PropertyList;
    474 
    475     SerializingTreeWalker(ExecState* exec)
    476         : BaseWalker(exec)
    477     {
    478     }
    479 
    480     OutputType null() { return SerializedScriptValueData(); }
    481 
    482     bool isArray(JSValue value)
    483     {
    484         if (!value.isObject())
    485             return false;
    486         JSObject* object = asObject(value);
    487         return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info);
    488     }
    489 
    490     bool isObject(JSValue value)
    491     {
    492         return value.isObject();
    493     }
    494 
    495     JSArray* asInputArray(JSValue value)
    496     {
    497         return asArray(value);
    498     }
    499 
    500     JSObject* asInputObject(JSValue value)
    501     {
    502         return asObject(value);
    503     }
    504 
    505     PassRefPtr<SerializedArray> createOutputArray(unsigned length)
    506     {
    507         return SerializedArray::create(length);
    508     }
    509 
    510     PassRefPtr<SerializedObject> createOutputObject()
    511     {
    512         return SerializedObject::create();
    513     }
    514 
    515     uint32_t length(JSValue array)
    516     {
    517         ASSERT(array.isObject());
    518         JSObject* object = asObject(array);
    519         return object->get(m_exec, m_exec->propertyNames().length).toUInt32(m_exec);
    520     }
    521 
    522     bool canDoFastRead(JSArray* array, unsigned index)
    523     {
    524         return isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index);
    525     }
    526 
    527     JSValue getIndex(JSArray* array, unsigned index)
    528     {
    529         return array->getIndex(index);
    530     }
    531 
    532     JSValue getSparseIndex(JSObject* object, unsigned propertyName, bool& hasIndex)
    533     {
    534         PropertySlot slot(object);
    535         if (object->getOwnPropertySlot(m_exec, propertyName, slot)) {
    536             hasIndex = true;
    537             return slot.getValue(m_exec, propertyName);
    538         }
    539         hasIndex = false;
    540         return jsNull();
    541     }
    542 
    543     JSValue getProperty(JSObject* object, const Identifier& propertyName, unsigned)
    544     {
    545         PropertySlot slot(object);
    546         if (object->getOwnPropertySlot(m_exec, propertyName, slot))
    547             return slot.getValue(m_exec, propertyName);
    548         return jsNull();
    549     }
    550 
    551     SerializedScriptValueData convertIfTerminal(JSValue value)
    552     {
    553         if (!value.isCell())
    554             return SerializedScriptValueData(value);
    555 
    556         if (value.isString())
    557             return SerializedScriptValueData(asString(value)->value(m_exec));
    558 
    559         if (value.isNumber())
    560             return SerializedScriptValueData(SerializedScriptValueData::NumberType, value.uncheckedGetNumber());
    561 
    562         if (value.isObject() && asObject(value)->inherits(&DateInstance::info))
    563             return SerializedScriptValueData(SerializedScriptValueData::DateType, asDateInstance(value)->internalNumber());
    564 
    565         if (isArray(value))
    566             return SerializedScriptValueData();
    567 
    568         if (value.isObject()) {
    569             JSObject* obj = asObject(value);
    570             if (obj->inherits(&JSFile::s_info))
    571                 return SerializedScriptValueData(toFile(obj));
    572             if (obj->inherits(&JSFileList::s_info))
    573                 return SerializedScriptValueData(toFileList(obj));
    574             if (obj->inherits(&JSImageData::s_info))
    575                 return SerializedScriptValueData(toImageData(obj));
    576 
    577             CallData unusedData;
    578             if (value.getCallData(unusedData) == CallTypeNone)
    579                 return SerializedScriptValueData();
    580         }
    581         // Any other types are expected to serialize as null.
    582         return SerializedScriptValueData(jsNull());
    583     }
    584 
    585     void getPropertyNames(JSObject* object, Vector<PropertyNameArray, 16>& propertyStack)
    586     {
    587         propertyStack.append(PropertyNameArray(m_exec));
    588         object->getOwnPropertyNames(m_exec, propertyStack.last());
    589     }
    590 
    591     void putProperty(RefPtr<SerializedArray> array, unsigned propertyName, const SerializedScriptValueData& value)
    592     {
    593         array->setIndex(propertyName, value);
    594     }
    595 
    596     void putProperty(RefPtr<SerializedObject> object, const Identifier& propertyName, const SerializedScriptValueData& value)
    597     {
    598         object->set(propertyName, value);
    599     }
    600 
    601     bool startArray(JSArray* inArray, RefPtr<SerializedArray>)
    602     {
    603         // Cycle detection
    604         if (!m_cycleDetector.add(inArray).second) {
    605             m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures."));
    606             return false;
    607         }
    608         m_gcBuffer.append(inArray);
    609         return true;
    610     }
    611 
    612     void endArray(JSArray* inArray, RefPtr<SerializedArray>)
    613     {
    614         m_cycleDetector.remove(inArray);
    615         m_gcBuffer.removeLast();
    616     }
    617 
    618     bool startObject(JSObject* inObject, RefPtr<SerializedObject>)
    619     {
    620         // Cycle detection
    621         if (!m_cycleDetector.add(inObject).second) {
    622             m_exec->setException(createTypeError(m_exec, "Cannot post cyclic structures."));
    623             return false;
    624         }
    625         m_gcBuffer.append(inObject);
    626         return true;
    627     }
    628 
    629     void endObject(JSObject* inObject, RefPtr<SerializedObject>)
    630     {
    631         m_cycleDetector.remove(inObject);
    632         m_gcBuffer.removeLast();
    633     }
    634 
    635 private:
    636     HashSet<JSObject*> m_cycleDetector;
    637 };
    638 
    639 SerializedScriptValueData SerializedScriptValueData::serialize(ExecState* exec, JSValue inValue)
    640 {
    641     SerializingTreeWalker context(exec);
    642     return walk<SerializingTreeWalker>(context, inValue);
    643 }
    644 
    645 
    646 struct DeserializingTreeWalker : public BaseWalker {
    647     typedef SerializedScriptValueData InputType;
    648     typedef RefPtr<SerializedArray> InputArray;
    649     typedef RefPtr<SerializedObject> InputObject;
    650     typedef JSValue OutputType;
    651     typedef JSArray* OutputArray;
    652     typedef JSObject* OutputObject;
    653     typedef SerializedObject::PropertyNameList PropertyList;
    654 
    655     DeserializingTreeWalker(ExecState* exec, JSGlobalObject* globalObject, bool mustCopy)
    656         : BaseWalker(exec)
    657         , m_globalObject(globalObject)
    658         , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
    659         , m_mustCopy(mustCopy)
    660     {
    661     }
    662 
    663     OutputType null() { return jsNull(); }
    664 
    665     bool isArray(const SerializedScriptValueData& value)
    666     {
    667         return value.type() == SerializedScriptValueData::ArrayType;
    668     }
    669 
    670     bool isObject(const SerializedScriptValueData& value)
    671     {
    672         return value.type() == SerializedScriptValueData::ObjectType;
    673     }
    674 
    675     SerializedArray* asInputArray(const SerializedScriptValueData& value)
    676     {
    677         return value.asArray();
    678     }
    679 
    680     SerializedObject* asInputObject(const SerializedScriptValueData& value)
    681     {
    682         return value.asObject();
    683     }
    684 
    685     JSArray* createOutputArray(unsigned length)
    686     {
    687         JSArray* array = constructEmptyArray(m_exec, m_globalObject);
    688         array->setLength(length);
    689         return array;
    690     }
    691 
    692     JSObject* createOutputObject()
    693     {
    694         return constructEmptyObject(m_exec, m_globalObject);
    695     }
    696 
    697     uint32_t length(RefPtr<SerializedArray> array)
    698     {
    699         return array->length();
    700     }
    701 
    702     bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index)
    703     {
    704         return array->canDoFastRead(index);
    705     }
    706 
    707     SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index)
    708     {
    709         return array->getIndex(index);
    710     }
    711 
    712     SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex)
    713     {
    714         return array->getSparseIndex(propertyName, hasIndex);
    715     }
    716 
    717     SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex)
    718     {
    719         ASSERT(object->names()[propertyIndex] == propertyName);
    720         UNUSED_PARAM(propertyName);
    721         return object->values()[propertyIndex];
    722     }
    723 
    724     JSValue convertIfTerminal(SerializedScriptValueData& value)
    725     {
    726         switch (value.type()) {
    727             case SerializedScriptValueData::ArrayType:
    728             case SerializedScriptValueData::ObjectType:
    729                 return JSValue();
    730             case SerializedScriptValueData::StringType:
    731                 return jsString(m_exec, value.asString().crossThreadString());
    732             case SerializedScriptValueData::ImmediateType:
    733                 return value.asImmediate();
    734             case SerializedScriptValueData::NumberType:
    735                 return jsNumber(m_exec, value.asDouble());
    736             case SerializedScriptValueData::DateType:
    737                 return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), value.asDouble());
    738             case SerializedScriptValueData::FileType:
    739                 if (!m_isDOMGlobalObject)
    740                     return jsNull();
    741                 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), File::create(value.asString().crossThreadString()));
    742             case SerializedScriptValueData::FileListType: {
    743                 if (!m_isDOMGlobalObject)
    744                     return jsNull();
    745                 RefPtr<FileList> result = FileList::create();
    746                 SerializedFileList* serializedFileList = value.asFileList();
    747                 unsigned length = serializedFileList->length();
    748                 for (unsigned i = 0; i < length; i++)
    749                     result->append(File::create(serializedFileList->item(i)));
    750                 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
    751             }
    752             case SerializedScriptValueData::ImageDataType: {
    753                 if (!m_isDOMGlobalObject)
    754                     return jsNull();
    755                 SerializedImageData* serializedImageData = value.asImageData();
    756                 RefPtr<ImageData> result = ImageData::create(serializedImageData->width(), serializedImageData->height());
    757                 memcpy(result->data()->data()->data(), serializedImageData->data()->data(), serializedImageData->data()->length());
    758                 return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
    759             }
    760             case SerializedScriptValueData::EmptyType:
    761                 ASSERT_NOT_REACHED();
    762                 return jsNull();
    763         }
    764         ASSERT_NOT_REACHED();
    765         return jsNull();
    766     }
    767 
    768     void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties)
    769     {
    770         properties.append(object->names());
    771     }
    772 
    773     void putProperty(JSArray* array, unsigned propertyName, JSValue value)
    774     {
    775         array->put(m_exec, propertyName, value);
    776     }
    777 
    778     void putProperty(JSObject* object, const RefPtr<StringImpl> propertyName, JSValue value)
    779     {
    780         object->putDirect(Identifier(m_exec, String(propertyName)), value);
    781     }
    782 
    783     bool startArray(RefPtr<SerializedArray>, JSArray* outArray)
    784     {
    785         m_gcBuffer.append(outArray);
    786         return true;
    787     }
    788     void endArray(RefPtr<SerializedArray>, JSArray*)
    789     {
    790         m_gcBuffer.removeLast();
    791     }
    792     bool startObject(RefPtr<SerializedObject>, JSObject* outObject)
    793     {
    794         m_gcBuffer.append(outObject);
    795         return true;
    796     }
    797     void endObject(RefPtr<SerializedObject>, JSObject*)
    798     {
    799         m_gcBuffer.removeLast();
    800     }
    801 
    802 private:
    803     void* operator new(size_t);
    804     JSGlobalObject* m_globalObject;
    805     bool m_isDOMGlobalObject;
    806     bool m_mustCopy;
    807 };
    808 
    809 JSValue SerializedScriptValueData::deserialize(ExecState* exec, JSGlobalObject* global, bool mustCopy) const
    810 {
    811     DeserializingTreeWalker context(exec, global, mustCopy);
    812     return walk<DeserializingTreeWalker>(context, *this);
    813 }
    814 
    815 struct TeardownTreeWalker {
    816     typedef SerializedScriptValueData InputType;
    817     typedef RefPtr<SerializedArray> InputArray;
    818     typedef RefPtr<SerializedObject> InputObject;
    819     typedef bool OutputType;
    820     typedef bool OutputArray;
    821     typedef bool OutputObject;
    822     typedef SerializedObject::PropertyNameList PropertyList;
    823 
    824     bool shouldTerminate()
    825     {
    826         return false;
    827     }
    828 
    829     unsigned ticksUntilNextCheck()
    830     {
    831         return 0xFFFFFFFF;
    832     }
    833 
    834     bool didTimeOut()
    835     {
    836         return false;
    837     }
    838 
    839     void throwStackOverflow()
    840     {
    841     }
    842 
    843     void throwInterruptedException()
    844     {
    845     }
    846 
    847     bool null() { return false; }
    848 
    849     bool isArray(const SerializedScriptValueData& value)
    850     {
    851         return value.type() == SerializedScriptValueData::ArrayType;
    852     }
    853 
    854     bool isObject(const SerializedScriptValueData& value)
    855     {
    856         return value.type() == SerializedScriptValueData::ObjectType;
    857     }
    858 
    859     SerializedArray* asInputArray(const SerializedScriptValueData& value)
    860     {
    861         return value.asArray();
    862     }
    863 
    864     SerializedObject* asInputObject(const SerializedScriptValueData& value)
    865     {
    866         return value.asObject();
    867     }
    868 
    869     bool createOutputArray(unsigned)
    870     {
    871         return false;
    872     }
    873 
    874     bool createOutputObject()
    875     {
    876         return false;
    877     }
    878 
    879     uint32_t length(RefPtr<SerializedArray> array)
    880     {
    881         return array->length();
    882     }
    883 
    884     bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index)
    885     {
    886         return array->canDoFastRead(index);
    887     }
    888 
    889     SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index)
    890     {
    891         return array->getIndex(index);
    892     }
    893 
    894     SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex)
    895     {
    896         return array->getSparseIndex(propertyName, hasIndex);
    897     }
    898 
    899     SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex)
    900     {
    901         ASSERT(object->names()[propertyIndex] == propertyName);
    902         UNUSED_PARAM(propertyName);
    903         return object->values()[propertyIndex];
    904     }
    905 
    906     bool convertIfTerminal(SerializedScriptValueData& value)
    907     {
    908         switch (value.type()) {
    909             case SerializedScriptValueData::ArrayType:
    910             case SerializedScriptValueData::ObjectType:
    911                 return false;
    912             case SerializedScriptValueData::StringType:
    913             case SerializedScriptValueData::ImmediateType:
    914             case SerializedScriptValueData::NumberType:
    915             case SerializedScriptValueData::DateType:
    916             case SerializedScriptValueData::EmptyType:
    917             case SerializedScriptValueData::FileType:
    918             case SerializedScriptValueData::FileListType:
    919             case SerializedScriptValueData::ImageDataType:
    920                 return true;
    921         }
    922         ASSERT_NOT_REACHED();
    923         return true;
    924     }
    925 
    926     void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties)
    927     {
    928         properties.append(object->names());
    929     }
    930 
    931     void putProperty(bool, unsigned, bool)
    932     {
    933     }
    934 
    935     void putProperty(bool, const RefPtr<StringImpl>&, bool)
    936     {
    937     }
    938 
    939     bool startArray(RefPtr<SerializedArray>, bool)
    940     {
    941         return true;
    942     }
    943     void endArray(RefPtr<SerializedArray> array, bool)
    944     {
    945         array->clear();
    946     }
    947     bool startObject(RefPtr<SerializedObject>, bool)
    948     {
    949         return true;
    950     }
    951     void endObject(RefPtr<SerializedObject> object, bool)
    952     {
    953         object->clear();
    954     }
    955 };
    956 
    957 void SerializedScriptValueData::tearDownSerializedData()
    958 {
    959     if (m_sharedData && m_sharedData->refCount() > 1)
    960         return;
    961     TeardownTreeWalker context;
    962     walk<TeardownTreeWalker>(context, *this);
    963 }
    964 
    965 SerializedScriptValue::~SerializedScriptValue()
    966 {
    967 }
    968 
    969 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
    970 {
    971     JSLock lock(SilenceAssertionsOnly);
    972     ExecState* exec = toJS(originContext);
    973     JSValue value = toJS(exec, apiValue);
    974     PassRefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value);
    975     if (exec->hadException()) {
    976         if (exception)
    977             *exception = toRef(exec, exec->exception());
    978         exec->clearException();
    979         return 0;
    980     }
    981 
    982     return serializedValue;
    983 }
    984 
    985 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
    986 {
    987     JSLock lock(SilenceAssertionsOnly);
    988     ExecState* exec = toJS(destinationContext);
    989     JSValue value = deserialize(exec, exec->lexicalGlobalObject());
    990     if (exec->hadException()) {
    991         if (exception)
    992             *exception = toRef(exec, exec->exception());
    993         exec->clearException();
    994         return 0;
    995     }
    996     return toRef(exec, value);
    997 }
    998 
    999 }
   1000