[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

oliver at apple.com oliver at apple.com
Wed Dec 22 13:05:19 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 8128fe1e91ccaa79c038d5cc06cf17f50f14c33d
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Sep 6 21:29:06 2010 +0000

    2010-09-05  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Sam Weinig.
    
            SerializedScriptValue needs to use a flat storage mechanism
            https://bugs.webkit.org/show_bug.cgi?id=45244
    
            Export JSArray::put
    
            * JavaScriptCore.exp:
    2010-09-05  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Sam Weinig.
    
            SerializedScriptValue needs to use a flat storage mechanism
            https://bugs.webkit.org/show_bug.cgi?id=45244
    
            Add a few more test cases to cover the new branches in the
            rewritten serialization logic.
    
            * fast/dom/Window/window-postmessage-clone-expected.txt:
            * fast/dom/Window/window-postmessage-clone.html:
    2010-09-05  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Sam Weinig.
    
            SerializedScriptValue needs to use a flat storage mechanism
            https://bugs.webkit.org/show_bug.cgi?id=45244
    
            Rewrite the old tree to tree serialization logic to use
            flat storage.  Unfortunately this basically required a
            complete rewrite.
    
            * bindings/js/SerializedScriptValue.cpp:
            (WebCore::CloneBase::CloneBase):
            (WebCore::CloneBase::shouldTerminate):
            (WebCore::CloneBase::ticksUntilNextCheck):
            (WebCore::CloneBase::didTimeOut):
            (WebCore::CloneBase::throwStackOverflow):
            (WebCore::CloneBase::throwInterruptedException):
            (WebCore::CloneBase::fail):
            (WebCore::CloneSerializer::serialize):
            (WebCore::CloneSerializer::CloneSerializer):
            (WebCore::CloneSerializer::isArray):
            (WebCore::CloneSerializer::startObject):
            (WebCore::CloneSerializer::startArray):
            (WebCore::CloneSerializer::endObject):
            (WebCore::CloneSerializer::getSparseIndex):
            (WebCore::CloneSerializer::getProperty):
            (WebCore::CloneSerializer::dumpImmediate):
            (WebCore::CloneSerializer::dumpString):
            (WebCore::CloneSerializer::dumpIfTerminal):
            (WebCore::CloneSerializer::write):
            (WebCore::CloneSerializer::writeLittleEndian):
            (WebCore::CloneSerializer::writeStringIndex):
            (WebCore::CloneDeserializer::deserializeString):
            (WebCore::CloneDeserializer::deserialize):
            (WebCore::CloneDeserializer::CloneDeserializer):
            (WebCore::CloneDeserializer::throwValidationError):
            (WebCore::CloneDeserializer::isValid):
            (WebCore::CloneDeserializer::readLittleEndian):
            (WebCore::CloneDeserializer::read):
            (WebCore::CloneDeserializer::readStringIndex):
            (WebCore::CloneDeserializer::readString):
            (WebCore::CloneDeserializer::readStringData):
            (WebCore::CloneDeserializer::readTag):
            (WebCore::CloneDeserializer::putProperty):
            (WebCore::CloneDeserializer::readFile):
            (WebCore::CloneDeserializer::readTerminal):
            (WebCore::SerializedScriptValue::~SerializedScriptValue):
            (WebCore::SerializedScriptValue::SerializedScriptValue):
            (WebCore::SerializedScriptValue::create):
            (WebCore::SerializedScriptValue::toString):
            (WebCore::SerializedScriptValue::deserialize):
            (WebCore::SerializedScriptValue::nullValue):
            * bindings/js/SerializedScriptValue.h:
            * dom/MessagePortChannel.cpp:
            (WebCore::MessagePortChannel::EventData::EventData):
            * workers/WorkerMessagingProxy.cpp:
            (WebCore::MessageWorkerContextTask::MessageWorkerContextTask):
            (WebCore::MessageWorkerTask::MessageWorkerTask):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66850 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 0e97c63..0da9399 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,14 @@
+2010-09-05  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Sam Weinig.
+
+        SerializedScriptValue needs to use a flat storage mechanism
+        https://bugs.webkit.org/show_bug.cgi?id=45244
+
+        Export JSArray::put
+
+        * JavaScriptCore.exp:
+
 2010-09-06  Chao-ying Fu  <fu at mips.com>
 
         Reviewed by Oliver Hunt.
diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp
index 30f5aa8..7df9376 100644
--- a/JavaScriptCore/JavaScriptCore.exp
+++ b/JavaScriptCore/JavaScriptCore.exp
@@ -241,6 +241,7 @@ __ZN3JSC6JSLockC1EPNS_9ExecStateE
 __ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE
 __ZN3JSC7JSArray12markChildrenERNS_9MarkStackE
 __ZN3JSC7JSArray15setSubclassDataEPv
+__ZN3JSC7JSArray18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
 __ZN3JSC7JSArray4infoE
 __ZN3JSC7JSArray9setLengthEj
 __ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index adbcc72..13af14d 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,16 @@
+2010-09-05  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Sam Weinig.
+
+        SerializedScriptValue needs to use a flat storage mechanism
+        https://bugs.webkit.org/show_bug.cgi?id=45244
+
+        Add a few more test cases to cover the new branches in the
+        rewritten serialization logic.
+
+        * fast/dom/Window/window-postmessage-clone-expected.txt:
+        * fast/dom/Window/window-postmessage-clone.html:
+
 2010-09-06  Justin Schuh  <jschuh at chromium.org>
 
         Reviewed by Nikolas Zimmermann.
diff --git a/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt b/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
index 54f1940..edb0124 100644
--- a/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
+++ b/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
@@ -10,7 +10,14 @@ PASS: eventData is true of type boolean
 PASS: eventData is 1 of type string
 PASS: eventData is [object Object] of type object
 PASS: eventData is [object Object] of type object
+PASS: eventData is [object Object] of type object
+PASS: eventData is [object Object] of type object
+PASS: eventData is [object Object] of type object
+PASS: eventData is [object Object] of type object
+PASS: eventData is [object Object] of type object
 PASS: eventData is of type object
+PASS: eventData is a,a,b,a,b of type object
+PASS: eventData is a,a,b,[object Object] of type object
 PASS: eventData is 1,2,3 of type object
 PASS: eventData is ,,1 of type object
 PASS: eventData is null of type object
diff --git a/LayoutTests/fast/dom/Window/window-postmessage-clone.html b/LayoutTests/fast/dom/Window/window-postmessage-clone.html
index e755f4a..6cb337d 100644
--- a/LayoutTests/fast/dom/Window/window-postmessage-clone.html
+++ b/LayoutTests/fast/dom/Window/window-postmessage-clone.html
@@ -124,7 +124,14 @@ tryPostMessage('true');
 tryPostMessage('"1"');
 tryPostMessage('({})');
 tryPostMessage('({a:1})');
+tryPostMessage('({a:"a"})');
+tryPostMessage('({b:"a", a:"b"})');
+tryPostMessage('({a:""})');
+tryPostMessage('({a:0})');
+tryPostMessage('({a:1})');
 tryPostMessage('[]');
+tryPostMessage('["a", "a", "b", "a", "b"]');
+tryPostMessage('["a", "a", "b", {a:"b", b:"a"}]');
 tryPostMessage('[1,2,3]');
 tryPostMessage('[,,1]');
 tryPostMessage('(function(){})', false, 'null');
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 09c3268..55caadb 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,63 @@
+2010-09-05  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Sam Weinig.
+
+        SerializedScriptValue needs to use a flat storage mechanism
+        https://bugs.webkit.org/show_bug.cgi?id=45244
+
+        Rewrite the old tree to tree serialization logic to use
+        flat storage.  Unfortunately this basically required a
+        complete rewrite.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneBase::CloneBase):
+        (WebCore::CloneBase::shouldTerminate):
+        (WebCore::CloneBase::ticksUntilNextCheck):
+        (WebCore::CloneBase::didTimeOut):
+        (WebCore::CloneBase::throwStackOverflow):
+        (WebCore::CloneBase::throwInterruptedException):
+        (WebCore::CloneBase::fail):
+        (WebCore::CloneSerializer::serialize):
+        (WebCore::CloneSerializer::CloneSerializer):
+        (WebCore::CloneSerializer::isArray):
+        (WebCore::CloneSerializer::startObject):
+        (WebCore::CloneSerializer::startArray):
+        (WebCore::CloneSerializer::endObject):
+        (WebCore::CloneSerializer::getSparseIndex):
+        (WebCore::CloneSerializer::getProperty):
+        (WebCore::CloneSerializer::dumpImmediate):
+        (WebCore::CloneSerializer::dumpString):
+        (WebCore::CloneSerializer::dumpIfTerminal):
+        (WebCore::CloneSerializer::write):
+        (WebCore::CloneSerializer::writeLittleEndian):
+        (WebCore::CloneSerializer::writeStringIndex):
+        (WebCore::CloneDeserializer::deserializeString):
+        (WebCore::CloneDeserializer::deserialize):
+        (WebCore::CloneDeserializer::CloneDeserializer):
+        (WebCore::CloneDeserializer::throwValidationError):
+        (WebCore::CloneDeserializer::isValid):
+        (WebCore::CloneDeserializer::readLittleEndian):
+        (WebCore::CloneDeserializer::read):
+        (WebCore::CloneDeserializer::readStringIndex):
+        (WebCore::CloneDeserializer::readString):
+        (WebCore::CloneDeserializer::readStringData):
+        (WebCore::CloneDeserializer::readTag):
+        (WebCore::CloneDeserializer::putProperty):
+        (WebCore::CloneDeserializer::readFile):
+        (WebCore::CloneDeserializer::readTerminal):
+        (WebCore::SerializedScriptValue::~SerializedScriptValue):
+        (WebCore::SerializedScriptValue::SerializedScriptValue):
+        (WebCore::SerializedScriptValue::create):
+        (WebCore::SerializedScriptValue::toString):
+        (WebCore::SerializedScriptValue::deserialize):
+        (WebCore::SerializedScriptValue::nullValue):
+        * bindings/js/SerializedScriptValue.h:
+        * dom/MessagePortChannel.cpp:
+        (WebCore::MessagePortChannel::EventData::EventData):
+        * workers/WorkerMessagingProxy.cpp:
+        (WebCore::MessageWorkerContextTask::MessageWorkerContextTask):
+        (WebCore::MessageWorkerTask::MessageWorkerTask):
+
 2010-09-06  Martin Robinson  <mrobinson at igalia.com>
 
         Reviewed by Gustavo Noronha Silva.
diff --git a/WebCore/bindings/js/SerializedScriptValue.cpp b/WebCore/bindings/js/SerializedScriptValue.cpp
index ca18ec0..2d83880 100644
--- a/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -36,6 +36,8 @@
 #include "JSFile.h"
 #include "JSFileList.h"
 #include "JSImageData.h"
+#include "SharedBuffer.h"
+#include <limits>
 #include <JavaScriptCore/APICast.h>
 #include <runtime/DateInstance.h>
 #include <runtime/Error.h>
@@ -47,323 +49,526 @@
 #include <wtf/Vector.h>
 
 using namespace JSC;
+using namespace std;
+
+#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
+#define ASSUME_LITTLE_ENDIAN 0
+#else
+#define ASSUME_LITTLE_ENDIAN 1
+#endif
 
 namespace WebCore {
 
-class SerializedObject : public SharedSerializedData
-{
-public:
-    typedef Vector<RefPtr<StringImpl> > PropertyNameList;
-    typedef Vector<SerializedScriptValueData> ValueList;
+static const unsigned maximumFilterRecursion = 40000;
 
-    void set(const Identifier& propertyName, const SerializedScriptValueData& value)
-    {
-        ASSERT(m_names.size() == m_values.size());
-        m_names.append(identifierToString(propertyName).crossThreadString().impl());
-        m_values.append(value);
-    }
+enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
+    ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
 
-    PropertyNameList& names() { return m_names; }
+// These can't be reordered, and any new types must be added to the end of the list
+enum SerializationTag {
+    ArrayTag = 1,
+    ObjectTag = 2,
+    UndefinedTag = 3,
+    NullTag = 4,
+    IntTag = 5,
+    ZeroTag = 6,
+    OneTag = 7,
+    FalseTag = 8,
+    TrueTag = 9,
+    DoubleTag = 10,
+    DateTag = 11,
+    FileTag = 12,
+    FileListTag = 13,
+    ImageDataTag = 14,
+    BlobTag = 15,
+    StringTag = 16,
+    EmptyStringTag = 17,
+    ErrorTag = 255
+};
 
-    ValueList& values() { return m_values; }
 
-    static PassRefPtr<SerializedObject> create()
+static const unsigned int CurrentVersion = 1;
+static const unsigned int TerminatorTag = 0xFFFFFFFF;
+static const unsigned int StringPoolTag = 0xFFFFFFFE;
+
+/*
+ * Object serialization is performed according to the following grammar, all tags
+ * are recorded as a single uint8_t.
+ *
+ * IndexType (used for StringData's constant pool) is the sized unsigned integer type
+ * required to represent the maximum index in the constant pool.
+ *
+ * SerializedValue :- <CurrentVersion:uint32_t> Value
+ * Value :- Array | Object | Terminal
+ *
+ * Array :-
+ *     ArrayTag <length:uint32_t>(<index:uint32_t><value:Value>)* TerminatorTag
+ *
+ * Object :-
+ *     ObjectTag (<name:StringData><value:Value>)* TerminatorTag
+ *
+ * Terminal :-
+ *      UndefinedTag
+ *    | NullTag
+ *    | IntTag <value:int32_t>
+ *    | ZeroTag
+ *    | OneTag
+ *    | DoubleTag <value:double>
+ *    | DateTag <value:double>
+ *    | String
+ *    | EmptyStringTag
+ *    | File
+ *    | FileList
+ *    | ImageData
+ *    | Blob
+ *
+ * String :-
+ *      EmptyStringTag
+ *      StringTag StringData
+ *
+ * StringData :-
+ *      StringPoolTag <cpIndex:IndexType>
+ *      (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed
+ *
+ * File :-
+ *    FileTag FileData
+ *
+ * FileData :-
+ *    <path:StringData> <url:StringData> <type:StringData>
+ *
+ * FileList :-
+ *    FileListTag <length:uint32_t>(<file:FileData>){length}
+ *
+ * ImageData :-
+ *    ImageDataTag <width:uint32_t><height:uint32_t><length:uint32_t><data:uint8_t{length}>
+ *
+ * Blob :-
+ *    BlobTag <url:StringData><type:StringData><size:long long>
+ *
+ */
+
+class CloneBase {
+protected:
+    CloneBase(ExecState* exec)
+        : m_exec(exec)
+        , m_failed(false)
+        , m_timeoutChecker(exec->globalData().timeoutChecker)
     {
-        return adoptRef(new SerializedObject);
     }
 
-    void clear()
+    bool shouldTerminate()
     {
-        m_names.clear();
-        m_values.clear();
+        return m_exec->hadException();
     }
 
-private:
-    SerializedObject() { }
-    PropertyNameList m_names;
-    ValueList m_values;
-};
-
-class SerializedArray : public SharedSerializedData
-{
-    typedef HashMap<unsigned, SerializedScriptValueData, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > SparseMap;
-public:
-    void setIndex(unsigned index, const SerializedScriptValueData& value)
+    unsigned ticksUntilNextCheck()
     {
-        ASSERT(index < m_length);
-        if (index == m_compactStorage.size())
-            m_compactStorage.append(value);
-        else
-            m_sparseStorage.set(index, value);
+        return m_timeoutChecker.ticksUntilNextCheck();
     }
 
-    bool canDoFastRead(unsigned index) const
+    bool didTimeOut()
     {
-        ASSERT(index < m_length);
-        return index < m_compactStorage.size();
+        return m_timeoutChecker.didTimeOut(m_exec);
     }
 
-    const SerializedScriptValueData& getIndex(unsigned index)
+    void throwStackOverflow()
     {
-        ASSERT(index < m_compactStorage.size());
-        return m_compactStorage[index];
+        throwError(m_exec, createStackOverflowError(m_exec));
     }
 
-    SerializedScriptValueData getSparseIndex(unsigned index, bool& hasIndex)
+    void throwInterruptedException()
     {
-        ASSERT(index >= m_compactStorage.size());
-        ASSERT(index < m_length);
-        SparseMap::iterator iter = m_sparseStorage.find(index);
-        if (iter == m_sparseStorage.end()) {
-            hasIndex = false;
-            return SerializedScriptValueData();
-        }
-        hasIndex = true;
-        return iter->second;
+        throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
     }
 
-    unsigned length() const
+    void fail()
     {
-        return m_length;
+        ASSERT_NOT_REACHED();
+        m_failed = true;
     }
 
-    static PassRefPtr<SerializedArray> create(unsigned length)
+    ExecState* m_exec;
+    bool m_failed;
+    TimeoutChecker m_timeoutChecker;
+    MarkedArgumentBuffer m_gcBuffer;
+};
+
+class CloneSerializer : CloneBase {
+public:
+    static bool serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out)
     {
-        return adoptRef(new SerializedArray(length));
+        CloneSerializer serializer(exec, out);
+        return serializer.serialize(value);
     }
 
-    void clear()
+    static bool serialize(String s, Vector<uint8_t>& out)
     {
-        m_compactStorage.clear();
-        m_sparseStorage.clear();
-        m_length = 0;
+        writeLittleEndian(out, CurrentVersion);
+        if (s.isEmpty()) {
+            writeLittleEndian<uint8_t>(out, EmptyStringTag);
+            return true;
+        }
+        writeLittleEndian<uint8_t>(out, StringTag);
+        writeLittleEndian(out, s.length());
+        return writeLittleEndian(out, s.impl()->characters(), s.length());
     }
+
 private:
-    SerializedArray(unsigned length)
-        : m_length(length)
+    CloneSerializer(ExecState* exec, Vector<uint8_t>& out)
+        : CloneBase(exec)
+        , m_buffer(out)
+        , m_emptyIdentifier(exec, UString("", 0))
     {
+        write(CurrentVersion);
     }
 
-    Vector<SerializedScriptValueData> m_compactStorage;
-    SparseMap m_sparseStorage;
-    unsigned m_length;
-};
+    bool serialize(JSValue in);
 
-class SerializedBlob : public SharedSerializedData {
-public:
-    static PassRefPtr<SerializedBlob> create(const Blob* blob)
+    bool isArray(JSValue value)
     {
-        return adoptRef(new SerializedBlob(blob));
+        if (!value.isObject())
+            return false;
+        JSObject* object = asObject(value);
+        return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info);
+    }
+
+    bool startObject(JSObject* object)
+    {
+        // Cycle detection
+        if (!m_cycleDetector.add(object).second) {
+            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+            return false;
+        }
+        m_gcBuffer.append(object);
+        write(ObjectTag);
+        return true;
     }
 
-    const KURL& url() const { return m_url; }
-    const String& type() const { return m_type; }
-    unsigned long long size() const { return m_size; }
 
-private:
-    SerializedBlob(const Blob* blob)
-        : m_url(blob->url().copy())
-        , m_type(blob->type().crossThreadString())
-        , m_size(blob->size())
+    bool startArray(JSArray* array)
     {
+        // Cycle detection
+        if (!m_cycleDetector.add(array).second) {
+            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+            return false;
+        }
+        m_gcBuffer.append(array);
+        unsigned length = array->length();
+        write(ArrayTag);
+        write(length);
+        return true;
     }
 
-    KURL m_url;
-    String m_type;
-    unsigned long long m_size;
-};
+    void endObject(JSObject* object)
+    {
+        write(TerminatorTag);
+        m_cycleDetector.remove(object);
+        m_gcBuffer.removeLast();
+    }
 
-class SerializedFile : public SharedSerializedData {
-public:
-    static PassRefPtr<SerializedFile> create(const File* file)
+    JSValue getSparseIndex(JSArray* array, unsigned propertyName, bool& hasIndex)
     {
-        return adoptRef(new SerializedFile(file));
+        PropertySlot slot(array);
+        if (isJSArray(&m_exec->globalData(), array)) {
+            if (array->JSArray::getOwnPropertySlot(m_exec, propertyName, slot)) {
+                hasIndex = true;
+                return slot.getValue(m_exec, propertyName);
+            }
+        } else if (array->getOwnPropertySlot(m_exec, propertyName, slot)) {
+            hasIndex = true;
+            return slot.getValue(m_exec, propertyName);
+        }
+        hasIndex = false;
+        return jsNull();
     }
 
-    const String& path() const { return m_path; }
-    const KURL& url() const { return m_url; }
-    const String& type() const { return m_type; }
+    JSValue getProperty(JSObject* object, const Identifier& propertyName)
+    {
+        PropertySlot slot(object);
+        if (object->getOwnPropertySlot(m_exec, propertyName, slot))
+            return slot.getValue(m_exec, propertyName);
+        return JSValue();
+    }
 
-private:
-    SerializedFile(const File* file)
-        : m_path(file->path().crossThreadString())
-        , m_url(file->url().copy())
-        , m_type(file->type().crossThreadString())
+    void dumpImmediate(JSValue value)
     {
+        if (value.isNull())
+            write(NullTag);
+        else if (value.isUndefined())
+            write(UndefinedTag);
+        else if (value.isNumber()) {
+            if (value.isInt32()) {
+                if (!value.asInt32())
+                    write(ZeroTag);
+                else if (value.asInt32() == 1)
+                    write(OneTag);
+                else {
+                    write(IntTag);
+                    write(static_cast<uint32_t>(value.asInt32()));
+                }
+            } else {
+                write(DoubleTag);
+                write(value.asDouble());
+            }
+        } else if (value.isBoolean()) {
+            if (value.isTrue())
+                write(TrueTag);
+            else
+                write(FalseTag);
+        }
     }
 
-    String m_path;
-    KURL m_url;
-    String m_type;
-};
+    void dumpString(UString str)
+    {
+        if (str.isEmpty())
+            write(EmptyStringTag);
+        else {
+            write(StringTag);
+            write(str);
+        }
+    }
 
-class SerializedFileList : public SharedSerializedData {
-public:
-    struct FileData {
-        String path;
-        KURL url;
-        String type;
-    };
+    bool dumpIfTerminal(JSValue value)
+    {
+        if (!value.isCell()) {
+            dumpImmediate(value);
+            return true;
+        }
+
+        if (value.isString()) {
+            UString str = asString(value)->value(m_exec);
+            dumpString(str);
+            return true;
+        }
+
+        if (value.isNumber()) {
+            write(DoubleTag);
+            write(value.uncheckedGetNumber());
+            return true;
+        }
+
+        if (value.isObject() && asObject(value)->inherits(&DateInstance::info)) {
+            write(DateTag);
+            write(asDateInstance(value)->internalNumber());
+            return true;
+        }
+
+        if (isArray(value))
+            return false;
+
+        if (value.isObject()) {
+            JSObject* obj = asObject(value);
+            if (obj->inherits(&JSFile::s_info)) {
+                write(FileTag);
+                write(toFile(obj));
+                return true;
+            }
+            if (obj->inherits(&JSFileList::s_info)) {
+                FileList* list = toFileList(obj);
+                write(FileListTag);
+                unsigned length = list->length();
+                write(length);
+                for (unsigned i = 0; i < length; i++)
+                    write(list->item(i));
+                return true;
+            }
+            if (obj->inherits(&JSBlob::s_info)) {
+                write(BlobTag);
+                Blob* blob = toBlob(obj);
+                write(blob->url());
+                write(blob->type());
+                write(blob->size());
+                return true;
+            }
+            if (obj->inherits(&JSImageData::s_info)) {
+                ImageData* data = toImageData(obj);
+                write(ImageDataTag);
+                write(data->width());
+                write(data->height());
+                write(data->data()->length());
+                write(data->data()->data()->data(), data->data()->length());
+                return true;
+            }
 
-    static PassRefPtr<SerializedFileList> create(const FileList* list)
+            CallData unusedData;
+            if (getCallData(value, unusedData) == CallTypeNone)
+                return false;
+        }
+        // Any other types are expected to serialize as null.
+        write(NullTag);
+        return true;
+    }
+
+    void write(SerializationTag tag)
     {
-        return adoptRef(new SerializedFileList(list));
+        writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
     }
 
-    unsigned length() const { return m_files.size(); }
-    const FileData& item(unsigned idx) { return m_files[idx]; }
+    void write(uint8_t c)
+    {
+        writeLittleEndian(m_buffer, c);
+    }
 
-private:
-    SerializedFileList(const FileList* list)
+#if ASSUME_LITTLE_ENDIAN
+    template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
     {
-        unsigned length = list->length();
-        m_files.reserveCapacity(length);
-        for (unsigned i = 0; i < length; i++) {
-            File* file = list->item(i);
-            FileData fileData;
-            fileData.path = file->path().crossThreadString();
-            fileData.url = file->url().copy();
-            fileData.type = file->type().crossThreadString();
-            m_files.append(fileData);
+        if (sizeof(T) == 1)
+            buffer.append(value);
+        else
+            buffer.append(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+    }
+#else
+    template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value)
+    {
+        for (unsigned i = 0; i < sizeof(T); i++) {
+            buffer.append(value & 0xFF);
+            value >>= 8;
         }
     }
+#endif
 
-    Vector<FileData> m_files;
-};
-
-class SerializedImageData : public SharedSerializedData {
-public:
-    static PassRefPtr<SerializedImageData> create(const ImageData* imageData)
+    template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, const T* values, uint32_t length)
     {
-        return adoptRef(new SerializedImageData(imageData));
+        if (length > numeric_limits<uint32_t>::max() / sizeof(T))
+            return false;
+
+#if ASSUME_LITTLE_ENDIAN
+        buffer.append(reinterpret_cast<const uint8_t*>(values), length * sizeof(T));
+#else
+        for (unsigned i = 0; i < length; i++) {
+            T value = values[i];
+            for (unsigned j = 0; j < sizeof(T); j++) {
+                buffer.append(static_cast<uint8_t>(value & 0xFF));
+                value >>= 8;
+            }
+        }
+#endif
+        return true;
     }
-    
-    unsigned width() const { return m_width; }
-    unsigned height() const { return m_height; }
-    WTF::ByteArray* data() const { return m_storage.get(); }
-private:
-    SerializedImageData(const ImageData* imageData)
-        : m_width(imageData->width())
-        , m_height(imageData->height())
+
+    void write(uint32_t i)
     {
-        WTF::ByteArray* array = imageData->data()->data();
-        m_storage = WTF::ByteArray::create(array->length());
-        memcpy(m_storage->data(), array->data(), array->length());
+        writeLittleEndian(m_buffer, i);
     }
-    unsigned m_width;
-    unsigned m_height;
-    RefPtr<WTF::ByteArray> m_storage;
-};
 
-SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedObject> data)
-    : m_type(ObjectType)
-    , m_sharedData(data)
-{
-}
+    void write(double d)
+    {
+        union {
+            double d;
+            int64_t i;
+        } u;
+        u.d = d;
+        writeLittleEndian(m_buffer, u.i);
+    }
 
-SerializedScriptValueData::SerializedScriptValueData(RefPtr<SerializedArray> data)
-    : m_type(ArrayType)
-    , m_sharedData(data)
-{
-}
+    void write(unsigned long long i)
+    {
+        writeLittleEndian(m_buffer, i);
+    }
+    void write(UChar ch)
+    {
+        writeLittleEndian(m_buffer, static_cast<uint16_t>(ch));
+    }
 
-SerializedScriptValueData::SerializedScriptValueData(const FileList* fileList)
-    : m_type(FileListType)
-    , m_sharedData(SerializedFileList::create(fileList))
-{
-}
+    void writeStringIndex(unsigned i)
+    {
+        if (m_constantPool.size() <= 0xFF)
+            write(static_cast<uint8_t>(i));
+        else if (m_constantPool.size() <= 0xFFFF)
+            write(static_cast<uint16_t>(i));
+        else
+            write(static_cast<uint32_t>(i));
+    }
 
-SerializedScriptValueData::SerializedScriptValueData(const ImageData* imageData)
-    : m_type(ImageDataType)
-    , m_sharedData(SerializedImageData::create(imageData))
-{
-}
+    void write(const Identifier& ident)
+    {
+        UString str = ident.ustring();
+        pair<ConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
+        if (!iter.second) {
+            write(StringPoolTag);
+            writeStringIndex(iter.first->second);
+            return;
+        }
 
-SerializedScriptValueData::SerializedScriptValueData(const Blob* blob)
-    : m_type(BlobType)
-    , m_sharedData(SerializedBlob::create(blob))
-{
-}
+        // This condition is unlikely to happen as they would imply an ~8gb
+        // string but we should guard against it anyway
+        if (str.length() >= StringPoolTag) {
+            fail();
+            return;
+        }
 
-SerializedScriptValueData::SerializedScriptValueData(const File* file)
-    : m_type(FileType)
-    , m_sharedData(SerializedFile::create(file))
-{
-}
+        // Guard against overflow
+        if (str.length() > (numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) {
+            fail();
+            return;
+        }
 
-SerializedArray* SharedSerializedData::asArray()
-{
-    return static_cast<SerializedArray*>(this);
-}
+        writeLittleEndian<uint32_t>(m_buffer, str.length());
+        if (!writeLittleEndian<uint16_t>(m_buffer, str.characters(), str.length()))
+            fail();
+    }
 
-SerializedObject* SharedSerializedData::asObject()
-{
-    return static_cast<SerializedObject*>(this);
-}
+    void write(const UString& str)
+    {
+        if (str.isNull())
+            write(m_emptyIdentifier);
+        else
+            write(Identifier(m_exec, str));
+    }
 
-SerializedBlob* SharedSerializedData::asBlob()
-{
-    return static_cast<SerializedBlob*>(this);
-}
+    void write(const String& str)
+    {
+        if (str.isEmpty())
+            write(m_emptyIdentifier);
+        else
+            write(Identifier(m_exec, str.impl()));
+    }
 
-SerializedFile* SharedSerializedData::asFile()
-{
-    return static_cast<SerializedFile*>(this);
-}
+    void write(const File* file)
+    {
+        write(file->path());
+        write(file->url());
+        write(file->type());
+    }
 
-SerializedFileList* SharedSerializedData::asFileList()
-{
-    return static_cast<SerializedFileList*>(this);
-}
+    void write(const uint8_t* data, unsigned length)
+    {
+        m_buffer.append(data, length);
+    }
 
-SerializedImageData* SharedSerializedData::asImageData()
-{
-    return static_cast<SerializedImageData*>(this);
-}
+    Vector<uint8_t>& m_buffer;
+    HashSet<JSObject*> m_cycleDetector;
+    typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> ConstantPool;
+    ConstantPool m_constantPool;
+    Identifier m_emptyIdentifier;
+};
 
-static const unsigned maximumFilterRecursion = 40000;
-enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
-    ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
-template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker& context, typename TreeWalker::InputType in)
+bool CloneSerializer::serialize(JSValue in)
 {
-    typedef typename TreeWalker::InputObject InputObject;
-    typedef typename TreeWalker::InputArray InputArray;
-    typedef typename TreeWalker::OutputObject OutputObject;
-    typedef typename TreeWalker::OutputArray OutputArray;
-    typedef typename TreeWalker::InputType InputType;
-    typedef typename TreeWalker::OutputType OutputType;
-    typedef typename TreeWalker::PropertyList PropertyList;
-
     Vector<uint32_t, 16> indexStack;
     Vector<uint32_t, 16> lengthStack;
-    Vector<PropertyList, 16> propertyStack;
-    Vector<InputObject, 16> inputObjectStack;
-    Vector<InputArray, 16> inputArrayStack;
-    Vector<OutputObject, 16> outputObjectStack;
-    Vector<OutputArray, 16> outputArrayStack;
+    Vector<PropertyNameArray, 16> propertyStack;
+    Vector<JSObject*, 16> inputObjectStack;
+    Vector<JSArray*, 16> inputArrayStack;
     Vector<WalkerState, 16> stateStack;
     WalkerState state = StateUnknown;
-    InputType inValue = in;
-    OutputType outValue = context.null();
-
-    unsigned tickCount = context.ticksUntilNextCheck();
+    JSValue inValue = in;
+    unsigned tickCount = ticksUntilNextCheck();
     while (1) {
         switch (state) {
             arrayStartState:
             case ArrayStartState: {
-                ASSERT(context.isArray(inValue));
+                ASSERT(isArray(inValue));
                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
-                    context.throwStackOverflow();
-                    return context.null();
+                    throwStackOverflow();
+                    return false;
                 }
 
-                InputArray inArray = context.asInputArray(inValue);
-                unsigned length = context.length(inArray);
-                OutputArray outArray = context.createOutputArray(length);
-                if (!context.startArray(inArray, outArray))
-                    return context.null();
+                JSArray* inArray = asArray(inValue);
+                unsigned length = inArray->length();
+                if (!startArray(inArray))
+                    return false;
                 inputArrayStack.append(inArray);
-                outputArrayStack.append(outArray);
                 indexStack.append(0);
                 lengthStack.append(length);
                 // fallthrough
@@ -371,120 +576,114 @@ template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker&
             arrayStartVisitMember:
             case ArrayStartVisitMember: {
                 if (!--tickCount) {
-                    if (context.didTimeOut()) {
-                        context.throwInterruptedException();
-                        return context.null();
+                    if (didTimeOut()) {
+                        throwInterruptedException();
+                        return false;
                     }
-                    tickCount = context.ticksUntilNextCheck();
+                    tickCount = ticksUntilNextCheck();
                 }
 
-                InputArray array = inputArrayStack.last();
+                JSArray* array = inputArrayStack.last();
                 uint32_t index = indexStack.last();
                 if (index == lengthStack.last()) {
-                    InputArray inArray = inputArrayStack.last();
-                    OutputArray outArray = outputArrayStack.last();
-                    context.endArray(inArray, outArray);
-                    outValue = outArray;
+                    endObject(array);
                     inputArrayStack.removeLast();
-                    outputArrayStack.removeLast();
                     indexStack.removeLast();
                     lengthStack.removeLast();
                     break;
                 }
-                if (context.canDoFastRead(array, index))
-                    inValue = context.getIndex(array, index);
+                if (array->canGetIndex(index))
+                    inValue = array->getIndex(index);
                 else {
                     bool hasIndex = false;
-                    inValue = context.getSparseIndex(array, index, hasIndex);
+                    inValue = getSparseIndex(array, index, hasIndex);
                     if (!hasIndex) {
                         indexStack.last()++;
                         goto arrayStartVisitMember;
                     }
                 }
 
-                if (OutputType transformed = context.convertIfTerminal(inValue))
-                    outValue = transformed;
-                else {
-                    stateStack.append(ArrayEndVisitMember);
-                    goto stateUnknown;
+                write(index);
+                if (dumpIfTerminal(inValue)) {
+                    indexStack.last()++;
+                    goto arrayStartVisitMember;
                 }
-                // fallthrough
+                stateStack.append(ArrayEndVisitMember);
+                goto stateUnknown;
             }
             case ArrayEndVisitMember: {
-                OutputArray outArray = outputArrayStack.last();
-                context.putProperty(outArray, indexStack.last(), outValue);
                 indexStack.last()++;
                 goto arrayStartVisitMember;
             }
             objectStartState:
             case ObjectStartState: {
-                ASSERT(context.isObject(inValue));
+                ASSERT(inValue.isObject());
                 if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) {
-                    context.throwStackOverflow();
-                    return context.null();
+                    throwStackOverflow();
+                    return false;
                 }
-                InputObject inObject = context.asInputObject(inValue);
-                OutputObject outObject = context.createOutputObject();
-                if (!context.startObject(inObject, outObject))
-                    return context.null();
+                JSObject* inObject = asObject(inValue);
+                if (!startObject(inObject))
+                    return false;
                 inputObjectStack.append(inObject);
-                outputObjectStack.append(outObject);
                 indexStack.append(0);
-                context.getPropertyNames(inObject, propertyStack);
+                propertyStack.append(PropertyNameArray(m_exec));
+                inObject->getOwnPropertyNames(m_exec, propertyStack.last());
                 // fallthrough
             }
             objectStartVisitMember:
             case ObjectStartVisitMember: {
                 if (!--tickCount) {
-                    if (context.didTimeOut()) {
-                        context.throwInterruptedException();
-                        return context.null();
+                    if (didTimeOut()) {
+                        throwInterruptedException();
+                        return false;
                     }
-                    tickCount = context.ticksUntilNextCheck();
+                    tickCount = ticksUntilNextCheck();
                 }
 
-                InputObject object = inputObjectStack.last();
+                JSObject* object = inputObjectStack.last();
                 uint32_t index = indexStack.last();
-                PropertyList& properties = propertyStack.last();
+                PropertyNameArray& properties = propertyStack.last();
                 if (index == properties.size()) {
-                    InputObject inObject = inputObjectStack.last();
-                    OutputObject outObject = outputObjectStack.last();
-                    context.endObject(inObject, outObject);
-                    outValue = outObject;
+                    endObject(object);
                     inputObjectStack.removeLast();
-                    outputObjectStack.removeLast();
                     indexStack.removeLast();
                     propertyStack.removeLast();
                     break;
                 }
-                inValue = context.getProperty(object, properties[index], index);
+                inValue = getProperty(object, properties[index]);
+                if (shouldTerminate())
+                    return false;
+
+                if (!inValue) {
+                    // Property was removed during serialisation
+                    indexStack.last()++;
+                    goto objectStartVisitMember;
+                }
+                write(properties[index]);
 
-                if (context.shouldTerminate())
-                    return context.null();
+                if (shouldTerminate())
+                    return false;
 
-                if (OutputType transformed = context.convertIfTerminal(inValue))
-                    outValue = transformed;
-                else {
+                if (!dumpIfTerminal(inValue)) {
                     stateStack.append(ObjectEndVisitMember);
                     goto stateUnknown;
                 }
                 // fallthrough
             }
             case ObjectEndVisitMember: {
-                context.putProperty(outputObjectStack.last(), propertyStack.last()[indexStack.last()], outValue);
-                if (context.shouldTerminate())
-                    return context.null();
+                if (shouldTerminate())
+                    return false;
 
                 indexStack.last()++;
                 goto objectStartVisitMember;
             }
             stateUnknown:
             case StateUnknown:
-                if (OutputType transformed = context.convertIfTerminal(inValue)) {
-                    outValue = transformed;
+                if (dumpIfTerminal(inValue))
                     break;
-                }
-                if (context.isArray(inValue))
+
+                if (isArray(inValue))
                     goto arrayStartState;
                 goto objectStartState;
         }
@@ -495,573 +694,569 @@ template <typename TreeWalker> typename TreeWalker::OutputType walk(TreeWalker&
         stateStack.removeLast();
 
         if (!--tickCount) {
-            if (context.didTimeOut()) {
-                context.throwInterruptedException();
-                return context.null();
+            if (didTimeOut()) {
+                throwInterruptedException();
+                return false;
             }
-            tickCount = context.ticksUntilNextCheck();
+            tickCount = ticksUntilNextCheck();
         }
     }
-    return outValue;
-}
-
-struct BaseWalker {
-    BaseWalker(ExecState* exec)
-        : m_exec(exec)
-        , m_timeoutChecker(exec->globalData().timeoutChecker)
-    {
-        m_timeoutChecker.reset();
-    }
-    ExecState* m_exec;
-    TimeoutChecker m_timeoutChecker;
-    MarkedArgumentBuffer m_gcBuffer;
-
-    bool shouldTerminate()
-    {
-        return m_exec->hadException();
-    }
+    if (m_failed)
+        return false;
 
-    unsigned ticksUntilNextCheck()
-    {
-        return m_timeoutChecker.ticksUntilNextCheck();
-    }
+    return true;
+}
 
-    bool didTimeOut()
-    {
-        return m_timeoutChecker.didTimeOut(m_exec);
+class CloneDeserializer : CloneBase {
+public:
+    static String deserializeString(const Vector<uint8_t>& buffer)
+    {
+        const uint8_t* ptr = buffer.begin();
+        const uint8_t* end = buffer.end();
+        uint32_t version;
+        if (!readLittleEndian(ptr, end, version) || version > CurrentVersion)
+            return String();
+        uint8_t tag;
+        if (!readLittleEndian(ptr, end, tag) || tag != StringTag)
+            return String();
+        uint32_t length;
+        if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag)
+            return String();
+        UString str;
+        if (!readString(ptr, end, str, length))
+            return String();
+        return String(str.impl());
+    }
+
+    static JSValue deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
+    {
+        if (!buffer.size())
+            return jsNull();
+        CloneDeserializer deserializer(exec, globalObject, buffer);
+        if (!deserializer.isValid()) {
+            deserializer.throwValidationError();
+            return JSValue();
+        }
+        return deserializer.deserialize();
     }
 
-    void throwStackOverflow()
+private:
+    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer)
+        : CloneBase(exec)
+        , m_globalObject(globalObject)
+        , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
+        , m_ptr(buffer.data())
+        , m_end(buffer.data() + buffer.size())
+        , m_version(0xFFFFFFFF)
     {
-        throwError(m_exec, createStackOverflowError(m_exec));
+        if (!read(m_version))
+            m_version = 0xFFFFFFFF;
     }
 
-    void throwInterruptedException()
-    {
-        throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
-    }
-};
+    JSValue deserialize();
 
-struct SerializingTreeWalker : public BaseWalker {
-    typedef JSValue InputType;
-    typedef JSArray* InputArray;
-    typedef JSObject* InputObject;
-    typedef SerializedScriptValueData OutputType;
-    typedef RefPtr<SerializedArray> OutputArray;
-    typedef RefPtr<SerializedObject> OutputObject;
-    typedef PropertyNameArray PropertyList;
-
-    SerializingTreeWalker(ExecState* exec)
-        : BaseWalker(exec)
+    void throwValidationError()
     {
+        throwError(m_exec, createTypeError(m_exec, "Unable to deserialize data."));
     }
 
-    OutputType null() { return SerializedScriptValueData(); }
+    bool isValid() const { return m_version <= CurrentVersion; }
 
-    bool isArray(JSValue value)
+    template <typename T> bool readLittleEndian(T& value)
     {
-        if (!value.isObject())
+        if (m_failed || !readLittleEndian(m_ptr, m_end, value)) {
+            fail();
             return false;
-        JSObject* object = asObject(value);
-        return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info);
+        }
+        return true;
     }
-
-    bool isObject(JSValue value)
+#if ASSUME_LITTLE_ENDIAN
+    template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
     {
-        return value.isObject();
-    }
+        if (ptr > end - sizeof(value))
+            return false;
 
-    JSArray* asInputArray(JSValue value)
-    {
-        return asArray(value);
+        if (sizeof(T) == 1)
+            value = *ptr++;
+        else {
+            value = *reinterpret_cast<const T*>(ptr);
+            ptr += sizeof(T);
+        }
+        return true;
     }
-
-    JSObject* asInputObject(JSValue value)
+#else
+    template <typename T> static bool readLittleEndian(const uint8_t*& ptr, const uint8_t* end, T& value)
     {
-        return asObject(value);
-    }
+        if (ptr > end - sizeof(value))
+            return false;
 
-    PassRefPtr<SerializedArray> createOutputArray(unsigned length)
-    {
-        return SerializedArray::create(length);
+        if (sizeof(T) == 1)
+            value = *ptr++;
+        else {
+            value = 0;
+            for (unsigned i = 0; i < sizeof(T); i++)
+                value += ((T)*ptr++) << (i * 8);
+        }
+        return true;
     }
+#endif
 
-    PassRefPtr<SerializedObject> createOutputObject()
+    bool read(uint32_t& i)
     {
-        return SerializedObject::create();
+        return readLittleEndian(i);
     }
 
-    uint32_t length(JSValue array)
+    bool read(int32_t& i)
     {
-        ASSERT(array.isObject());
-        JSObject* object = asObject(array);
-        return object->get(m_exec, m_exec->propertyNames().length).toUInt32(m_exec);
+        return readLittleEndian(*reinterpret_cast<uint32_t*>(&i));
     }
 
-    bool canDoFastRead(JSArray* array, unsigned index)
+    bool read(uint16_t& i)
     {
-        return isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index);
+        return readLittleEndian(i);
     }
 
-    JSValue getIndex(JSArray* array, unsigned index)
+    bool read(uint8_t& i)
     {
-        return array->getIndex(index);
+        return readLittleEndian(i);
     }
 
-    JSValue getSparseIndex(JSObject* object, unsigned propertyName, bool& hasIndex)
+    bool read(double& d)
     {
-        PropertySlot slot(object);
-        if (object->getOwnPropertySlot(m_exec, propertyName, slot)) {
-            hasIndex = true;
-            return slot.getValue(m_exec, propertyName);
-        }
-        hasIndex = false;
-        return jsNull();
+        union {
+            double d;
+            uint64_t i64;
+        } u;
+        if (!readLittleEndian(u.i64))
+            return false;
+        d = u.d;
+        return true;
     }
 
-    JSValue getProperty(JSObject* object, const Identifier& propertyName, unsigned)
+    bool read(unsigned long long& i)
     {
-        PropertySlot slot(object);
-        if (object->getOwnPropertySlot(m_exec, propertyName, slot))
-            return slot.getValue(m_exec, propertyName);
-        return jsNull();
+        return readLittleEndian(i);
     }
 
-    SerializedScriptValueData convertIfTerminal(JSValue value)
+    bool readStringIndex(uint32_t& i)
     {
-        if (!value.isCell())
-            return SerializedScriptValueData(value);
-
-        if (value.isString())
-            return SerializedScriptValueData(ustringToString(asString(value)->value(m_exec)));
-
-        if (value.isNumber())
-            return SerializedScriptValueData(SerializedScriptValueData::NumberType, value.uncheckedGetNumber());
-
-        if (value.isObject() && asObject(value)->inherits(&DateInstance::info))
-            return SerializedScriptValueData(SerializedScriptValueData::DateType, asDateInstance(value)->internalNumber());
-
-        if (isArray(value))
-            return SerializedScriptValueData();
-
-        if (value.isObject()) {
-            JSObject* obj = asObject(value);
-            if (obj->inherits(&JSFile::s_info))
-                return SerializedScriptValueData(toFile(obj));
-            if (obj->inherits(&JSBlob::s_info))
-                return SerializedScriptValueData(toBlob(obj));
-            if (obj->inherits(&JSFileList::s_info))
-                return SerializedScriptValueData(toFileList(obj));
-            if (obj->inherits(&JSImageData::s_info))
-                return SerializedScriptValueData(toImageData(obj));
-                
-            CallData unusedData;
-            if (getCallData(value, unusedData) == CallTypeNone)
-                return SerializedScriptValueData();
+        if (m_constantPool.size() <= 0xFF) {
+            uint8_t i8;
+            if (!read(i8))
+                return false;
+            i = i8;
+            return true;
         }
-        // Any other types are expected to serialize as null.
-        return SerializedScriptValueData(jsNull());
-    }
-
-    void getPropertyNames(JSObject* object, Vector<PropertyNameArray, 16>& propertyStack)
-    {
-        propertyStack.append(PropertyNameArray(m_exec));
-        object->getOwnPropertyNames(m_exec, propertyStack.last());
-    }
-
-    void putProperty(RefPtr<SerializedArray> array, unsigned propertyName, const SerializedScriptValueData& value)
-    {
-        array->setIndex(propertyName, value);
+        if (m_constantPool.size() <= 0xFFFF) {
+            uint16_t i16;
+            if (!read(i16))
+                return false;
+            i = i16;
+            return true;
+        }
+        return read(i);
     }
 
-    void putProperty(RefPtr<SerializedObject> object, const Identifier& propertyName, const SerializedScriptValueData& value)
+    static bool readString(const uint8_t*& ptr, const uint8_t* end, UString& str, unsigned length)
     {
-        object->set(propertyName, value);
-    }
+        if (length >= numeric_limits<int32_t>::max() / sizeof(UChar))
+            return false;
 
-    bool startArray(JSArray* inArray, RefPtr<SerializedArray>)
-    {
-        // Cycle detection
-        if (!m_cycleDetector.add(inArray).second) {
-            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+        unsigned size = length * sizeof(UChar);
+        if ((end - ptr) < static_cast<int>(size))
             return false;
+
+#if ASSUME_LITTLE_ENDIAN
+        str = UString(reinterpret_cast<const UChar*>(ptr), length);
+        ptr += length * sizeof(UChar);
+#else
+        Vector<UChar> buffer;
+        buffer.reserveCapacity(length);
+        for (unsigned i = 0; i < length; i++) {
+            uint16_t ch;
+            readLittleEndian(ptr, end, ch);
+            buffer.append(ch);
         }
-        m_gcBuffer.append(inArray);
+        str = UString::adopt(buffer);
+#endif
         return true;
     }
 
-    void endArray(JSArray* inArray, RefPtr<SerializedArray>)
+    bool readStringData(Identifier& ident)
     {
-        m_cycleDetector.remove(inArray);
-        m_gcBuffer.removeLast();
+        bool scratch;
+        return readStringData(ident, scratch);
     }
 
-    bool startObject(JSObject* inObject, RefPtr<SerializedObject>)
+    bool readStringData(Identifier& ident, bool& wasTerminator)
     {
-        // Cycle detection
-        if (!m_cycleDetector.add(inObject).second) {
-            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+        if (m_failed)
+            return false;
+        uint32_t length = 0;
+        if (!read(length))
+            return false;
+        if (length == TerminatorTag) {
+            wasTerminator = true;
             return false;
         }
-        m_gcBuffer.append(inObject);
+        if (length == StringPoolTag) {
+            unsigned index = 0;
+            if (!readStringIndex(index)) {
+                fail();
+                return false;
+            }
+            if (index >= m_constantPool.size()) {
+                fail();
+                return false;
+            }
+            ident = m_constantPool[index];
+            return true;
+        }
+        UString str;
+        if (!readString(m_ptr, m_end, str, length)) {
+            fail();
+            return false;
+        }
+        ident = Identifier(m_exec, str);
+        m_constantPool.append(ident);
         return true;
     }
 
-    void endObject(JSObject* inObject, RefPtr<SerializedObject>)
-    {
-        m_cycleDetector.remove(inObject);
-        m_gcBuffer.removeLast();
-    }
-
-private:
-    HashSet<JSObject*> m_cycleDetector;
-};
-
-SerializedScriptValueData SerializedScriptValueData::serialize(ExecState* exec, JSValue inValue)
-{
-    SerializingTreeWalker context(exec);
-    return walk<SerializingTreeWalker>(context, inValue);
-}
-
-
-struct DeserializingTreeWalker : public BaseWalker {
-    typedef SerializedScriptValueData InputType;
-    typedef RefPtr<SerializedArray> InputArray;
-    typedef RefPtr<SerializedObject> InputObject;
-    typedef JSValue OutputType;
-    typedef JSArray* OutputArray;
-    typedef JSObject* OutputObject;
-    typedef SerializedObject::PropertyNameList PropertyList;
-
-    DeserializingTreeWalker(ExecState* exec, JSGlobalObject* globalObject, bool mustCopy)
-        : BaseWalker(exec)
-        , m_globalObject(globalObject)
-        , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
-        , m_mustCopy(mustCopy)
-    {
-    }
-
-    OutputType null() { return jsNull(); }
-
-    bool isArray(const SerializedScriptValueData& value)
+    SerializationTag readTag()
     {
-        return value.type() == SerializedScriptValueData::ArrayType;
+        if (m_ptr >= m_end)
+            return ErrorTag;
+        return static_cast<SerializationTag>(*m_ptr++);
     }
 
-    bool isObject(const SerializedScriptValueData& value)
+    void putProperty(JSArray* array, unsigned index, JSValue value)
     {
-        return value.type() == SerializedScriptValueData::ObjectType;
-    }
-
-    SerializedArray* asInputArray(const SerializedScriptValueData& value)
-    {
-        return value.asArray();
-    }
-
-    SerializedObject* asInputObject(const SerializedScriptValueData& value)
-    {
-        return value.asObject();
-    }
-
-    JSArray* createOutputArray(unsigned length)
-    {
-        JSArray* array = constructEmptyArray(m_exec, m_globalObject);
-        array->setLength(length);
-        return array;
-    }
-
-    JSObject* createOutputObject()
-    {
-        return constructEmptyObject(m_exec, m_globalObject);
-    }
-
-    uint32_t length(RefPtr<SerializedArray> array)
-    {
-        return array->length();
-    }
-
-    bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index)
-    {
-        return array->canDoFastRead(index);
-    }
-
-    SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index)
-    {
-        return array->getIndex(index);
+        if (array->canSetIndex(index))
+            array->setIndex(index, value);
+        else
+            array->put(m_exec, index, value);
     }
 
-    SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex)
+    void putProperty(JSObject* object, Identifier& property, JSValue value)
     {
-        return array->getSparseIndex(propertyName, hasIndex);
+        object->putDirect(property, value);
     }
 
-    SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex)
+    bool readFile(RefPtr<File>& file)
     {
-        ASSERT(object->names()[propertyIndex] == propertyName);
-        UNUSED_PARAM(propertyName);
-        return object->values()[propertyIndex];
+        Identifier path;
+        if (!readStringData(path))
+            return 0;
+        Identifier url;
+        if (!readStringData(url))
+            return 0;
+        Identifier type;
+        if (!readStringData(type))
+            return 0;
+        if (m_isDOMGlobalObject) {
+            ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
+            file = File::create(scriptExecutionContext, String(path.ustring().impl()), KURL(KURL(), String(url.ustring().impl())), String(type.ustring().impl()));
+        }
+        return true;
     }
 
-    JSValue convertIfTerminal(SerializedScriptValueData& value)
+    JSValue readTerminal()
     {
-        switch (value.type()) {
-            case SerializedScriptValueData::ArrayType:
-            case SerializedScriptValueData::ObjectType:
+        SerializationTag tag = readTag();
+        switch (tag) {
+        case UndefinedTag:
+            return jsUndefined();
+        case NullTag:
+            return jsNull();
+        case IntTag: {
+            int32_t i;
+            if (!read(i))
                 return JSValue();
-            case SerializedScriptValueData::StringType:
-                return jsString(m_exec, value.asString().crossThreadString());
-            case SerializedScriptValueData::ImmediateType:
-                return value.asImmediate();
-            case SerializedScriptValueData::NumberType:
-                return jsNumber(m_exec, value.asDouble());
-            case SerializedScriptValueData::DateType:
-                return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), value.asDouble());
-            case SerializedScriptValueData::BlobType: {
-                if (!m_isDOMGlobalObject)
-                    return jsNull();
-                SerializedBlob* serializedBlob = value.asBlob();
-                ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
-                ASSERT(scriptExecutionContext);
-                return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(scriptExecutionContext, serializedBlob->url(), serializedBlob->type(), serializedBlob->size()));
-            }
-            case SerializedScriptValueData::FileType: {
-                if (!m_isDOMGlobalObject)
-                    return jsNull();
-                SerializedFile* serializedFile = value.asFile();
-                ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
-                ASSERT(scriptExecutionContext);
-                return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), File::create(scriptExecutionContext, serializedFile->path(), serializedFile->url(), serializedFile->type()));
+            return jsNumber(m_exec, i);
+        }
+        case ZeroTag:
+            return jsNumber(m_exec, 0);
+        case OneTag:
+            return jsNumber(m_exec, 1);
+        case FalseTag:
+            return jsBoolean(false);
+        case TrueTag:
+            return jsBoolean(true);
+        case DoubleTag: {
+            double d;
+            if (!read(d))
+                return JSValue();
+            return jsNumber(m_exec, d);
+        }
+        case DateTag: {
+            double d;
+            if (!read(d))
+                return JSValue();
+            return new (m_exec) DateInstance(m_exec, m_globalObject->dateStructure(), d);
+        }
+        case FileTag: {
+            RefPtr<File> file;
+            if (!readFile(file))
+                return JSValue();
+            if (!m_isDOMGlobalObject)
+                return jsNull();
+            return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), file.get());
+        }
+        case FileListTag: {
+            unsigned length = 0;
+            if (!read(length))
+                return JSValue();
+            RefPtr<FileList> result = FileList::create();
+            for (unsigned i = 0; i < length; i++) {
+                RefPtr<File> file;
+                if (!readFile(file))
+                    return JSValue();
+                if (m_isDOMGlobalObject)
+                    result->append(file.get());
             }
-            case SerializedScriptValueData::FileListType: {
-                if (!m_isDOMGlobalObject)
-                    return jsNull();
-                RefPtr<FileList> result = FileList::create();
-                SerializedFileList* serializedFileList = value.asFileList();
-                unsigned length = serializedFileList->length();
-                ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
-                ASSERT(scriptExecutionContext);
-                for (unsigned i = 0; i < length; i++) {
-                    const SerializedFileList::FileData& fileData = serializedFileList->item(i);
-                    result->append(File::create(scriptExecutionContext, fileData.path, fileData.url, fileData.type));
-                }
-                return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
+            if (!m_isDOMGlobalObject)
+                return jsNull();
+            return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
+        }
+        case ImageDataTag: {
+            uint32_t width;
+            if (!read(width))
+                return JSValue();
+            uint32_t height;
+            if (!read(height))
+                return JSValue();
+            uint32_t length;
+            if (!read(length))
+                return JSValue();
+            if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) {
+                fail();
+                return JSValue();
             }
-            case SerializedScriptValueData::ImageDataType: {
-                if (!m_isDOMGlobalObject)
-                    return jsNull();
-                SerializedImageData* serializedImageData = value.asImageData();
-                RefPtr<ImageData> result = ImageData::create(serializedImageData->width(), serializedImageData->height());
-                memcpy(result->data()->data()->data(), serializedImageData->data()->data(), serializedImageData->data()->length());
-                return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
+            if (!m_isDOMGlobalObject) {
+                m_ptr += length;
+                return jsNull();
             }
-            case SerializedScriptValueData::EmptyType:
-                ASSERT_NOT_REACHED();
+            RefPtr<ImageData> result = ImageData::create(width, height);
+            memcpy(result->data()->data()->data(), m_ptr, length);
+            m_ptr += length;
+            return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), result.get());
+        }
+        case BlobTag: {
+            Identifier url;
+            if (!readStringData(url))
+                return JSValue();
+            Identifier type;
+            if (!readStringData(type))
+                return JSValue();
+            unsigned long long size = 0;
+            if (!read(size))
+                return JSValue();
+            if (!m_isDOMGlobalObject)
                 return jsNull();
+            ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject())->scriptExecutionContext();
+            ASSERT(scriptExecutionContext);
+            return toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_globalObject), Blob::create(scriptExecutionContext, KURL(KURL(), url.ustring().impl()), String(type.ustring().impl()), size));
+        }
+        case StringTag: {
+            Identifier ident;
+            if (!readStringData(ident))
+                return JSValue();
+            return jsString(m_exec, ident.ustring());
+        }
+        case EmptyStringTag:
+            return jsEmptyString(&m_exec->globalData());
+        default:
+            m_ptr--; // Push the tag back
+            return JSValue();
         }
-        ASSERT_NOT_REACHED();
-        return jsNull();
-    }
-
-    void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties)
-    {
-        properties.append(object->names());
-    }
-
-    void putProperty(JSArray* array, unsigned propertyName, JSValue value)
-    {
-        array->put(m_exec, propertyName, value);
-    }
-
-    void putProperty(JSObject* object, const RefPtr<StringImpl> propertyName, JSValue value)
-    {
-        object->putDirect(Identifier(m_exec, stringToUString(String(propertyName))), value);
-    }
-
-    bool startArray(RefPtr<SerializedArray>, JSArray* outArray)
-    {
-        m_gcBuffer.append(outArray);
-        return true;
-    }
-    void endArray(RefPtr<SerializedArray>, JSArray*)
-    {
-        m_gcBuffer.removeLast();
-    }
-    bool startObject(RefPtr<SerializedObject>, JSObject* outObject)
-    {
-        m_gcBuffer.append(outObject);
-        return true;
-    }
-    void endObject(RefPtr<SerializedObject>, JSObject*)
-    {
-        m_gcBuffer.removeLast();
     }
 
-private:
-    void* operator new(size_t);
     JSGlobalObject* m_globalObject;
     bool m_isDOMGlobalObject;
-    bool m_mustCopy;
+    const uint8_t* m_ptr;
+    const uint8_t* m_end;
+    unsigned m_version;
+    Vector<Identifier> m_constantPool;
 };
 
-JSValue SerializedScriptValueData::deserialize(ExecState* exec, JSGlobalObject* global, bool mustCopy) const
+JSValue CloneDeserializer::deserialize()
 {
-    DeserializingTreeWalker context(exec, global, mustCopy);
-    return walk<DeserializingTreeWalker>(context, *this);
-}
-
-struct TeardownTreeWalker {
-    typedef SerializedScriptValueData InputType;
-    typedef RefPtr<SerializedArray> InputArray;
-    typedef RefPtr<SerializedObject> InputObject;
-    typedef bool OutputType;
-    typedef bool OutputArray;
-    typedef bool OutputObject;
-    typedef SerializedObject::PropertyNameList PropertyList;
-
-    bool shouldTerminate()
-    {
-        return false;
-    }
-
-    unsigned ticksUntilNextCheck()
-    {
-        return 0xFFFFFFFF;
-    }
-
-    bool didTimeOut()
-    {
-        return false;
-    }
-
-    void throwStackOverflow()
-    {
-    }
-
-    void throwInterruptedException()
-    {
-    }
-
-    bool null() { return false; }
-
-    bool isArray(const SerializedScriptValueData& value)
-    {
-        return value.type() == SerializedScriptValueData::ArrayType;
-    }
-
-    bool isObject(const SerializedScriptValueData& value)
-    {
-        return value.type() == SerializedScriptValueData::ObjectType;
-    }
-
-    SerializedArray* asInputArray(const SerializedScriptValueData& value)
-    {
-        return value.asArray();
-    }
-
-    SerializedObject* asInputObject(const SerializedScriptValueData& value)
-    {
-        return value.asObject();
-    }
-
-    bool createOutputArray(unsigned)
-    {
-        return false;
-    }
+    Vector<uint32_t, 16> indexStack;
+    Vector<Identifier, 16> propertyNameStack;
+    Vector<JSObject*, 16> outputObjectStack;
+    Vector<JSArray*, 16> outputArrayStack;
+    Vector<WalkerState, 16> stateStack;
+    WalkerState state = StateUnknown;
+    JSValue outValue;
 
-    bool createOutputObject()
-    {
-        return false;
-    }
+    unsigned tickCount = ticksUntilNextCheck();
+    while (1) {
+        switch (state) {
+        arrayStartState:
+        case ArrayStartState: {
+            uint32_t length;
+            if (!read(length)) {
+                fail();
+                goto error;
+            }
+            JSArray* outArray = constructEmptyArray(m_exec, m_globalObject);
+            outArray->setLength(length);
+            m_gcBuffer.append(outArray);
+            outputArrayStack.append(outArray);
+            // fallthrough
+        }
+        arrayStartVisitMember:
+        case ArrayStartVisitMember: {
+            if (!--tickCount) {
+                if (didTimeOut()) {
+                    throwInterruptedException();
+                    return JSValue();
+                }
+                tickCount = ticksUntilNextCheck();
+            }
 
-    uint32_t length(RefPtr<SerializedArray> array)
-    {
-        return array->length();
-    }
+            uint32_t index;
+            if (!read(index)) {
+                fail();
+                goto error;
+            }
+            if (index == TerminatorTag) {
+                JSArray* outArray = outputArrayStack.last();
+                m_gcBuffer.removeLast();
+                outValue = outArray;
+                outputArrayStack.removeLast();
+                break;
+            }
 
-    bool canDoFastRead(RefPtr<SerializedArray> array, unsigned index)
-    {
-        return array->canDoFastRead(index);
-    }
+            if (JSValue terminal = readTerminal()) {
+                putProperty(outputArrayStack.last(), index, terminal);
+                goto arrayStartVisitMember;
+            }
+            if (m_failed)
+                goto error;
+            indexStack.append(index);
+            stateStack.append(ArrayEndVisitMember);
+            goto stateUnknown;
+        }
+        case ArrayEndVisitMember: {
+            JSArray* outArray = outputArrayStack.last();
+            putProperty(outArray, indexStack.last(), outValue);
+            indexStack.removeLast();
+            goto arrayStartVisitMember;
+        }
+        objectStartState:
+        case ObjectStartState: {
+            if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion) {
+                throwStackOverflow();
+                return JSValue();
+            }
+            JSObject* outObject = constructEmptyObject(m_exec, m_globalObject);
+            m_gcBuffer.append(outObject);
+            outputObjectStack.append(outObject);
+            // fallthrough
+        }
+        objectStartVisitMember:
+        case ObjectStartVisitMember: {
+            if (!--tickCount) {
+                if (didTimeOut()) {
+                    throwInterruptedException();
+                    return JSValue();
+                }
+                tickCount = ticksUntilNextCheck();
+            }
 
-    SerializedScriptValueData getIndex(RefPtr<SerializedArray> array, unsigned index)
-    {
-        return array->getIndex(index);
-    }
+            Identifier ident;
+            bool wasTerminator = false;
+            if (!readStringData(ident, wasTerminator)) {
+                if (!wasTerminator)
+                    goto error;
+                JSObject* outObject = outputObjectStack.last();
+                m_gcBuffer.removeLast();
+                outValue = outObject;
+                outputObjectStack.removeLast();
+                break;
+            }
 
-    SerializedScriptValueData getSparseIndex(RefPtr<SerializedArray> array, unsigned propertyName, bool& hasIndex)
-    {
-        return array->getSparseIndex(propertyName, hasIndex);
-    }
+            if (JSValue terminal = readTerminal()) {
+                putProperty(outputObjectStack.last(), ident, terminal);
+                goto objectStartVisitMember;
+            }
+            stateStack.append(ObjectEndVisitMember);
+            propertyNameStack.append(ident);
+            goto stateUnknown;
+        }
+        case ObjectEndVisitMember: {
+            putProperty(outputObjectStack.last(), propertyNameStack.last(), outValue);
+            propertyNameStack.removeLast();
+            goto objectStartVisitMember;
+        }
+        stateUnknown:
+        case StateUnknown:
+            if (JSValue terminal = readTerminal()) {
+                outValue = terminal;
+                break;
+            }
+            SerializationTag tag = readTag();
+            if (tag == ArrayTag)
+                goto arrayStartState;
+            if (tag == ObjectTag)
+                goto objectStartState;
+            goto error;
+        }
+        if (stateStack.isEmpty())
+            break;
 
-    SerializedScriptValueData getProperty(RefPtr<SerializedObject> object, const RefPtr<StringImpl>& propertyName, unsigned propertyIndex)
-    {
-        ASSERT(object->names()[propertyIndex] == propertyName);
-        UNUSED_PARAM(propertyName);
-        return object->values()[propertyIndex];
-    }
+        state = stateStack.last();
+        stateStack.removeLast();
 
-    bool convertIfTerminal(SerializedScriptValueData& value)
-    {
-        switch (value.type()) {
-            case SerializedScriptValueData::ArrayType:
-            case SerializedScriptValueData::ObjectType:
-                return false;
-            case SerializedScriptValueData::StringType:
-            case SerializedScriptValueData::ImmediateType:
-            case SerializedScriptValueData::NumberType:
-            case SerializedScriptValueData::DateType:
-            case SerializedScriptValueData::EmptyType:
-            case SerializedScriptValueData::BlobType:
-            case SerializedScriptValueData::FileType:
-            case SerializedScriptValueData::FileListType:
-            case SerializedScriptValueData::ImageDataType:
-                return true;
+        if (!--tickCount) {
+            if (didTimeOut()) {
+                throwInterruptedException();
+                return JSValue();
+            }
+            tickCount = ticksUntilNextCheck();
         }
-        ASSERT_NOT_REACHED();
-        return true;
     }
+    ASSERT(outValue);
+    ASSERT(!m_failed);
+    return outValue;
+error:
+    fail();
+    throwValidationError();
+    return JSValue();
+}
 
-    void getPropertyNames(RefPtr<SerializedObject> object, Vector<SerializedObject::PropertyNameList, 16>& properties)
-    {
-        properties.append(object->names());
-    }
 
-    void putProperty(bool, unsigned, bool)
-    {
-    }
 
-    void putProperty(bool, const RefPtr<StringImpl>&, bool)
-    {
-    }
+SerializedScriptValue::~SerializedScriptValue()
+{
+}
 
-    bool startArray(RefPtr<SerializedArray>, bool)
-    {
-        return true;
-    }
-    void endArray(RefPtr<SerializedArray> array, bool)
-    {
-        array->clear();
-    }
-    bool startObject(RefPtr<SerializedObject>, bool)
-    {
-        return true;
-    }
-    void endObject(RefPtr<SerializedObject> object, bool)
-    {
-        object->clear();
-    }
-};
+SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
+{
+    m_data.swap(buffer);
+}
 
-void SerializedScriptValueData::tearDownSerializedData()
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value)
 {
-    if (m_sharedData && m_sharedData->refCount() > 1)
-        return;
-    TeardownTreeWalker context;
-    walk<TeardownTreeWalker>(context, *this);
+    Vector<uint8_t> buffer;
+    if (!CloneSerializer::serialize(exec, value, buffer))
+        return 0;
+    return adoptRef(new SerializedScriptValue(buffer));
 }
 
-SerializedScriptValue::~SerializedScriptValue()
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
+{
+    Vector<uint8_t> buffer;
+    return adoptRef(new SerializedScriptValue(buffer));
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(String string)
 {
+    Vector<uint8_t> buffer;
+    if (!CloneSerializer::serialize(string, buffer))
+        return 0;
+    return adoptRef(new SerializedScriptValue(buffer));
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception)
@@ -1076,14 +1271,18 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef ori
         exec->clearException();
         return 0;
     }
-    
+    ASSERT(serializedValue);
     return serializedValue;
 }
 
-SerializedScriptValue* SerializedScriptValue::nullValue() 
+String SerializedScriptValue::toString()
+{
+    return CloneDeserializer::deserializeString(m_data);
+}
+
+JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject)
 {
-    DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, nullValue, (SerializedScriptValue::create()));
-    return nullValue.get();
+    return CloneDeserializer::deserialize(exec, globalObject, m_data);
 }
 
 JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
@@ -1097,7 +1296,14 @@ JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, J
         exec->clearException();
         return 0;
     }
+    ASSERT(value);
     return toRef(exec, value);
 }
 
+SerializedScriptValue* SerializedScriptValue::nullValue()
+{
+    DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, emptyValue, (SerializedScriptValue::create()));
+    return emptyValue.get();
+}
+
 }
diff --git a/WebCore/bindings/js/SerializedScriptValue.h b/WebCore/bindings/js/SerializedScriptValue.h
index 32ce418..b41d9a3 100644
--- a/WebCore/bindings/js/SerializedScriptValue.h
+++ b/WebCore/bindings/js/SerializedScriptValue.h
@@ -28,229 +28,34 @@
 #define SerializedScriptValue_h
 
 #include "ScriptValue.h"
+#include <wtf/Forward.h>
 
 typedef const struct OpaqueJSContext* JSContextRef;
 typedef const struct OpaqueJSValue* JSValueRef;
 
 namespace WebCore {
-    class Blob;
-    class File;
-    class FileList;
-    class ImageData;
-    class SerializedArray;
-    class SerializedBlob;
-    class SerializedFile;
-    class SerializedFileList;
-    class SerializedImageData;
-    class SerializedObject;
 
-    class SharedSerializedData : public RefCounted<SharedSerializedData> {
-    public:
-        virtual ~SharedSerializedData() { }
-        SerializedArray* asArray();
-        SerializedObject* asObject();
-        SerializedBlob* asBlob();
-        SerializedFile* asFile();
-        SerializedFileList* asFileList();
-        SerializedImageData* asImageData();
-    };
+class SharedBuffer;
 
-    class SerializedScriptValue;
+class SerializedScriptValue : public RefCounted<SerializedScriptValue> {
+public:
+    static PassRefPtr<SerializedScriptValue> create(JSC::ExecState* exec, JSC::JSValue value);
+    static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef value, JSValueRef* exception);
+    static PassRefPtr<SerializedScriptValue> create(String string);
+    static PassRefPtr<SerializedScriptValue> create();
+    static SerializedScriptValue* nullValue();
 
-    class SerializedScriptValueData {
-    public:
-        enum SerializedType {
-            EmptyType,
-            DateType,
-            NumberType,
-            ImmediateType,
-            ObjectType,
-            ArrayType,
-            StringType,
-            BlobType,
-            FileType,
-            FileListType,
-            ImageDataType
-        };
+    JSC::JSValue deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject);
+    String toString();
+    JSValueRef deserialize(JSContextRef, JSValueRef* exception);
+    
+    ~SerializedScriptValue();
 
-        SerializedType type() const { return m_type; }
-        static SerializedScriptValueData serialize(JSC::ExecState*, JSC::JSValue);
-        JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*, bool mustCopy) const;
+private:
+    SerializedScriptValue(Vector<unsigned char>&);
+    Vector<unsigned char> m_data;
+};
 
-        ~SerializedScriptValueData()
-        {
-            if (m_sharedData)
-                tearDownSerializedData();
-        }
-
-        SerializedScriptValueData()
-            : m_type(EmptyType)
-        {
-        }
-
-        explicit SerializedScriptValueData(const String& string)
-            : m_type(StringType)
-            , m_string(string.crossThreadString()) // FIXME: Should be able to just share the StringImpl
-        {
-        }
-
-        explicit SerializedScriptValueData(const Blob*);
-        explicit SerializedScriptValueData(const File*);
-        explicit SerializedScriptValueData(const FileList*);
-        explicit SerializedScriptValueData(const ImageData*);
-
-        explicit SerializedScriptValueData(JSC::JSValue value)
-            : m_type(ImmediateType)
-        {
-            ASSERT(!value.isCell());
-            m_data.m_immediate = JSC::JSValue::encode(value);
-        }
-
-        SerializedScriptValueData(SerializedType type, double value)
-            : m_type(type)
-        {
-            m_data.m_double = value;
-        }
-
-        SerializedScriptValueData(RefPtr<SerializedObject>);
-        SerializedScriptValueData(RefPtr<SerializedArray>);
-
-        JSC::JSValue asImmediate() const
-        {
-            ASSERT(m_type == ImmediateType);
-            return JSC::JSValue::decode(m_data.m_immediate);
-        }
-
-        double asDouble() const
-        {
-            ASSERT(m_type == NumberType || m_type == DateType);
-            return m_data.m_double;
-        }
-
-        String asString() const
-        {
-            ASSERT(m_type == StringType);
-            return m_string;
-        }
-
-        SerializedObject* asObject() const
-        {
-            ASSERT(m_type == ObjectType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asObject();
-        }
-
-        SerializedArray* asArray() const
-        {
-            ASSERT(m_type == ArrayType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asArray();
-        }
-
-        SerializedBlob* asBlob() const
-        {
-            ASSERT(m_type == BlobType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asBlob();
-        }
-
-        SerializedFile* asFile() const
-        {
-            ASSERT(m_type == FileType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asFile();
-        }
-
-        SerializedFileList* asFileList() const
-        {
-            ASSERT(m_type == FileListType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asFileList();
-        }
-        
-        SerializedImageData* asImageData() const
-        {
-            ASSERT(m_type == ImageDataType);
-            ASSERT(m_sharedData);
-            return m_sharedData->asImageData();
-        }
-
-        operator bool() const { return m_type != EmptyType; }
-
-        SerializedScriptValueData release()
-        {
-            SerializedScriptValueData result = *this;
-            *this = SerializedScriptValueData();
-            return result;
-        }
-
-    private:
-        void tearDownSerializedData();
-        SerializedType m_type;
-        RefPtr<SharedSerializedData> m_sharedData;
-        String m_string;
-        union {
-            double m_double;
-            JSC::EncodedJSValue m_immediate;
-        } m_data;
-    };
-
-    class SerializedScriptValue : public RefCounted<SerializedScriptValue> {
-    public:
-        static PassRefPtr<SerializedScriptValue> create(JSC::ExecState* exec, JSC::JSValue value)
-        {
-            return adoptRef(new SerializedScriptValue(SerializedScriptValueData::serialize(exec, value)));
-        }
-
-        static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef value, JSValueRef* exception);
-
-        static PassRefPtr<SerializedScriptValue> create(String string)
-        {
-            return adoptRef(new SerializedScriptValue(SerializedScriptValueData(string)));
-        }
-
-        static PassRefPtr<SerializedScriptValue> create()
-        {
-            return adoptRef(new SerializedScriptValue(SerializedScriptValueData()));
-        }
-        
-        static SerializedScriptValue* nullValue();
-
-        PassRefPtr<SerializedScriptValue> release()
-        {
-            PassRefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_value));
-            m_value = SerializedScriptValueData();
-            result->m_mustCopy = true;
-            return result;
-        }
-
-        String toString()
-        {
-            if (m_value.type() != SerializedScriptValueData::StringType)
-                return "";
-            return m_value.asString();
-        }
-
-        JSC::JSValue deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
-        {
-            if (!m_value)
-                return JSC::jsNull();
-            return m_value.deserialize(exec, globalObject, m_mustCopy);
-        }
-
-        JSValueRef deserialize(JSContextRef, JSValueRef* exception);
-        ~SerializedScriptValue();
-
-    private:
-        SerializedScriptValue(SerializedScriptValueData value)
-            : m_value(value)
-            , m_mustCopy(false)
-        {
-        }
-
-        SerializedScriptValueData m_value;
-        bool m_mustCopy;
-    };
 }
 
 #endif // SerializedScriptValue_h
diff --git a/WebCore/dom/MessagePortChannel.cpp b/WebCore/dom/MessagePortChannel.cpp
index e1a3ac6..cb431a1 100644
--- a/WebCore/dom/MessagePortChannel.cpp
+++ b/WebCore/dom/MessagePortChannel.cpp
@@ -39,7 +39,7 @@ PassOwnPtr<MessagePortChannel::EventData> MessagePortChannel::EventData::create(
 }
 
 MessagePortChannel::EventData::EventData(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
-    : m_message(message->release())
+    : m_message(message)
     , m_channels(channels)
 {
 }
diff --git a/WebCore/workers/WorkerMessagingProxy.cpp b/WebCore/workers/WorkerMessagingProxy.cpp
index 21994cc..10700c6 100644
--- a/WebCore/workers/WorkerMessagingProxy.cpp
+++ b/WebCore/workers/WorkerMessagingProxy.cpp
@@ -54,7 +54,7 @@ public:
 
 private:
     MessageWorkerContextTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
-        : m_message(message->release())
+        : m_message(message)
         , m_channels(channels)
     {
     }
@@ -82,7 +82,7 @@ public:
 
 private:
     MessageWorkerTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels, WorkerMessagingProxy* messagingProxy)
-        : m_message(message->release())
+        : m_message(message)
         , m_channels(channels)
         , m_messagingProxy(messagingProxy)
     {

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list