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