[SCM] WebKit Debian packaging branch, debian/experimental, updated. debian/1.3.8-1-142-g786665c

oliver at apple.com oliver at apple.com
Mon Dec 27 16:25:03 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit e864155a84cfc2c72183bb0ba0f939f80641eddb
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Dec 20 22:40:37 2010 +0000

    2010-12-20  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Darin Adler.
    
            Need to support serialisation of cyclic graphs in the internal structured cloning algorithm
            https://bugs.webkit.org/show_bug.cgi?id=51353
    
            Update test to cover correct behaviour, and extend to test for actual graph construction.
    
            * fast/dom/Window/window-postmessage-clone-expected.txt:
            * fast/dom/Window/window-postmessage-clone.html:
    2010-12-20  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Darin Adler.
    
            Need to support serialisation of cyclic graphs in the internal structured cloning algorithm
            https://bugs.webkit.org/show_bug.cgi?id=51353
    
            The Internal Structured Clone algorithm has been changed to allow (and
            correctly clone) cyclic graphs.  This patch updates our implementation
            to provide that functionality.
    
            I've bumped the serialization version number, and added ObjectReferenceTag
            to represent references to objects that have already been seen.
    
            * bindings/js/SerializedScriptValue.cpp:
            (WebCore::CloneSerializer::startObjectInternal):
              Now that we have something a bit more complex than cycle checking
              I've replaced the duplicate code in startObject and startArray with
              a shared function that implements that logic to plant an object
              reference
            (WebCore::CloneSerializer::startObject):
            (WebCore::CloneSerializer::startArray):
              Lift out duplicate code
            (WebCore::CloneSerializer::endObject):
              Can't remove objects from the gcbuffer now as they need to remain live
              so we can identify graphs
            (WebCore::CloneSerializer::writeStringIndex):
            (WebCore::CloneSerializer::writeObjectIndex):
            (WebCore::CloneSerializer::writeConstantPoolIndex):
            (WebCore::CloneSerializer::write):
            (WebCore::CloneSerializer::serialize):
            (WebCore::CloneDeserializer::readStringIndex):
            (WebCore::CloneDeserializer::readConstantPoolIndex):
            (WebCore::CloneDeserializer::readTerminal):
            (WebCore::CloneDeserializer::deserialize):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@74368 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 829df3d..e9bd05a 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2010-12-20  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Darin Adler.
+
+        Need to support serialisation of cyclic graphs in the internal structured cloning algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=51353
+
+        Update test to cover correct behaviour, and extend to test for actual graph construction.
+
+        * fast/dom/Window/window-postmessage-clone-expected.txt:
+        * fast/dom/Window/window-postmessage-clone.html:
+
 2010-12-20  Abhishek Arya  <inferno at chromium.org>
 
         Reviewed by James Robinson.
diff --git a/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt b/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
index 7b4fc89..a5e117e 100644
--- a/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
+++ b/LayoutTests/fast/dom/Window/window-postmessage-clone-expected.txt
@@ -1,6 +1,4 @@
 Tests that we clone object hierarchies
-PASS: 'postMessage(cyclicObject)' threw TypeError: Cannot post cyclic structures.
-PASS: 'postMessage(cyclicArray)' threw TypeError: Cannot post cyclic structures.
 PASS: 'postMessage(reallyDeepArray)' threw RangeError: Maximum call stack size exceeded.
 PASS: 'postMessage(window)' threw TypeError: Type error
 PASS: eventData is null of type object
@@ -25,6 +23,10 @@ PASS: eventData is ,,1 of type object
 PASS: eventData is null of type object
 PASS: eventData is 2009-02-13T23:31:30.000Z of type object
 PASS: eventData is [object Object] of type object
+PASS: eventData is === to eventData.self
+PASS: eventData is === to eventData[0]
+PASS: eventData.graph1 is === to eventData.graph2
+PASS: eventData[0] is === to eventData[1]
 PASS: eventData is [object Array](default toString threw RangeError: Maximum call stack size exceeded.) of type object
 PASS: eventData is [object File] of type object
 PASS: eventData is [object FileList] of type object
diff --git a/LayoutTests/fast/dom/Window/window-postmessage-clone.html b/LayoutTests/fast/dom/Window/window-postmessage-clone.html
index 6733e09..bf50139 100644
--- a/LayoutTests/fast/dom/Window/window-postmessage-clone.html
+++ b/LayoutTests/fast/dom/Window/window-postmessage-clone.html
@@ -80,11 +80,37 @@ function shouldBe(actual, expected)
         console.innerHTML += "FAIL: " + actual + " is " + actualValue + " should be " + expectedValue + " of type " + typeof expectedValue + "<br>";
 }
 
+function shouldBeIdentical(actual, expected)
+{
+    var actualValue = eval(actual);
+    var expectedValue = eval(expected);
+    if (actualValue === expectedValue)
+        console.innerHTML += "PASS: " + actual + " is === to " + expected + "<br>";
+    else
+        console.innerHTML += "FAIL: " + actual + " is not === to " + expected + "<br>";
+}
+
 function onmessage(evt) {
     eventData = evt.data;
     if (evt.data !== evt.data)
         console.innerHTML += "MessageEvent.data does not produce the same value on multiple queries.<br>";
-    shouldBe("eventData", messages.shift());
+    var message = messages.shift();
+    switch (message) {
+    case "cyclicObject":
+        shouldBeIdentical("eventData", "eventData.self");
+        break;
+    case "cyclicArray":
+        shouldBeIdentical("eventData", "eventData[0]");
+        break;
+    case "objectGraph":
+        shouldBeIdentical("eventData.graph1", "eventData.graph2");
+        break;
+    case "arrayGraph":
+        shouldBeIdentical("eventData[0]", "eventData[1]");
+        break;
+    default:
+        shouldBe("eventData", message);
+    }
 
     if (safeToString(evt.data) == 'done' && window.layoutTestController)
         layoutTestController.notifyDone();
@@ -141,10 +167,17 @@ tryPostMessage('new Date(1234567890000)');
 tryPostMessage('new ConstructorWithPrototype("foo")', false, '({field:"foo"})');
 cyclicObject={};
 cyclicObject.self = cyclicObject;
-tryPostMessage('cyclicObject', true);
+tryPostMessage('cyclicObject', false, "cyclicObject");
 cyclicArray=[];
 cyclicArray[0] = cyclicArray;
-tryPostMessage('cyclicArray', true);
+tryPostMessage('cyclicArray', false, "cyclicArray");
+objectGraph = {};
+object = {};
+objectGraph.graph1 = object;
+objectGraph.graph2 = object;
+tryPostMessage('objectGraph', false, "objectGraph");
+arrayGraph = [object, object];
+tryPostMessage('arrayGraph', false, "arrayGraph");
 deepArray=[];
 for (var i = 0; i < 10000; i++)
     deepArray=[deepArray];
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 81d8aaa..e2ba1af 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,39 @@
+2010-12-20  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Darin Adler.
+
+        Need to support serialisation of cyclic graphs in the internal structured cloning algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=51353
+
+        The Internal Structured Clone algorithm has been changed to allow (and
+        correctly clone) cyclic graphs.  This patch updates our implementation
+        to provide that functionality.
+
+        I've bumped the serialization version number, and added ObjectReferenceTag
+        to represent references to objects that have already been seen.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneSerializer::startObjectInternal):
+          Now that we have something a bit more complex than cycle checking
+          I've replaced the duplicate code in startObject and startArray with
+          a shared function that implements that logic to plant an object
+          reference
+        (WebCore::CloneSerializer::startObject):
+        (WebCore::CloneSerializer::startArray):
+          Lift out duplicate code
+        (WebCore::CloneSerializer::endObject):
+          Can't remove objects from the gcbuffer now as they need to remain live
+          so we can identify graphs
+        (WebCore::CloneSerializer::writeStringIndex):
+        (WebCore::CloneSerializer::writeObjectIndex):
+        (WebCore::CloneSerializer::writeConstantPoolIndex):
+        (WebCore::CloneSerializer::write):
+        (WebCore::CloneSerializer::serialize):
+        (WebCore::CloneDeserializer::readStringIndex):
+        (WebCore::CloneDeserializer::readConstantPoolIndex):
+        (WebCore::CloneDeserializer::readTerminal):
+        (WebCore::CloneDeserializer::deserialize):
+
 2010-12-20  Xan Lopez  <xlopez at igalia.com>
 
         Reviewed by Gustavo Noronha.
diff --git a/WebCore/bindings/js/SerializedScriptValue.cpp b/WebCore/bindings/js/SerializedScriptValue.cpp
index 65abd75..bfa2b75 100644
--- a/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -86,11 +86,17 @@ enum SerializationTag {
     StringTag = 16,
     EmptyStringTag = 17,
     RegExpTag = 18,
+    ObjectReferenceTag = 19,
     ErrorTag = 255
 };
 
-
-static const unsigned int CurrentVersion = 1;
+/* CurrentVersion tracks the serialization version so that persistant stores
+ * are able to correctly bail out in the case of encountering newer formats.
+ *
+ * Initial version was 1.
+ * Version 2. added the ObjectReferenceTag and support for serialization of cyclic graphs.
+ */
+static const unsigned int CurrentVersion = 2;
 static const unsigned int TerminatorTag = 0xFFFFFFFF;
 static const unsigned int StringPoolTag = 0xFFFFFFFE;
 
@@ -98,8 +104,9 @@ 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.
+ * IndexType (used for the object pool and StringData's constant pool) is the
+ * minimum sized unsigned integer type required to represent the maximum index
+ * in the constant pool.
  *
  * SerializedValue :- <CurrentVersion:uint32_t> Value
  * Value :- Array | Object | Terminal
@@ -124,6 +131,7 @@ static const unsigned int StringPoolTag = 0xFFFFFFFE;
  *    | FileList
  *    | ImageData
  *    | Blob
+ *    | ObjectReferenceTag <opIndex:IndexType>
  *
  * String :-
  *      EmptyStringTag
@@ -237,38 +245,45 @@ private:
         return isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info);
     }
 
-    bool startObject(JSObject* object)
+    bool startObjectInternal(JSObject* object)
     {
-        // Cycle detection
-        if (!m_cycleDetector.add(object).second) {
-            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+        // Record object for graph reconstruction
+        pair<ObjectPool::iterator, bool> iter = m_objectPool.add(object, m_objectPool.size());
+        
+        // Handle duplicate references
+        if (!iter.second) {
+            write(ObjectReferenceTag);
+            ASSERT(static_cast<int32_t>(iter.first->second) < m_objectPool.size());
+            writeObjectIndex(iter.first->second);
             return false;
         }
+        
         m_gcBuffer.append(object);
-        write(ObjectTag);
         return true;
     }
 
+    bool startObject(JSObject* object)
+    {
+        if (!startObjectInternal(object))
+            return false;
+        write(ObjectTag);
+        return true;
+    }
 
     bool startArray(JSArray* array)
     {
-        // Cycle detection
-        if (!m_cycleDetector.add(array).second) {
-            throwError(m_exec, createTypeError(m_exec, "Cannot post cyclic structures."));
+        if (!startObjectInternal(array))
             return false;
-        }
-        m_gcBuffer.append(array);
+
         unsigned length = array->length();
         write(ArrayTag);
         write(length);
         return true;
     }
 
-    void endObject(JSObject* object)
+    void endObject()
     {
         write(TerminatorTag);
-        m_cycleDetector.remove(object);
-        m_gcBuffer.removeLast();
     }
 
     JSValue getSparseIndex(JSArray* array, unsigned propertyName, bool& hasIndex)
@@ -493,9 +508,20 @@ private:
 
     void writeStringIndex(unsigned i)
     {
-        if (m_constantPool.size() <= 0xFF)
+        writeConstantPoolIndex(m_constantPool, i);
+    }
+    
+    void writeObjectIndex(unsigned i)
+    {
+        writeConstantPoolIndex(m_objectPool, i);
+    }
+
+    template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i)
+    {
+        ASSERT(static_cast<int32_t>(i) < constantPool.size());
+        if (constantPool.size() <= 0xFF)
             write(static_cast<uint8_t>(i));
-        else if (m_constantPool.size() <= 0xFFFF)
+        else if (constantPool.size() <= 0xFFFF)
             write(static_cast<uint16_t>(i));
         else
             write(static_cast<uint32_t>(i));
@@ -504,7 +530,7 @@ private:
     void write(const Identifier& ident)
     {
         UString str = ident.ustring();
-        pair<ConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
+        pair<StringConstantPool::iterator, bool> iter = m_constantPool.add(str.impl(), m_constantPool.size());
         if (!iter.second) {
             write(StringPoolTag);
             writeStringIndex(iter.first->second);
@@ -558,9 +584,10 @@ private:
     }
 
     Vector<uint8_t>& m_buffer;
-    HashSet<JSObject*> m_cycleDetector;
-    typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> ConstantPool;
-    ConstantPool m_constantPool;
+    typedef HashMap<JSObject*, uint32_t> ObjectPool;
+    ObjectPool m_objectPool;
+    typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
+    StringConstantPool m_constantPool;
     Identifier m_emptyIdentifier;
 };
 
@@ -588,7 +615,7 @@ bool CloneSerializer::serialize(JSValue in)
                 JSArray* inArray = asArray(inValue);
                 unsigned length = inArray->length();
                 if (!startArray(inArray))
-                    return false;
+                    break;
                 inputArrayStack.append(inArray);
                 indexStack.append(0);
                 lengthStack.append(length);
@@ -607,7 +634,7 @@ bool CloneSerializer::serialize(JSValue in)
                 JSArray* array = inputArrayStack.last();
                 uint32_t index = indexStack.last();
                 if (index == lengthStack.last()) {
-                    endObject(array);
+                    endObject();
                     inputArrayStack.removeLast();
                     indexStack.removeLast();
                     lengthStack.removeLast();
@@ -645,7 +672,7 @@ bool CloneSerializer::serialize(JSValue in)
                 }
                 JSObject* inObject = asObject(inValue);
                 if (!startObject(inObject))
-                    return false;
+                    break;
                 inputObjectStack.append(inObject);
                 indexStack.append(0);
                 propertyStack.append(PropertyNameArray(m_exec));
@@ -666,7 +693,7 @@ bool CloneSerializer::serialize(JSValue in)
                 uint32_t index = indexStack.last();
                 PropertyNameArray& properties = propertyStack.last();
                 if (index == properties.size()) {
-                    endObject(object);
+                    endObject();
                     inputObjectStack.removeLast();
                     indexStack.removeLast();
                     propertyStack.removeLast();
@@ -904,14 +931,19 @@ private:
 
     bool readStringIndex(uint32_t& i)
     {
-        if (m_constantPool.size() <= 0xFF) {
+        return readConstantPoolIndex(m_constantPool, i);
+    }
+
+    template <class T> bool readConstantPoolIndex(const T& constantPool, uint32_t& i)
+    {
+        if (constantPool.size() <= 0xFF) {
             uint8_t i8;
             if (!read(i8))
                 return false;
             i = i8;
             return true;
         }
-        if (m_constantPool.size() <= 0xFFFF) {
+        if (constantPool.size() <= 0xFFFF) {
             uint16_t i16;
             if (!read(i16))
                 return false;
@@ -1142,6 +1174,14 @@ private:
             RefPtr<RegExp> regExp = RegExp::create(&m_exec->globalData(), pattern->ustring(), flags->ustring());
             return new (m_exec) RegExpObject(m_exec->lexicalGlobalObject(), m_globalObject->regExpStructure(), regExp); 
         }
+        case ObjectReferenceTag: {
+            unsigned index = 0;
+            if (!readConstantPoolIndex(m_gcBuffer, index)) {
+                fail();
+                return JSValue();
+            }
+            return m_gcBuffer.at(index);
+        }
         default:
             m_ptr--; // Push the tag back
             return JSValue();
@@ -1199,7 +1239,6 @@ JSValue CloneDeserializer::deserialize()
             }
             if (index == TerminatorTag) {
                 JSArray* outArray = outputArrayStack.last();
-                m_gcBuffer.removeLast();
                 outValue = outArray;
                 outputArrayStack.removeLast();
                 break;
@@ -1248,7 +1287,6 @@ JSValue CloneDeserializer::deserialize()
                 if (!wasTerminator)
                     goto error;
                 JSObject* outObject = outputObjectStack.last();
-                m_gcBuffer.removeLast();
                 outValue = outObject;
                 outputObjectStack.removeLast();
                 break;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list