2010-03-31  Vitaly Repeshko  <vitalyr@chromium.org>

        Reviewed by David Levin.

        [V8] SerializedScriptValue must be deserialized only once and in the right context
        https://bugs.webkit.org/show_bug.cgi?id=36892

        See also https://bugs.webkit.org/show_bug.cgi?id=34227 for the
        corresponding JSC change.

        General idea: SerializedScriptValue must be deserialized only once
        and in the context of the intended MessageEvent recepient. The
        approach we take for now is to eagerly deserialize when a
        JavaScript wrapper for MessageEvent is created.

        A better fix would be to keep a reference to the context in
        MessageEvent and use it when lazily deserializing. It's harder to
        do since the API doesn't have a clean method to have such a reference.

        Tested by fast/dom/Window/window-postmessage-clone-frames.html. This
        test still fails but only for the types which we can't serialize yet.

        * bindings/scripts/CodeGeneratorV8.pm:
        * bindings/v8/SerializedScriptValue.h:
        (WebCore::SerializedScriptValue::deserializeAndSetProperty):
        * bindings/v8/custom/V8MessageEventCustom.cpp:
        (WebCore::V8MessageEvent::initMessageEventCallback):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@56877 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 93fa577..4142ece 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,31 @@
+2010-03-31  Vitaly Repeshko  <vitalyr@chromium.org>
+
+        Reviewed by David Levin.
+
+        [V8] SerializedScriptValue must be deserialized only once and in the right context
+        https://bugs.webkit.org/show_bug.cgi?id=36892
+
+        See also https://bugs.webkit.org/show_bug.cgi?id=34227 for the
+        corresponding JSC change.
+
+        General idea: SerializedScriptValue must be deserialized only once
+        and in the context of the intended MessageEvent recepient. The
+        approach we take for now is to eagerly deserialize when a
+        JavaScript wrapper for MessageEvent is created.
+
+        A better fix would be to keep a reference to the context in
+        MessageEvent and use it when lazily deserializing. It's harder to
+        do since the API doesn't have a clean method to have such a reference.
+
+        Tested by fast/dom/Window/window-postmessage-clone-frames.html. This
+        test still fails but only for the types which we can't serialize yet.
+
+        * bindings/scripts/CodeGeneratorV8.pm:
+        * bindings/v8/SerializedScriptValue.h:
+        (WebCore::SerializedScriptValue::deserializeAndSetProperty):
+        * bindings/v8/custom/V8MessageEventCustom.cpp:
+        (WebCore::V8MessageEvent::initMessageEventCallback):
+
 2010-03-31  Adam Barth  <abarth@webkit.org>
 
         Reviewed by Darin Fisher.
diff --git a/WebCore/bindings/scripts/CodeGeneratorV8.pm b/WebCore/bindings/scripts/CodeGeneratorV8.pm
index 68007e2..0c28707 100644
--- a/WebCore/bindings/scripts/CodeGeneratorV8.pm
+++ b/WebCore/bindings/scripts/CodeGeneratorV8.pm
@@ -1141,6 +1141,10 @@
     my $attrName = $attribute->signature->name;
     my $attrExt = $attribute->signature->extendedAttributes;
 
+    # Attributes of type SerializedScriptValue are set in the
+    # constructor and don't require callbacks.
+    return if ($attribute->signature->type eq "SerializedScriptValue");
+
     my $accessControl = "v8::DEFAULT";
     if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) {
         $accessControl = "v8::ALL_CAN_READ";
@@ -1467,6 +1471,7 @@
     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
 
     my $hasConstructors = 0;
+    my $serializedAttribute;
     # Generate property accessors for attributes.
     for ($index = 0; $index < @{$dataNode->attributes}; $index++) {
         $attribute = @{$dataNode->attributes}[$index];
@@ -1486,6 +1491,15 @@
             $attribute->signature->extendedAttributes->{"v8OnProto"} = 1;
         }
 
+        # Attributes of type SerializedScriptValue are set in the
+        # constructor and don't require callbacks.
+        if ($attrType eq "SerializedScriptValue") {
+            die "Only one attribute of type SerializedScriptValue supported" if $serializedAttribute;
+            $implIncludes{"SerializedScriptValue.h"} = 1;
+            $serializedAttribute = $attribute;
+            next;
+        }
+
         # Do not generate accessor if this is a custom attribute.  The
         # call will be forwarded to a hand-written accessor
         # implementation.
@@ -1911,7 +1925,7 @@
 END
     }
 
-    GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType);
+    GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute);
 
     push(@implContent, <<END);
 
@@ -1940,6 +1954,7 @@
     my $interfaceName = shift;
     my $className = shift;
     my $nativeType = shift;
+    my $serializedAttribute = shift;
 
     my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
@@ -1993,7 +2008,6 @@
     push(@implContent, <<END);
     wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl);
 END
-
     if (IsNodeSubType($dataNode)) {
         push(@implContent, <<END);
     // Exit the node's context if it was entered.
@@ -2008,6 +2022,22 @@
 END
     push(@implContent, "\n    impl->ref();\n") if IsRefPtrType($interfaceName);
 
+    # Eagerly deserialize attributes of type SerializedScriptValue
+    # while we're in the right context.
+    if ($serializedAttribute) {
+        die "Attribute of type SerializedScriptValue expected" if $serializedAttribute->signature->type ne "SerializedScriptValue";
+        my $attrName = $serializedAttribute->signature->name;
+        my $attrAttr = "v8::DontDelete";
+        if ($serializedAttribute->type =~ /^readonly/) {
+            $attrAttr .= " | v8::ReadOnly";
+        }
+        $attrAttr = "static_cast<v8::PropertyAttribute>($attrAttr)";
+        my $getterFunc = $codeGenerator->WK_lcfirst($attrName);
+        push(@implContent, <<END);
+    SerializedScriptValue::deserializeAndSetProperty(wrapper, "${attrName}", ${attrAttr}, impl->${getterFunc}());
+END
+    }
+
     if ($domMapFunction) {
         push(@implContent, <<END);
     ${domMapFunction}.set(impl, v8::Persistent<v8::Object>::New(wrapper));
diff --git a/WebCore/bindings/v8/SerializedScriptValue.h b/WebCore/bindings/v8/SerializedScriptValue.h
index ba4d5ed..2b6c392 100644
--- a/WebCore/bindings/v8/SerializedScriptValue.h
+++ b/WebCore/bindings/v8/SerializedScriptValue.h
@@ -40,6 +40,18 @@
 
 class SerializedScriptValue : public RefCounted<SerializedScriptValue> {
 public:
+    // Deserializes the given value and sets it as a property on the
+    // object.
+    static void deserializeAndSetProperty(v8::Handle<v8::Object> object,
+                                          const char* propertyName,
+                                          v8::PropertyAttribute attribute,
+                                          SerializedScriptValue* value)
+    {
+        ASSERT(value);
+        v8::Handle<v8::Value> deserialized = value->deserialize();
+        object->ForceSet(v8::String::NewSymbol(propertyName), deserialized, attribute);
+    }
+
     // Creates a serialized representation of the given V8 value.
     static PassRefPtr<SerializedScriptValue> create(v8::Handle<v8::Value> value)
     {
diff --git a/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
index d41a785..cca4a24 100644
--- a/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
@@ -84,6 +84,8 @@
             return v8::Undefined();
     }
     event->initMessageEvent(typeArg, canBubbleArg, cancelableArg, dataArg.release(), originArg, lastEventIdArg, sourceArg, portArray.release());
+    v8::PropertyAttribute dataAttr = static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly);
+    SerializedScriptValue::deserializeAndSetProperty(args.Holder(), "data", dataAttr, event->data());
     return v8::Undefined();
   }