[JSC] Implement ArrayBuffer transfer
authordslomov@google.com <dslomov@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Feb 2012 06:40:35 +0000 (06:40 +0000)
committerdslomov@google.com <dslomov@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Feb 2012 06:40:35 +0000 (06:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=73493.
Implement ArrayBuffer transfer, per Khronos spec:  http://www.khronos.org/registry/typedarray/specs/latest/#9.
This brings parity with V8 implementation of transferable typed arrays.

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Extra export.
* wtf/ArrayBuffer.h:
(ArrayBuffer): Added extra export.

Source/WebCore:

Covered by existing tests.

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::handlePostMessage):
* bindings/js/JSDictionary.cpp:
(WebCore::JSDictionary::convertValue):
* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::pushState):
(WebCore::JSHistory::replaceState):
* bindings/js/JSMessageEventCustom.cpp:
(WebCore::handleInitMessageEvent):
* bindings/js/JSMessagePortCustom.cpp:
(WebCore::fillMessagePortArray):
* bindings/js/JSMessagePortCustom.h:
(WebCore):
(WebCore::handlePostMessage):
* bindings/js/ScriptValue.cpp:
(WebCore::ScriptValue::serialize):
* bindings/js/SerializedScriptValue.cpp:
(WebCore):
(WebCore::CloneSerializer::serialize):
(CloneSerializer):
(WebCore::CloneSerializer::CloneSerializer):
(WebCore::CloneSerializer::fillTransferMap):
(WebCore::CloneSerializer::dumpArrayBufferView):
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneDeserializer::deserialize):
(WebCore::CloneDeserializer::CloneDeserializer):
(WebCore::CloneDeserializer::readTerminal):
(CloneDeserializer):
(WebCore::SerializedScriptValue::SerializedScriptValue):
(WebCore::SerializedScriptValue::transferArrayBuffers):
(WebCore::SerializedScriptValue::create):
(WebCore::SerializedScriptValue::deserialize):
* bindings/js/SerializedScriptValue.h:
(WebCore):
(SerializedScriptValue):

LayoutTests:

* fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt:
* fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js: Added tests for Uint8ClampedArray
* fast/dom/Window/window-postmessage-args-expected.txt:
* platform/gtk/Skipped:
* platform/mac/Skipped:
* platform/qt/Skipped:
* platform/win/Skipped:
* platform/wincairo/Skipped:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@109196 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt
LayoutTests/fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js
LayoutTests/fast/dom/Window/window-postmessage-args-expected.txt
LayoutTests/platform/gtk/Skipped
LayoutTests/platform/mac/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win/Skipped
LayoutTests/platform/wincairo/Skipped
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/wtf/ArrayBuffer.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSDictionary.cpp
Source/WebCore/bindings/js/JSHistoryCustom.cpp
Source/WebCore/bindings/js/JSMessageEventCustom.cpp
Source/WebCore/bindings/js/JSMessagePortCustom.cpp
Source/WebCore/bindings/js/JSMessagePortCustom.h
Source/WebCore/bindings/js/ScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.h

index 359a6c6..b6f2589 100644 (file)
@@ -1,3 +1,21 @@
+2012-02-28  Dmitry Lomov  <dslomov@google.com>
+
+        [JSC] Implement ArrayBuffer transfer
+        https://bugs.webkit.org/show_bug.cgi?id=73493.
+        Implement ArrayBuffer transfer, per Khronos spec:  http://www.khronos.org/registry/typedarray/specs/latest/#9.
+        This brings parity with V8 implementation of transferable typed arrays.
+
+        Reviewed by Oliver Hunt.
+
+        * fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt:
+        * fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js: Added tests for Uint8ClampedArray
+        * fast/dom/Window/window-postmessage-args-expected.txt:
+        * platform/gtk/Skipped:
+        * platform/mac/Skipped:
+        * platform/qt/Skipped:
+        * platform/win/Skipped:
+        * platform/wincairo/Skipped:
+
 2012-02-28  Yoshifumi Inoue  <yosin@chromium.org>
 
         [Forms] Spin button sometimes ignores Indeterminate of m_upDownState
index 15fb1cf..c655aae 100644 (file)
@@ -12,6 +12,7 @@ PASS raw Int32
 PASS raw Uint32
 PASS raw Int8
 PASS raw Uint8
+PASS raw Uint8Clamped
 PASS raw Int16
 PASS raw Uint16
 PASS raw Float32
@@ -21,6 +22,7 @@ PASS send view, buffer for Int32
 PASS send view, buffer for Uint32
 PASS send view, buffer for Int8
 PASS send view, buffer for Uint8
+PASS send view, buffer for Uint8Clamped
 PASS send view, buffer for Int16
 PASS send view, buffer for Uint16
 PASS send view, buffer for Float32
@@ -30,6 +32,7 @@ PASS send buffer, view for Int32
 PASS send buffer, view for Uint32
 PASS send buffer, view for Int8
 PASS send buffer, view for Uint8
+PASS send buffer, view for Uint8Clamped
 PASS send buffer, view for Int16
 PASS send buffer, view for Uint16
 PASS send buffer, view for Float32
@@ -39,6 +42,7 @@ PASS squash unrelated views for Int32
 PASS squash unrelated views for Uint32
 PASS squash unrelated views for Int8
 PASS squash unrelated views for Uint8
+PASS squash unrelated views for Uint8Clamped
 PASS squash unrelated views for Int16
 PASS squash unrelated views for Uint16
 PASS squash unrelated views for Float32
index 0bc7b29..76066f3 100644 (file)
@@ -25,11 +25,12 @@ var allBufferTypes =
     ["Uint32", Uint32Array, 4],
     ["Int8", Int8Array, 1],
     ["Uint8", Uint8Array, 1],
+    ["Uint8Clamped", Uint8ClampedArray, 1],
     ["Int16", Int16Array, 2],
     ["Uint16", Uint16Array, 2],
     ["Float32", Float32Array, 4],
     ["Float64", Float64Array, 8],
-    ["DataView", DataView, 1]
+    ["DataView", DataView, 1] 
 ];
 
 function isTypedArray(view)
@@ -360,6 +361,7 @@ testList = testList.concat(allBufferTypes.map(function(bufferType) { return {
     }
 }}));
 
+
 function viewAndBuffer(viewFirst, bufferType) {
     return {
         name: (viewFirst ? "send view, buffer for " : "send buffer, view for ") + bufferType[0],
index 986d263..b6787ed 100644 (file)
@@ -22,9 +22,9 @@ PASS: Posting message ('2147483648', null) did not throw an exception
 PASS: Posting message ('[object MessagePort]', [object MessagePort],[object MessagePort]) did not throw an exception
 PASS: Posting message ('[object MessagePort]', [object MessagePort],[object MessagePort]) did not throw an exception
 PASS: Posting message ('[object MessagePort],[object MessagePort]', [object MessagePort],[object MessagePort]) did not throw an exception
-FAIL: Posting message ('[object ArrayBuffer]', [object ArrayBuffer]): threw exception TypeError: Type error
-FAIL: arrayBuffer not neutered; byteLength = 30
-FAIL: view was not neutered; length = 10
+PASS: Posting message ('[object ArrayBuffer]', [object ArrayBuffer]) did not throw an exception
+PASS: arrayBuffer neutered
+PASS: view neutered
 PASS: Posting message ('done', undefined) did not throw an exception
 Received message '4' with 0 ports.
 Received message '4' with 0 ports.
@@ -42,5 +42,6 @@ Received message '2147483648' with 0 ports.
 Received message '[object Object]' with 2 ports.
 Received message '[object MessagePort]' with 2 ports.
 Received message '[object MessagePort],[object MessagePort]' with 2 ports.
+Received message '[object ArrayBuffer]' with 0 ports.
 Received message 'done' with 0 ports.
 
index 3e7db5c..6fedcd1 100644 (file)
@@ -1507,9 +1507,6 @@ fast/forms/cursor-at-editable-content-boundary.html
 fast/text/glyph-reordering.html
 fast/text/ipa-tone-letters.html
 
-# https://bugs.webkit.org/show_bug.cgi?id=73493
-fast/canvas/webgl/arraybuffer-transfer-of-control.html
-
 # https://bugs.webkit.org/show_bug.cgi?id=73653
 fast/events/offsetX-offsetY.html
 fast/forms/number/spin-in-multi-column.html
index 2287105..283fbee 100644 (file)
@@ -527,9 +527,6 @@ fast/dom/Window/window-postmessage-arrays.html
 # https://bugs.webkit.org/show_bug.cgi?id=73148
 fast/canvas/webgl/webgl-texture-binding-preserved.html
 
-# https://bugs.webkit.org/show_bug.cgi?id=73493
-fast/canvas/webgl/arraybuffer-transfer-of-control.html
-
 # https://bugs.webkit.org/show_bug.cgi?id=73974
 fast/canvas/webgl/canvas-2d-webgl-texture.html
 
index f78ee4d..83d3853 100644 (file)
@@ -2562,9 +2562,6 @@ http/tests/security/text-track-crossorigin.html
 # https://bugs.webkit.org/show_bug.cgi?id=72694
 fast/canvas/canvas-lineWidth.html
 
-# https://bugs.webkit.org/show_bug.cgi?id=73493
-fast/canvas/webgl/arraybuffer-transfer-of-control.html
-
 # [Qt] fast/forms/select/listbox-in-multi-column.html fails
 # https://bugs.webkit.org/show_bug.cgi?id=73660
 fast/forms/select/listbox-in-multi-column.html
index 1335095..61e6c26 100644 (file)
@@ -1532,9 +1532,6 @@ pointer-lock/
 # https://bugs.webkit.org/show_bug.cgi?id=72435
 fast/dom/Window/window-postmessage-arrays.html
 
-# https://bugs.webkit.org/show_bug.cgi?id=73493
-fast/canvas/webgl/arraybuffer-transfer-of-control.html
-
 # Fails because MutationObservers are not notified at end-of-task
 # https://bugs.webkit.org/show_bug.cgi?id=78290
 fast/mutation/end-of-task-delivery.html
index 46c5738..fe611c9 100644 (file)
@@ -2045,9 +2045,6 @@ pointer-lock/
 # https://bugs.webkit.org/show_bug.cgi?id=72435
 fast/dom/Window/window-postmessage-arrays.html
 
-# https://bugs.webkit.org/show_bug.cgi?id=73493
-fast/canvas/webgl/arraybuffer-transfer-of-control.html
-
 # Fails because MutationObservers are not notified at end-of-task
 # https://bugs.webkit.org/show_bug.cgi?id=78290
 fast/mutation/end-of-task-delivery.html
index 5bc797a..24d50ac 100644 (file)
@@ -1,3 +1,16 @@
+2012-02-28  Dmitry Lomov  <dslomov@google.com>
+
+        [JSC] Implement ArrayBuffer transfer
+        https://bugs.webkit.org/show_bug.cgi?id=73493.
+        Implement ArrayBuffer transfer, per Khronos spec:  http://www.khronos.org/registry/typedarray/specs/latest/#9.
+        This brings parity with V8 implementation of transferable typed arrays.
+
+        Reviewed by Oliver Hunt.
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Extra export.
+        * wtf/ArrayBuffer.h:
+        (ArrayBuffer): Added extra export.
+
 2012-02-28  Kevin Ollivier  <kevino@theolliviers.com>
 
         [wx] Unreviewed. Build fix after recent LLInt additions.
index 02622ad..84462e7 100644 (file)
@@ -348,6 +348,7 @@ EXPORTS
     ?toThisObject@JSObject@JSC@@SAPAV12@PAVJSCell@2@PAVExecState@2@@Z
     ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z
     ?toUInt32@Identifier@JSC@@SAIABVUString@2@AA_N@Z
+    ?transfer@ArrayBuffer@WTF@@QAE_NAAVArrayBufferContents@2@AAV?$Vector@V?$RefPtr@VArrayBufferView@WTF@@@WTF@@$0A@@2@@Z
     ?tryFastCalloc@WTF@@YA?AUTryMallocReturnValue@1@II@Z
     ?tryFastMalloc@WTF@@YA?AUTryMallocReturnValue@1@I@Z
     ?tryFastRealloc@WTF@@YA?AUTryMallocReturnValue@1@PAXI@Z
index ee95f5b..3257df3 100644 (file)
@@ -88,7 +88,7 @@ public:
     void addView(ArrayBufferView*);
     void removeView(ArrayBufferView*);
 
-    bool transfer(ArrayBufferContents&, Vector<RefPtr<ArrayBufferView> >& neuteredViews);
+    WTF_EXPORT_PRIVATE bool transfer(ArrayBufferContents&, Vector<RefPtr<ArrayBufferView> >& neuteredViews);
     bool isNeutered() { return !m_contents.m_data; }
 
     ~ArrayBuffer() { }
index b1b3744..fb060a8 100644 (file)
@@ -1,3 +1,50 @@
+2012-02-28  Dmitry Lomov  <dslomov@google.com>
+
+        [JSC] Implement ArrayBuffer transfer
+        https://bugs.webkit.org/show_bug.cgi?id=73493.
+        Implement ArrayBuffer transfer, per Khronos spec:  http://www.khronos.org/registry/typedarray/specs/latest/#9.
+        This brings parity with V8 implementation of transferable typed arrays.
+
+        Reviewed by Oliver Hunt.
+
+        Covered by existing tests.
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::handlePostMessage):
+        * bindings/js/JSDictionary.cpp:
+        (WebCore::JSDictionary::convertValue):
+        * bindings/js/JSHistoryCustom.cpp:
+        (WebCore::JSHistory::pushState):
+        (WebCore::JSHistory::replaceState):
+        * bindings/js/JSMessageEventCustom.cpp:
+        (WebCore::handleInitMessageEvent):
+        * bindings/js/JSMessagePortCustom.cpp:
+        (WebCore::fillMessagePortArray):
+        * bindings/js/JSMessagePortCustom.h:
+        (WebCore):
+        (WebCore::handlePostMessage):
+        * bindings/js/ScriptValue.cpp:
+        (WebCore::ScriptValue::serialize):
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore):
+        (WebCore::CloneSerializer::serialize):
+        (CloneSerializer):
+        (WebCore::CloneSerializer::CloneSerializer):
+        (WebCore::CloneSerializer::fillTransferMap):
+        (WebCore::CloneSerializer::dumpArrayBufferView):
+        (WebCore::CloneSerializer::dumpIfTerminal):
+        (WebCore::CloneDeserializer::deserialize):
+        (WebCore::CloneDeserializer::CloneDeserializer):
+        (WebCore::CloneDeserializer::readTerminal):
+        (CloneDeserializer):
+        (WebCore::SerializedScriptValue::SerializedScriptValue):
+        (WebCore::SerializedScriptValue::transferArrayBuffers):
+        (WebCore::SerializedScriptValue::create):
+        (WebCore::SerializedScriptValue::deserialize):
+        * bindings/js/SerializedScriptValue.h:
+        (WebCore):
+        (SerializedScriptValue):
+
 2012-02-28  Kevin Ollivier  <kevino@theolliviers.com>
 
         [wx] Unreviewed. Build fixes after recent bindings changes.
index 0ba259e..0634659 100644 (file)
@@ -568,6 +568,7 @@ JSValue JSDOMWindow::showModalDialog(ExecState* exec)
 static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec, bool doTransfer)
 {
     MessagePortArray messagePorts;
+    ArrayBufferArray arrayBuffers;
 
     // This function has variable arguments and can be:
     // Per current spec:
@@ -582,13 +583,14 @@ static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec, bool doTransf
             targetOriginArgIndex = 2;
             transferablesArgIndex = 1;
         }
-        fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts);
+        fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts, arrayBuffers);
     }
     if (exec->hadException())
         return jsUndefined();
 
-    RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0), 
-                                                                         doTransfer ? &messagePorts : 0);
+    RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0),
+                                                                         doTransfer ? &messagePorts : 0,
+                                                                         doTransfer ? &arrayBuffers : 0);
 
     if (exec->hadException())
         return jsUndefined();
index bd06216..d7913fa 100644 (file)
@@ -103,7 +103,7 @@ void JSDictionary::convertValue(ExecState* exec, JSValue value, ScriptValue& res
 
 void JSDictionary::convertValue(ExecState* exec, JSValue value, RefPtr<SerializedScriptValue>& result)
 {
-    result = SerializedScriptValue::create(exec, value, 0);
+    result = SerializedScriptValue::create(exec, value, 0, 0);
 }
 
 void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<DOMWindow>& result)
@@ -128,7 +128,8 @@ void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<Storage>& resu
 
 void JSDictionary::convertValue(ExecState* exec, JSValue value, MessagePortArray& result)
 {
-    fillMessagePortArray(exec, value, result);
+    ArrayBufferArray arrayBuffers;
+    fillMessagePortArray(exec, value, result, arrayBuffers);
 }
 
 #if ENABLE(VIDEO_TRACK)
index 480658b..e72c258 100644 (file)
@@ -180,7 +180,7 @@ JSValue JSHistory::state(ExecState *exec) const
 
 JSValue JSHistory::pushState(ExecState* exec)
 {
-    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0);
+    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0);
     if (exec->hadException())
         return jsUndefined();
 
@@ -206,7 +206,7 @@ JSValue JSHistory::pushState(ExecState* exec)
 
 JSValue JSHistory::replaceState(ExecState* exec)
 {
-    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0);
+    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0);
     if (exec->hadException())
         return jsUndefined();
 
index 64b989c..64fcef8 100644 (file)
@@ -109,9 +109,11 @@ static JSC::JSValue handleInitMessageEvent(JSMessageEvent* jsEvent, JSC::ExecSta
     const UString& lastEventIdArg = exec->argument(5).toString(exec)->value(exec);
     DOMWindow* sourceArg = toDOMWindow(exec->argument(6));
     OwnPtr<MessagePortArray> messagePorts;
+    OwnPtr<ArrayBufferArray> arrayBuffers;
     if (!exec->argument(7).isUndefinedOrNull()) {
         messagePorts = adoptPtr(new MessagePortArray);
-        fillMessagePortArray(exec, exec->argument(7), *messagePorts);
+        arrayBuffers = adoptPtr(new ArrayBufferArray);
+        fillMessagePortArray(exec, exec->argument(7), *messagePorts, *arrayBuffers);
         if (exec->hadException())
             return jsUndefined();
     }
index 711166b..76a8c0f 100644 (file)
@@ -30,6 +30,7 @@
 #include "Event.h"
 #include "ExceptionCode.h"
 #include "Frame.h"
+#include "JSArrayBuffer.h"
 #include "JSDOMGlobalObject.h"
 #include "JSEvent.h"
 #include "JSEventListener.h"
@@ -67,12 +68,13 @@ JSC::JSValue JSMessagePort::webkitPostMessage(JSC::ExecState* exec)
     return handlePostMessage(exec, impl());
 }
 
-void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray)
+void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray, ArrayBufferArray& arrayBuffers)
 {
     // Convert from the passed-in JS array-like object to a MessagePortArray.
     // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec.
     if (value.isUndefinedOrNull()) {
         portArray.resize(0);
+        arrayBuffers.resize(0);
         return;
     }
 
@@ -94,11 +96,17 @@ void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortA
 
         // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
         RefPtr<MessagePort> port = toMessagePort(value);
-        if (!port) {
-            throwTypeError(exec);
-            return;
+        if (port)
+            portArray.append(port.release());
+        else {
+            RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value);
+            if (arrayBuffer)
+                arrayBuffers.append(arrayBuffer);
+            else {
+                throwTypeError(exec);
+                return;
+            }
         }
-        portArray.append(port.release());
     }
 }
 
index 5a9e04b..e76e76d 100644 (file)
@@ -42,15 +42,16 @@ namespace WebCore {
     // Helper function which pulls the values out of a JS sequence and into a MessagePortArray.
     // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec.
     // May generate an exception via the passed ExecState.
-    void fillMessagePortArray(JSC::ExecState*, JSC::JSValue, MessagePortArray&);
+    void fillMessagePortArray(JSC::ExecState*, JSC::JSValue, MessagePortArray&, ArrayBufferArray&);
 
     // Helper function to convert from JS postMessage arguments to WebCore postMessage arguments.
     template <typename T>
     inline JSC::JSValue handlePostMessage(JSC::ExecState* exec, T* impl)
     {
         MessagePortArray portArray;
-        fillMessagePortArray(exec, exec->argument(1), portArray);
-        RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0), &portArray);
+        ArrayBufferArray arrayBufferArray;
+        fillMessagePortArray(exec, exec->argument(1), portArray, arrayBufferArray);
+        RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0), &portArray, &arrayBufferArray);
         if (exec->hadException())
             return JSC::jsUndefined();
 
index 7272a10..f75851f 100644 (file)
@@ -102,7 +102,7 @@ bool ScriptValue::isFunction() const
 
 PassRefPtr<SerializedScriptValue> ScriptValue::serialize(ScriptState* scriptState, SerializationErrorMode throwExceptions)
 {
-    return SerializedScriptValue::create(scriptState, jsValue(), 0, throwExceptions);
+    return SerializedScriptValue::create(scriptState, jsValue(), 0, 0, throwExceptions);
 }
 
 ScriptValue ScriptValue::deserialize(ScriptState* scriptState, SerializedScriptValue* value, SerializationErrorMode throwExceptions)
index 77cd65b..7c7d337 100644 (file)
@@ -61,6 +61,7 @@
 #include <runtime/PropertyNameArray.h>
 #include <runtime/RegExp.h>
 #include <runtime/RegExpObject.h>
+#include <wtf/ArrayBuffer.h>
 #include <wtf/ByteArray.h>
 #include <wtf/HashTraits.h>
 #include <wtf/Vector.h>
@@ -105,6 +106,7 @@ enum SerializationTag {
     MessagePortReferenceTag = 20,
     ArrayBufferTag = 21,
     ArrayBufferViewTag = 22,
+    ArrayBufferTransferTag = 23,
     ErrorTag = 255
 };
 
@@ -191,6 +193,7 @@ static const unsigned int StringPoolTag = 0xFFFFFFFE;
  *    | MessagePortReferenceTag <value:uint32_t>
  *    | ArrayBuffer
  *    | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLenght:uint32_t> (ArrayBuffer | ObjectReference)
+ *    | ArrayBufferTransferTag <value:uint32_t>
  *
  * String :-
  *      EmptyStringTag
@@ -315,9 +318,11 @@ template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, con
 
 class CloneSerializer : CloneBase {
 public:
-    static SerializationReturnCode serialize(ExecState* exec, JSValue value, MessagePortArray* messagePorts, Vector<uint8_t>& out)
+    static SerializationReturnCode serialize(ExecState* exec, JSValue value,
+                                             MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
+                                             Vector<uint8_t>& out)
     {
-        CloneSerializer serializer(exec, messagePorts, out);
+        CloneSerializer serializer(exec, messagePorts, arrayBuffers, out);
         return serializer.serialize(value);
     }
 
@@ -346,19 +351,29 @@ public:
     }
 
 private:
-    CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, Vector<uint8_t>& out)
+    typedef HashMap<JSObject*, uint32_t> ObjectPool;
+
+    CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<uint8_t>& out)
         : CloneBase(exec)
         , m_buffer(out)
         , m_emptyIdentifier(exec, UString("", 0))
     {
         write(CurrentVersion);
-        if (messagePorts) {
-            JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
-            for (size_t i = 0; i < messagePorts->size(); i++) {
-                JSC::JSValue value = toJS(exec, globalObject, messagePorts->at(i).get());
-                if (value.getObject())
-                    m_transferredMessagePorts.add(value.getObject(), i);
-            }
+        fillTransferMap(messagePorts, m_transferredMessagePorts);
+        fillTransferMap(arrayBuffers, m_transferredArrayBuffers);
+    }
+
+    template <class T>
+    void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result)
+    {
+        if (!input)
+            return;
+        JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject());
+        for (size_t i = 0; i < input->size(); i++) {
+            JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get());
+            JSC::JSObject* obj = value.getObject();
+            if (obj && !result.contains(obj))
+                result.add(obj, i);
         }
     }
 
@@ -475,7 +490,7 @@ private:
         }
     }
 
-    bool dumpArrayBufferView(JSObject* obj)
+    bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code)
     {
         write(ArrayBufferViewTag);
         if (obj->inherits(&JSDataView::s_info))
@@ -505,11 +520,15 @@ private:
         write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
         write(static_cast<uint32_t>(arrayBufferView->byteLength()));
         RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
+        if (!arrayBuffer) {
+            code = ValidationError;
+            return true;
+        }
         JSValue bufferObj = toJS(m_exec, static_cast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get());
-        return dumpIfTerminal(bufferObj);
+        return dumpIfTerminal(bufferObj, code);
     }
 
-    bool dumpIfTerminal(JSValue value)
+    bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
     {
         if (!value.isCell()) {
             dumpImmediate(value);
@@ -596,17 +615,26 @@ private:
                 ObjectPool::iterator index = m_transferredMessagePorts.find(obj);
                 if (index != m_transferredMessagePorts.end()) {
                     write(MessagePortReferenceTag);
-                    uint32_t i = index->second;
-                    write(i);
+                    write(index->second);
                     return true;
                 }
                 return false;
             }
             if (obj->inherits(&JSArrayBuffer::s_info)) {
+                RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(obj);
+                if (arrayBuffer->isNeutered()) {
+                    code = ValidationError;
+                    return true;
+                }
+                ObjectPool::iterator index = m_transferredArrayBuffers.find(obj);
+                if (index != m_transferredArrayBuffers.end()) {
+                    write(ArrayBufferTransferTag);
+                    write(index->second);
+                    return true;
+                }
                 if (!startObjectInternal(obj)) // handle duplicates
                     return true;
                 write(ArrayBufferTag);
-                RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(obj);
                 write(arrayBuffer->byteLength());
                 write(static_cast<const uint8_t *>(arrayBuffer->data()), arrayBuffer->byteLength());
                 return true;
@@ -614,7 +642,7 @@ private:
             if (obj->inherits(&JSArrayBufferView::s_info)) {
                 if (!startObjectInternal(obj))
                     return true;
-                return dumpArrayBufferView(obj);
+                return dumpArrayBufferView(obj, code);
             }
 
             CallData unusedData;
@@ -749,9 +777,9 @@ private:
     }
 
     Vector<uint8_t>& m_buffer;
-    typedef HashMap<JSObject*, uint32_t> ObjectPool;
     ObjectPool m_objectPool;
     ObjectPool m_transferredMessagePorts;
+    ObjectPool m_transferredArrayBuffers;
     typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
     StringConstantPool m_constantPool;
     Identifier m_emptyIdentifier;
@@ -814,7 +842,10 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in)
                 }
 
                 write(index);
-                if (dumpIfTerminal(inValue)) {
+                SerializationReturnCode terminalCode = SuccessfullyCompleted;
+                if (dumpIfTerminal(inValue, terminalCode)) {
+                    if (terminalCode != SuccessfullyCompleted)
+                        return terminalCode;
                     indexStack.last()++;
                     goto arrayStartVisitMember;
                 }
@@ -871,10 +902,13 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in)
                 if (shouldTerminate())
                     return ExistingExceptionError;
 
-                if (!dumpIfTerminal(inValue)) {
+                SerializationReturnCode terminalCode = SuccessfullyCompleted;
+                if (!dumpIfTerminal(inValue, terminalCode)) {
                     stateStack.append(ObjectEndVisitMember);
                     goto stateUnknown;
                 }
+                if (terminalCode != SuccessfullyCompleted)
+                    return terminalCode;
                 // fallthrough
             }
             case ObjectEndVisitMember: {
@@ -885,13 +919,18 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in)
                 goto objectStartVisitMember;
             }
             stateUnknown:
-            case StateUnknown:
-                if (dumpIfTerminal(inValue))
+            case StateUnknown: {
+                SerializationReturnCode terminalCode = SuccessfullyCompleted;
+                if (dumpIfTerminal(inValue, terminalCode)) {
+                    if (terminalCode != SuccessfullyCompleted)
+                        return terminalCode;
                     break;
+                }
 
                 if (isArray(inValue))
                     goto arrayStartState;
                 goto objectStartState;
+            }
         }
         if (stateStack.isEmpty())
             break;
@@ -911,6 +950,8 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in)
     return SuccessfullyCompleted;
 }
 
+typedef Vector<WTF::ArrayBufferContents> ArrayBufferContentsArray;
+
 class CloneDeserializer : CloneBase {
 public:
     static String deserializeString(const Vector<uint8_t>& buffer)
@@ -932,12 +973,13 @@ public:
         return String(str.impl());
     }
 
-    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts,
+    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject,
+                                             MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray,
                                              const Vector<uint8_t>& buffer)
     {
         if (!buffer.size())
             return make_pair(jsNull(), UnspecifiedError);
-        CloneDeserializer deserializer(exec, globalObject, messagePorts, buffer);
+        CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer);
         if (!deserializer.isValid())
             return make_pair(JSValue(), ValidationError);
         return deserializer.deserialize();
@@ -982,7 +1024,9 @@ private:
         size_t m_index;
     };
 
-    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, MessagePortArray* messagePorts, const Vector<uint8_t>& buffer)
+    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, 
+                      MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents,
+                      const Vector<uint8_t>& buffer)
         : CloneBase(exec)
         , m_globalObject(globalObject)
         , m_isDOMGlobalObject(globalObject->inherits(&JSDOMGlobalObject::s_info))
@@ -990,6 +1034,8 @@ private:
         , m_end(buffer.data() + buffer.size())
         , m_version(0xFFFFFFFF)
         , m_messagePorts(messagePorts)
+        , m_arrayBufferContents(arrayBufferContents)
+        , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
     {
         if (!read(m_version))
             m_version = 0xFFFFFFFF;
@@ -1432,6 +1478,19 @@ private:
             m_gcBuffer.append(result);
             return result;
         }
+        case ArrayBufferTransferTag: {
+            uint32_t index;
+            bool indexSuccessfullyRead = read(index);
+            if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
+                fail();
+                return JSValue();
+            }
+
+            if (!m_arrayBuffers[index])
+                m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
+
+            return getJSValue(m_arrayBuffers[index].get());
+        }
         case ArrayBufferViewTag: {
             JSValue arrayBufferView;
             if (!readArrayBufferView(arrayBufferView)) {
@@ -1454,6 +1513,8 @@ private:
     unsigned m_version;
     Vector<CachedString> m_constantPool;
     MessagePortArray* m_messagePorts;
+    ArrayBufferContentsArray* m_arrayBufferContents;
+    ArrayBufferArray m_arrayBuffers;
 };
 
 DeserializationResult CloneDeserializer::deserialize()
@@ -1603,17 +1664,61 @@ SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer)
     m_data.swap(buffer);
 }
 
-PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value, MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
+SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray)
+    : m_arrayBufferContentsArray(arrayBufferContentsArray)
+{
+    m_data.swap(buffer);
+}
+
+PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
+    ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
+{
+    for (size_t i = 0; i < arrayBuffers.size(); i++) {
+        if (arrayBuffers[i]->isNeutered()) {
+            code = ValidationError;
+            return nullptr;
+        }
+    }
+
+    OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
+
+    HashSet<WTF::ArrayBuffer*> visited;
+    for (size_t i = 0; i < arrayBuffers.size(); i++) {
+        Vector<RefPtr<ArrayBufferView> > neuteredViews;
+
+        if (visited.contains(arrayBuffers[i].get()))
+            continue;
+        visited.add(arrayBuffers[i].get());
+
+        bool result = arrayBuffers[i]->transfer(contents->at(i), neuteredViews);
+        if (!result) {
+            code = ValidationError;
+            return nullptr;
+        }
+    }
+    return contents.release();
+}
+
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value,
+                                                                MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
+                                                                SerializationErrorMode throwExceptions)
 {
     Vector<uint8_t> buffer;
-    SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, buffer);
+    SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, buffer);
+
+    OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
+
+    if (arrayBuffers && serializationDidCompleteSuccessfully(code))
+        arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, code);
+
     if (throwExceptions == Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, code);
 
     if (!serializationDidCompleteSuccessfully(code))
         return 0;
-        
-    return adoptRef(new SerializedScriptValue(buffer));
+
+    return adoptRef(new SerializedScriptValue(buffer, arrayBufferContentsArray.release()));
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
@@ -1631,12 +1736,13 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& st
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, 
-                                                                MessagePortArray* messagePorts, JSValueRef* exception)
+                                                                MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
+                                                                JSValueRef* exception)
 {
     ExecState* exec = toJS(originContext);
     APIEntryShim entryShim(exec);
     JSValue value = toJS(exec, apiValue);
-    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts);
+    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts, arrayBuffers);
     if (exec->hadException()) {
         if (exception)
             *exception = toRef(exec, exec->exception());
@@ -1650,7 +1756,7 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef ori
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue,
                                                                 JSValueRef* exception)
 {
-    return create(originContext, apiValue, 0, exception);
+    return create(originContext, apiValue, 0, 0, exception);
 }
 
 String SerializedScriptValue::toString()
@@ -1658,10 +1764,11 @@ String SerializedScriptValue::toString()
     return CloneDeserializer::deserializeString(m_data);
 }
 
-JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, 
+JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject,
                                            MessagePortArray* messagePorts, SerializationErrorMode throwExceptions)
 {
-    DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts, m_data);
+    DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts,
+                                                                  m_arrayBufferContentsArray.get(), m_data);
     if (throwExceptions == Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, result.second);
     return result.first;
index 75ce694..3f8da5e 100644 (file)
@@ -30,6 +30,7 @@
 #include "ScriptState.h"
 #include <heap/Strong.h>
 #include <runtime/JSValue.h>
+#include <wtf/ArrayBuffer.h>
 #include <wtf/Forward.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
@@ -41,6 +42,7 @@ namespace WebCore {
 
 class MessagePort;
 typedef Vector<RefPtr<MessagePort>, 1> MessagePortArray;
+typedef Vector<RefPtr<WTF::ArrayBuffer>, 1> ArrayBufferArray;
  
 enum SerializationReturnCode {
     SuccessfullyCompleted,
@@ -58,8 +60,9 @@ class SharedBuffer;
 
 class SerializedScriptValue : public RefCounted<SerializedScriptValue> {
 public:
-    static PassRefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue, MessagePortArray*, SerializationErrorMode = Throwing);
-    static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, MessagePortArray*,  JSValueRef* exception);
+    static PassRefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue, MessagePortArray*, ArrayBufferArray*,
+                                                    SerializationErrorMode = Throwing);
+    static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, MessagePortArray*, ArrayBufferArray*, JSValueRef* exception);
     static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, JSValueRef* exception);
 
     static PassRefPtr<SerializedScriptValue> create(const String&);
@@ -88,11 +91,15 @@ public:
     ~SerializedScriptValue();
 
 private:
+    typedef Vector<WTF::ArrayBufferContents> ArrayBufferContentsArray;
     static void maybeThrowExceptionIfSerializationFailed(JSC::ExecState*, SerializationReturnCode);
     static bool serializationDidCompleteSuccessfully(SerializationReturnCode);
+    static PassOwnPtr<ArrayBufferContentsArray> transferArrayBuffers(ArrayBufferArray&, SerializationReturnCode&);
     
     SerializedScriptValue(Vector<unsigned char>&);
+    SerializedScriptValue(Vector<unsigned char>&, PassOwnPtr<ArrayBufferContentsArray>);
     Vector<unsigned char> m_data;
+    OwnPtr<ArrayBufferContentsArray> m_arrayBufferContentsArray;
 };
 
 }