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
46using namespace JSC;
47
48namespace WebCore {
49
50class SerializedObject : public SharedSerializedData
51{
52public:
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
78private:
79    SerializedObject() { }
80    PropertyNameList m_names;
81    ValueList m_values;
82};
83
84class SerializedArray : public SharedSerializedData
85{
86    typedef HashMap<unsigned, SerializedScriptValueData, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > SparseMap;
87public:
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    }
138private:
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
149class SerializedFileList : public SharedSerializedData {
150public:
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
159private:
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
171class SerializedImageData : public SharedSerializedData {
172public:
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(); }
181private:
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
195SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedObject> data)
196    : m_type(ObjectType)
197    , m_sharedData(data)
198{
199}
200
201SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedArray> data)
202    : m_type(ArrayType)
203    , m_sharedData(data)
204{
205}
206
207SerializedScriptValueData::SerializedScriptValueData(const FileList* fileList)
208    : m_type(FileListType)
209    , m_sharedData(SerializedFileList::create(fileList))
210{
211}
212
213SerializedScriptValueData::SerializedScriptValueData(const ImageData* imageData)
214    : m_type(ImageDataType)
215    , m_sharedData(SerializedImageData::create(imageData))
216{
217}
218
219SerializedScriptValueData::SerializedScriptValueData(const File* file)
220    : m_type(FileType)
221    , m_string(file->path().crossThreadString())
222{
223}
224
225SerializedArray* SharedSerializedData::asArray()
226{
227    return static_cast<SerializedArray*>(this);
228}
229
230SerializedObject* SharedSerializedData::asObject()
231{
232    return static_cast<SerializedObject*>(this);
233}
234
235SerializedFileList* SharedSerializedData::asFileList()
236{
237    return static_cast<SerializedFileList*>(this);
238}
239
240SerializedImageData* SharedSerializedData::asImageData()
241{
242    return static_cast<SerializedImageData*>(this);
243}
244
245static const unsigned maximumFilterRecursion = 40000;
246enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
247    ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
248template <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
429struct 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
466struct 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
635private:
636    HashSet<JSObject*> m_cycleDetector;
637};
638
639SerializedScriptValueData SerializedScriptValueData::serialize(ExecState* exec, JSValue inValue)
640{
641    SerializingTreeWalker context(exec);
642    return walk<SerializingTreeWalker>(context, inValue);
643}
644
645
646struct 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
802private:
803    void* operator new(size_t);
804    JSGlobalObject* m_globalObject;
805    bool m_isDOMGlobalObject;
806    bool m_mustCopy;
807};
808
809JSValue SerializedScriptValueData::deserialize(ExecState* exec, JSGlobalObject* global, bool mustCopy) const
810{
811    DeserializingTreeWalker context(exec, global, mustCopy);
812    return walk<DeserializingTreeWalker>(context, *this);
813}
814
815struct 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
957void SerializedScriptValueData::tearDownSerializedData()
958{
959    if (m_sharedData && m_sharedData->refCount() > 1)
960        return;
961    TeardownTreeWalker context;
962    walk<TeardownTreeWalker>(context, *this);
963}
964
965SerializedScriptValue::~SerializedScriptValue()
966{
967}
968
969PassRefPtr<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
985JSValueRef 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