https://bugs.webkit.org/show_bug.cgi?id=73503
authordslomov@google.com <dslomov@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Dec 2011 17:57:32 +0000 (17:57 +0000)
committerdslomov@google.com <dslomov@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Dec 2011 17:57:32 +0000 (17:57 +0000)
[Chromium][V8] Implement ArrayBuffer transfer in chromium.
Portions of this patch come from Luke Zarko.

Source/JavaScriptCore:

Reviewed by David Levin.

* wtf/ArrayBuffer.cpp:
(WTF::ArrayBuffer::transfer): Changed prototype from pointers to RefPtr.
* wtf/ArrayBuffer.h:
(WTF::ArrayBufferContents::transfer): Changed prototype from pointers to RefPtr.
(WTF::ArrayBuffer::isNeutered):
* wtf/TypedArrayBase.h:
(WTF::TypedArrayBase::neuter):

Source/WebCore:

Reviewed by David Levin.

Test: fast/canvas/webgl/arraybuffer-transfer-of-control.html

* bindings/v8/SerializedScriptValue.cpp:
(WebCore::V8ObjectMap::Writer::writeTransferredArrayBuffer):
(WebCore::V8ObjectMap::Serializer::Serializer):
(WebCore::V8ObjectMap::Serializer::writeAndGreyArrayBufferView):
(WebCore::V8ObjectMap::Serializer::writeArrayBuffer):
(WebCore::V8ObjectMap::Serializer::writeTransferredArrayBuffer):
(WebCore::V8ObjectMap::Serializer::doSerialize):
(WebCore::V8ObjectMap::Reader::read):
(WebCore::V8ObjectMap::Reader::readArrayBufferView):
(WebCore::V8ObjectMap::Deserializer::Deserializer):
(WebCore::V8ObjectMap::Deserializer::tryGetTransferredArrayBuffer):
(WebCore::SerializedScriptValue::create):
(WebCore::neuterBinding):
(WebCore::SerializedScriptValue::transferArrayBuffers):
(WebCore::SerializedScriptValue::SerializedScriptValue):
(WebCore::SerializedScriptValue::deserialize):
* bindings/v8/SerializedScriptValue.h:

LayoutTests:

Reviewed by David Levin.

* fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt: Added.
* fast/canvas/webgl/arraybuffer-transfer-of-control.html: Added.
* fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js: Added.
(isTypedArray):
(isDataView):
(isArrayBuffer):
(assertBufferClosed):
(createBuffer):
(checkBuffer):
(createView):
(createEveryView):
(checkView):
(checkEmptyArray):
(wrapSend):
(wrapFailSend):
(testList.name.send):
(testList.test):
(.name.send):
(.test):
(testList.testList.concat.):
(viewAndBuffer.return.name.bufferType.0.send):
(viewAndBuffer.return.test):
():
(squashUnrelatedViews.return.name.bufferType.0.send):
(squashUnrelatedViews.return.test):
(squashUnrelatedViews):
(testList):
(doneTest):
(windowHandleMessage):
* fast/dom/Window/window-postmessage-args.html:
* platform/chromium/fast/dom/Window/window-postmessage-args-expected.txt:
* platform/gtk/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
* platform/mac/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
* platform/qt/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
* platform/win/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.

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

18 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt [new file with mode: 0644]
LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control.html [new file with mode: 0644]
LayoutTests/fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js [new file with mode: 0644]
LayoutTests/fast/dom/Window/window-postmessage-args-expected.txt
LayoutTests/fast/dom/Window/window-postmessage-args.html
LayoutTests/platform/chromium/fast/dom/Window/window-postmessage-args-expected.txt
LayoutTests/platform/gtk/Skipped
LayoutTests/platform/mac/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win/Skipped
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wtf/ArrayBuffer.cpp
Source/JavaScriptCore/wtf/ArrayBuffer.h
Source/JavaScriptCore/wtf/TypedArrayBase.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/v8/SerializedScriptValue.cpp
Source/WebCore/bindings/v8/SerializedScriptValue.h

index 875bbf7..e116cb0 100644 (file)
@@ -1,3 +1,47 @@
+2011-11-30  Dmitry Lomov  <dslomov@google.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=73503
+        [Chromium][V8] Implement ArrayBuffer transfer in chromium.
+        Portions of this patch come from Luke Zarko.
+
+        Reviewed by David Levin. 
+
+        * fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt: Added.
+        * fast/canvas/webgl/arraybuffer-transfer-of-control.html: Added.
+        * fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js: Added.
+        (isTypedArray):
+        (isDataView):
+        (isArrayBuffer):
+        (assertBufferClosed):
+        (createBuffer):
+        (checkBuffer):
+        (createView):
+        (createEveryView):
+        (checkView):
+        (checkEmptyArray):
+        (wrapSend):
+        (wrapFailSend):
+        (testList.name.send):
+        (testList.test):
+        (.name.send):
+        (.test):
+        (testList.testList.concat.):
+        (viewAndBuffer.return.name.bufferType.0.send):
+        (viewAndBuffer.return.test):
+        ():
+        (squashUnrelatedViews.return.name.bufferType.0.send):
+        (squashUnrelatedViews.return.test):
+        (squashUnrelatedViews):
+        (testList):
+        (doneTest):
+        (windowHandleMessage):
+        * fast/dom/Window/window-postmessage-args.html:
+        * platform/chromium/fast/dom/Window/window-postmessage-args-expected.txt:
+        * platform/gtk/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
+        * platform/mac/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
+        * platform/qt/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
+        * platform/win/Skipped: Skipped arraybuffer-transfer-of-control.js on JSC platfroms.
+
 2011-12-01  Vincent Scheib  <scheib@chromium.org>
 
         [Chromium] Test expectations:
diff --git a/LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt b/LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control-expected.txt
new file mode 100644 (file)
index 0000000..15fb1cf
--- /dev/null
@@ -0,0 +1,50 @@
+Test transfer of control semantics for ArrayBuffers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS sanity check
+PASS raw ArrayBuffer
+PASS sending buffers is sane even if cloning doesn't special-case
+PASS send every view
+PASS transfer list multiple
+PASS transfer neuters unmentioned
+PASS raw Int32
+PASS raw Uint32
+PASS raw Int8
+PASS raw Uint8
+PASS raw Int16
+PASS raw Uint16
+PASS raw Float32
+PASS raw Float64
+PASS raw DataView
+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 Int16
+PASS send view, buffer for Uint16
+PASS send view, buffer for Float32
+PASS send view, buffer for Float64
+PASS send view, buffer for DataView
+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 Int16
+PASS send buffer, view for Uint16
+PASS send buffer, view for Float32
+PASS send buffer, view for Float64
+PASS send buffer, view for DataView
+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 Int16
+PASS squash unrelated views for Uint16
+PASS squash unrelated views for Float32
+PASS squash unrelated views for Float64
+PASS squash unrelated views for DataView
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control.html b/LayoutTests/fast/canvas/webgl/arraybuffer-transfer-of-control.html
new file mode 100644 (file)
index 0000000..465f561
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css"/>
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script src="script-tests/arraybuffer-transfer-of-control.js"></script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
+
diff --git a/LayoutTests/fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js b/LayoutTests/fast/canvas/webgl/script-tests/arraybuffer-transfer-of-control.js
new file mode 100644 (file)
index 0000000..646712d
--- /dev/null
@@ -0,0 +1,453 @@
+window.jsTestIsAsync = true;
+
+description('Test transfer of control semantics for ArrayBuffers.');
+window.testsComplete = 0;
+
+var arraySize = 40;
+var arrayOffset = 8;
+var arrayEffectiveSize = arraySize - arrayOffset;
+
+var basicBufferTypes =
+[
+    ["Int32", Int32Array, 4],
+    ["Uint32", Uint32Array, 4],
+    ["Int8", Int8Array, 1],
+    ["Uint8", Uint8Array, 1],
+    ["Int16", Int16Array, 2],
+    ["Uint16", Uint16Array, 2],
+    ["Float32", Float32Array, 4],
+    ["Float64", Float64Array, 8]
+];
+
+var allBufferTypes =
+[
+    ["Int32", Int32Array, 4],
+    ["Uint32", Uint32Array, 4],
+    ["Int8", Int8Array, 1],
+    ["Uint8", Uint8Array, 1],
+    ["Int16", Int16Array, 2],
+    ["Uint16", Uint16Array, 2],
+    ["Float32", Float32Array, 4],
+    ["Float64", Float64Array, 8],
+    ["DataView", DataView, 1]
+];
+
+function isTypedArray(view)
+{
+    for (var i = 0; i < basicBufferTypes.length; ++i) {
+        var bufferType = basicBufferTypes[i];
+        if (view instanceof bufferType[1]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+function isDataView(view)
+{
+    return (view instanceof DataView);
+}
+
+function isArrayBuffer(buffer)
+{
+    return (buffer instanceof ArrayBuffer);
+}
+
+function assertBufferClosed(testName, buffer)
+{
+    if (buffer === null) {
+        return true;
+    }
+    if (!isArrayBuffer(buffer)) {
+        testFailed(testName + ": not an array buffer (" + buffer + ")");
+        return false;
+    }
+    if (buffer.byteLength !== 0 || !(buffer.byteLength === 0)) {
+        testFailed(testName + ": ArrayBuffer byteLength !== 0");
+        return false;
+    }
+    return true;
+}
+
+function assertViewClosed(testName, view)
+{
+    if (isTypedArray(view) || isDataView(view)) {
+        if (view.buffer !== null && !assertBufferClosed(testName, view.buffer))
+            return false;
+        if (view.byteOffset !== 0 || !(view.byteOffset === 0)) {
+            testFailed(testName + ": view byteOffset !== 0");
+            return false;
+        }
+        if (view.byteLength !== 0 || !(view.byteLength === 0)) {
+            testFailed(testName + ": view byteLength !== 0");
+            return false;
+        }
+        if (!isDataView(view)) {
+            if (view.length !== 0 || !(view.length === 0)) {
+                testFailed(testName + ": TypedArray length !== 0");
+                return false;
+            }
+            try {
+                var v = view[0];
+                if (v !== undefined) {
+                    testFailed(testName + ": index get on a closed view did not return undefined.");
+                    return false;
+                }
+            } catch(xn) {
+                testFailed(testName + ": index get on a closed view threw an exception: " + xn);
+                return false;
+            }
+            try {
+                view[0] = 42;
+                var v = view[0];
+                if (v !== undefined) {
+                    testFailed(testName + ": index set then get on a closed view did not return undefined.");
+                    return false;
+                }
+            } catch(xn) {
+                testFailed(testName + ": index set then get on a closed view threw an exception: " + xn);
+                return false;
+            }
+            try {
+                view.get(0);
+                testFailed(testName + ": get on a closed view succeeded");
+                return false;
+            } catch (xn) { }
+            try {
+                view.set(0, 1);
+                testFailed(testName + ": set on a closed view succeeded");
+                return false;
+            } catch (xn) { }
+        } else {
+            try {
+                view.getInt8(0);
+                testFailed(testName + ": get on a closed view succeeded");
+                return false;
+            } catch (xn) { }
+            try {
+                view.setInt8(0, 1);
+                testFailed(testName + ": set on a closed view succeeded");
+                return false;
+            } catch (xn) { }
+        }
+    } else {
+        testFailed(testName + " not a view (" + view + ")");
+        return false;
+    }
+    return true;
+}
+
+function createBuffer(length)
+{
+    var buffer = new ArrayBuffer(length);
+    var view = new Uint8Array(buffer);
+    for (var i = 0; i < length; ++i) {
+        view[i] = i + 1;
+    }
+    return buffer;
+}
+
+function checkBuffer(testName, buffer, length)
+{
+    if (!isArrayBuffer(buffer)) {
+        testFailed(testName + ": buffer is not an ArrayBuffer");
+        return false;
+    }
+    if (buffer.byteLength !== length) {
+        testFailed(testName + ": buffer is the wrong length");
+        return false;
+    }
+    var view = new Uint8Array(buffer);
+    for (var i = 0; i < length; ++i) {
+        if (view[i] !== i + 1) {
+            testFailed(testName + ": buffer contains the wrong data");
+            return false;
+        }
+    }
+    return true;
+}
+
+function createView(viewType, bytesPerElement)
+{
+    if (viewType === DataView) {
+        var view = new Uint8Array(arraySize);
+        for (var i = arrayOffset; i < arraySize; ++i) {
+            view[i] = i - arrayOffset + 1;
+        }
+        return new DataView(view.buffer, arrayOffset, arrayEffectiveSize);
+    } else {
+        var view = new viewType(new ArrayBuffer(arraySize), arrayOffset, arrayEffectiveSize / bytesPerElement);
+        for (var i = 0; i < arrayEffectiveSize / bytesPerElement; ++i) {
+            view[i] = i + 1;
+        }
+        return view;
+    }
+}
+
+function createEveryView(buffer)
+{
+    return allBufferTypes.map(function (bufferType) {
+        return new bufferType[1](buffer, arrayOffset, arrayEffectiveSize / bufferType[2]);
+    });
+}
+
+function checkView(testName, typedArrayType, view)
+{
+    if (!(view instanceof typedArrayType)) {
+        testFailed(testName + ": " + view + " not an instance of " + typedArrayType);
+        return false;
+    }
+    if (view.buffer.byteLength !== arraySize ||
+        (!(view instanceof DataView) && view.length !== arrayEffectiveSize / view.BYTES_PER_ELEMENT)) {
+        testFailed(testName + ": view has the wrong length (" + view.length + ")");
+        return false;
+    }
+    if (view.byteOffset !== arrayOffset) {
+        testFailed(testName + ": view has wrong byte offset");
+    }
+    var max = arrayEffectiveSize;
+    if (!(view instanceof DataView)) {
+        max = max / view.BYTES_PER_ELEMENT;
+    }
+    for (var i = 0; i < max; ++i) {
+        if (view instanceof DataView) {
+            if (view.getInt8(i) !== i + 1) {
+                testFailed(testName + ": view contains the wrong data");
+                return false;
+            }
+        } else {
+            if (view[i] !== i + 1) {
+                testFailed(testName + ": view contains the wrong data");
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+function checkEmptyArray(testName, array)
+{
+    if (array === null || array === undefined) {
+        testFailed(testName + ": port list is null or undefined");
+        return false;
+    }
+    if (array.length !== 0) {
+        testFailed(testName + ": port list is not zero-length");
+        return false;
+    }
+    return true;
+}
+
+function wrapSend(testName, message, xfer)
+{
+    try {
+        window.webkitPostMessage(message, xfer, '*');
+    } catch (e) {
+        testFailed(testName + ": could not webkitPostMessage: " + e);
+        doneTest();
+        return false;
+    }
+    return true;
+}
+
+function wrapFailSend(testName, message, xfer)
+{
+    try {
+        window.webkitPostMessage(message, xfer, '*');
+    } catch (e) {
+        return true;
+    }
+    testFailed(testName + ": expected webkitPostMessage to fail but it didn't.");
+    return false;
+}
+
+var testList = [{
+    name: "sanity check",
+    send: function (name) { wrapSend(name, [], []); },
+    test: function (name, e) { return true; }
+}, {
+    name: "raw ArrayBuffer",
+    send: function (name) {
+        var buffer = createBuffer(3);
+        wrapSend(name, buffer, [buffer]);
+        assertBufferClosed(name, buffer);
+        wrapFailSend(name, buffer, [buffer]);
+        wrapFailSend(name, buffer, []);
+    },
+    test: function (name, e) { return checkBuffer(name, e.data, 3) && checkEmptyArray(name, e.ports); }
+}, {
+    name: "sending buffers is sane even if cloning doesn't special-case",
+    send: function(name) {
+        var view = createView(Int32Array, 4);
+        var buffer = view.buffer;
+        wrapSend(name, [view, buffer], [buffer]);
+        assertBufferClosed(name, buffer);
+        assertViewClosed(name, view);
+    },
+    test: function (name, e) {
+        if (e.data[0].buffer !== e.data[1]) {
+            testFailed("View and buffer were not linked.");
+            return false;
+        }
+        return true;
+    }
+}, {
+    name: "send every view",
+    send: function(name) {
+        var buffer = createBuffer(arraySize);
+        var views = createEveryView(buffer);
+        wrapSend(name, views, [buffer]);
+        assertBufferClosed(name, buffer);
+        wrapFailSend(name, views, [buffer]);
+        wrapFailSend(name, views, []);
+    },
+    test: function (name, e) {
+        if (e.data.length !== allBufferTypes.length) {
+            testFailed(name + ": not every view was sent.");
+        }
+        for (var v = 0; v < e.data.length; ++v) {
+            var view = e.data[v];
+            if (view.buffer !== e.data[0].buffer) {
+                testFailed(name + ": not every view pointed to the correct buffer.");
+                return false;
+            }
+        }
+        return true;
+    }
+}, {
+    name: "transfer list multiple",
+    send: function(name) {
+        var buffer = createBuffer(arraySize);
+        wrapSend(name, { buffer : buffer }, [buffer,buffer]);
+        assertBufferClosed(name, buffer);
+        wrapFailSend(name, [buffer], [buffer]);
+        wrapFailSend(name, [], [buffer]);
+        var buffer2 = createBuffer(arraySize);
+        wrapFailSend(name, [], [buffer2, buffer]);
+        checkBuffer(name, buffer2, arraySize);
+        wrapFailSend(name, [], [buffer, buffer2]);
+        checkBuffer(name, buffer2, arraySize);
+        wrapFailSend(name, [buffer2], [buffer2, buffer]);
+        checkBuffer(name, buffer2, arraySize);
+    },
+    test: function (name, e) {
+        return checkBuffer(name, e.data.buffer, arraySize);
+    }
+}, {
+    name: "transfer neuters unmentioned",
+    send: function (name) {
+        var buffer = createBuffer(arraySize);
+        wrapSend(name, [], [buffer]);
+        assertBufferClosed(name, buffer);
+    },
+    test : function (name, e) {
+        return e.data.length == 0;
+    }
+}];
+
+testList = testList.concat(allBufferTypes.map(function(bufferType) { return {
+    name: "raw " + bufferType[0],
+    send: function (name) {
+        var view = createView(bufferType[1], bufferType[2]);
+        wrapSend(name, view, [view.buffer]);
+        assertViewClosed(name, view);
+        assertBufferClosed(name, view.buffer);
+        wrapFailSend(name, view, [view.buffer]);
+        wrapFailSend(name, view, []);
+    },
+    test: function (name, e) {
+        return checkView(name, bufferType[1], e.data) && checkEmptyArray(name, e.ports);
+    }
+}}));
+
+function viewAndBuffer(viewFirst, bufferType) {
+    return {
+        name: (viewFirst ? "send view, buffer for " : "send buffer, view for ") + bufferType[0],
+        send: function (name) {
+            var view = createView(bufferType[1], bufferType[2]);
+            var buffer = view.buffer;
+            wrapSend(name, viewFirst ? [view, buffer] : [buffer, view], [buffer]);
+            assertViewClosed(name, view);
+            assertBufferClosed(name, buffer);
+            wrapFailSend(name, view, [buffer]);
+            wrapFailSend(name, view, []);
+            wrapFailSend(name, buffer, [buffer]);
+            wrapFailSend(name, buffer, []);
+            wrapFailSend(name, [view, buffer], [buffer]);
+            wrapFailSend(name, [buffer, view], [buffer]);
+            wrapFailSend(name, [view, buffer], []);
+            wrapFailSend(name, [buffer, view], []);
+        },
+        test: function (name, e) {
+            var view = e.data[viewFirst ? 0 : 1];
+            var buffer = e.data[viewFirst ? 1 : 0];
+            if (buffer !== view.buffer) {
+                testFailed(name + " buffer not shared");
+                return false;
+            }
+            return checkView(name, bufferType[1], view) && checkEmptyArray(name, e.ports);
+        }
+    }
+};
+
+function squashUnrelatedViews(bufferType) {
+    return {
+        name: "squash unrelated views for " + bufferType[0],
+        send: function(name) {
+            var view = createView(bufferType[1], bufferType[2]);
+            var views = createEveryView(view.buffer);
+            var buffer = view.buffer;
+            wrapSend(name, view, [view.buffer]);
+            assertViewClosed(name, view);
+            assertBufferClosed(name, view.buffer);
+            for (var v = 0; v < views.length; ++v) {
+                assertViewClosed(name + "(view " + v + ")", views[v]);
+            }
+            wrapFailSend(name, views, [buffer]);
+        },
+        test: function (name, e) { return checkView(name, bufferType[1], e.data) && checkEmptyArray(name, e.ports); }
+    }
+}
+
+testList = testList.concat(allBufferTypes.map(function(bufferType) { return viewAndBuffer(true, bufferType); }));
+testList = testList.concat(allBufferTypes.map(function(bufferType) { return viewAndBuffer(false, bufferType); }));
+testList = testList.concat(allBufferTypes.map(function(bufferType) { return squashUnrelatedViews(bufferType); }));
+
+function doneTest() {
+    if (++window.testsComplete == testList.length) {
+        finishJSTest();
+    }
+    else {
+        var t = testList[window.testsComplete];
+        try {
+            t.send(t.name);
+        } catch(e) {
+            testFailed(t.name + ": on send: " + e);
+            doneTest();
+        }
+    }
+}
+
+function windowHandleMessage(event) {
+    var currentTest = testList[window.testsComplete];
+    if (currentTest.alreadyHit) {
+        testFailed(currentTest.name + ": windowHandleMessage hit more than once.");
+        return false;
+    }
+    currentTest.alreadyHit = true;
+    try {
+        if (currentTest.test(currentTest.name, event)) {
+            testPassed(currentTest.name);
+        }
+    } catch(e) {
+        testFailed(currentTest.name + ": on recieve: " + e + ". event.data = " + event.data);
+    }
+    doneTest();
+}
+
+window.addEventListener('message', windowHandleMessage);
+window.testsComplete = -1;
+doneTest();
+
+successfullyParsed = true;
+
index ae7ab43..b3fae5a 100644 (file)
@@ -19,6 +19,9 @@ PASS: Posting message ('2147483648', null) did not throw an exception
 FAIL: 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 ('done', *) did not throw an exception
 Received message '4' with 0 ports.
 Received message '4' with 0 ports.
index 646b364..6d0a52f 100644 (file)
@@ -60,6 +60,24 @@ tryPostMessageFunction(window.webkitPostMessage, channel4.port1, [channel4.port1
 var channel5 = new MessageChannel;
 tryPostMessageFunction(window.webkitPostMessage, [channel5.port1, channel5.port2], [channel5.port1, channel5.port2], '*');
 
+var arrayBuffer = new ArrayBuffer(30);
+var int8View = new Int8Array(arrayBuffer, 2, 10);
+tryPostMessageFunction(window.webkitPostMessage, arrayBuffer, [arrayBuffer], '*');
+if (!(arrayBuffer.byteLength === 0)) {
+    console.innerHTML += "FAIL: arrayBuffer not neutered; byteLength = " + arrayBuffer.byteLength + "<br>";
+}
+else {
+    console.innerHTML += "PASS: arrayBuffer neutered<br>";
+}
+
+if (!(int8View.length == 0)) {
+    console.innerHTML += "FAIL: view was not neutered; length = " + int8View.length + "<br>";
+}
+else {
+    console.innerHTML += "PASS: view neutered<br>"
+}
+
+
 tryPostMessageFunction(window.postMessage, 'done', '*');
 </script>
 </body>
index 0e81f8f..23aa852 100644 (file)
@@ -19,6 +19,9 @@ PASS: Posting message ('2147483648', null) did not throw an exception
 PASS: Posting message ('[object MessagePort]', [object MessagePort],[object MessagePort]): threw exception Error: DATA_CLONE_ERR: DOM Exception 25
 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
+PASS: Posting message ('[object ArrayBuffer]', [object ArrayBuffer]) did not throw an exception
+PASS: arrayBuffer neutered
+PASS: view neutered
 PASS: Posting message ('done', *) did not throw an exception
 Received message '4' with 0 ports.
 Received message '4' with 0 ports.
@@ -32,5 +35,6 @@ Received message '2147483648' with 0 ports.
 Received message '2147483648' with 0 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 899a380..105a312 100644 (file)
@@ -1563,3 +1563,6 @@ fast/events/keydown-1.html
 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
index bdfd11d..e8b9974 100644 (file)
@@ -499,3 +499,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
index 0aeced0..6c33fdd 100644 (file)
@@ -2503,3 +2503,6 @@ inspector/extensions/extensions-events.html
 # REGRESSION(r101268):fast/block/child-not-removed-from-parent-lineboxes-crash.html crashes in Debug
 # https://bugs.webkit.org/show_bug.cgi?id=73250
 fast/block/child-not-removed-from-parent-lineboxes-crash.html
+
+# https://bugs.webkit.org/show_bug.cgi?id=73493
+fast/canvas/webgl/arraybuffer-transfer-of-control.html
index 5076211..48ee0d8 100644 (file)
@@ -1463,4 +1463,5 @@ 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
index 613d6dc..120a30c 100644 (file)
@@ -1,3 +1,19 @@
+2011-11-30  Dmitry Lomov  <dslomov@google.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=73503
+        [Chromium][V8] Implement ArrayBuffer transfer in chromium.
+        Portions of this patch come from Luke Zarko.
+
+        Reviewed by David Levin.
+
+        * wtf/ArrayBuffer.cpp:
+        (WTF::ArrayBuffer::transfer): Changed prototype from pointers to RefPtr.
+        * wtf/ArrayBuffer.h:
+        (WTF::ArrayBufferContents::transfer): Changed prototype from pointers to RefPtr.
+        (WTF::ArrayBuffer::isNeutered):
+        * wtf/TypedArrayBase.h:
+        (WTF::TypedArrayBase::neuter):
+
 2011-12-01  Chao-ying Fu  <fu@mips.com>
 
         MacroAssemblerMIPS does not implement readCallTarget
index 1ebe74f..45cfa1d 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace WTF {
 
-bool ArrayBuffer::transfer(ArrayBufferContents& result, Vector<ArrayBufferView*>& neuteredViews)
+bool ArrayBuffer::transfer(ArrayBufferContents& result, Vector<RefPtr<ArrayBufferView> >& neuteredViews)
 {
     RefPtr<ArrayBuffer> keepAlive(this);
 
index 4196aa8..ee95f5b 100644 (file)
@@ -58,13 +58,13 @@ private:
     friend class ArrayBuffer;
 
     static inline void tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents&);
-    void transfer(ArrayBufferContents& other) 
+    void transfer(ArrayBufferContents& other)
     {
         ASSERT(!other.m_data);
         other.m_data = m_data;
         other.m_sizeInBytes = m_sizeInBytes;
-        m_data = 0; 
-        m_sizeInBytes = 0; 
+        m_data = 0;
+        m_sizeInBytes = 0;
     }
 
     void* m_data;
@@ -88,7 +88,8 @@ public:
     void addView(ArrayBufferView*);
     void removeView(ArrayBufferView*);
 
-    bool transfer(ArrayBufferContents&, Vector<ArrayBufferView*>& neuteredViews);
+    bool transfer(ArrayBufferContents&, Vector<RefPtr<ArrayBufferView> >& neuteredViews);
+    bool isNeutered() { return !m_contents.m_data; }
 
     ~ArrayBuffer() { }
 
index ae30c17..dba95d5 100644 (file)
@@ -112,6 +112,12 @@ protected:
         return create<Subclass>(buffer(), offset, length);
     }
 
+    virtual void neuter()
+    {
+        ArrayBufferView::neuter();
+        m_length = 0;
+    }
+
     // We do not want to have to access this via a virtual function in subclasses,
     // which is why it is protected rather than private.
     unsigned m_length;
index 3b270a4..0d0e055 100644 (file)
@@ -1,3 +1,31 @@
+2011-11-30  Dmitry Lomov  <dslomov@google.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=73503
+        [Chromium][V8] Implement ArrayBuffer transfer in chromium.
+        Portions of this patch come from Luke Zarko.
+
+        Reviewed by David Levin.
+
+        Test: fast/canvas/webgl/arraybuffer-transfer-of-control.html
+
+        * bindings/v8/SerializedScriptValue.cpp:
+        (WebCore::V8ObjectMap::Writer::writeTransferredArrayBuffer):
+        (WebCore::V8ObjectMap::Serializer::Serializer):
+        (WebCore::V8ObjectMap::Serializer::writeAndGreyArrayBufferView):
+        (WebCore::V8ObjectMap::Serializer::writeArrayBuffer):
+        (WebCore::V8ObjectMap::Serializer::writeTransferredArrayBuffer):
+        (WebCore::V8ObjectMap::Serializer::doSerialize):
+        (WebCore::V8ObjectMap::Reader::read):
+        (WebCore::V8ObjectMap::Reader::readArrayBufferView):
+        (WebCore::V8ObjectMap::Deserializer::Deserializer):
+        (WebCore::V8ObjectMap::Deserializer::tryGetTransferredArrayBuffer):
+        (WebCore::SerializedScriptValue::create):
+        (WebCore::neuterBinding):
+        (WebCore::SerializedScriptValue::transferArrayBuffers):
+        (WebCore::SerializedScriptValue::SerializedScriptValue):
+        (WebCore::SerializedScriptValue::deserialize):
+        * bindings/v8/SerializedScriptValue.h:
+
 2011-12-01  Roland Steiner  <rolandsteiner@chromium.org>
 
         Shadow ID pseudo-element selectors serialize incorrectly
index d3a4b1d..7031a55 100644 (file)
@@ -197,6 +197,7 @@ enum SerializationTag {
                          //                                            fills it with the last length elements and numProperties name,value pairs pushed onto deserialization stack
     RegExpTag = 'R', // pattern:RawString, flags:uint32_t -> RegExp (ref)
     ArrayBufferTag = 'B', // byteLength:uint32_t, data:byte[byteLength] -> ArrayBuffer (ref)
+    ArrayBufferTransferTag = 't', // index:uint32_t -> ArrayBuffer. For ArrayBuffer transfer
     ArrayBufferViewTag = 'V', // subtag:byte, byteOffset:uint32_t, byteLength:uint32_t -> ArrayBufferView (ref). Consumes an ArrayBuffer from the top of the deserialization stack.
     ObjectReferenceTag = '^', // ref:uint32_t -> reference table[ref]
     GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and pushed onto the open stack (ref)
@@ -438,6 +439,12 @@ public:
         doWriteUint32(index);
     }
 
+    void writeTransferredArrayBuffer(uint32_t index)
+    {
+        append(ArrayBufferTransferTag);
+        doWriteUint32(index);
+    }
+
     void writeObjectReference(uint32_t reference)
     {
         append(ObjectReferenceTag);
@@ -589,11 +596,12 @@ public:
         Success,
         InputError,
         DataCloneError,
+        InvalidStateError,
         JSException,
         JSFailure
     };
 
-    Serializer(Writer& writer, MessagePortArray* messagePorts, v8::TryCatch& tryCatch)
+    Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, v8::TryCatch& tryCatch)
         : m_writer(writer)
         , m_tryCatch(tryCatch)
         , m_depth(0)
@@ -606,6 +614,14 @@ public:
             for (size_t i = 0; i < messagePorts->size(); i++)
                 m_transferredMessagePorts.set(V8MessagePort::wrap(messagePorts->at(i).get()), i);
         }
+        if (arrayBuffers) {
+            for (size_t i = 0; i < arrayBuffers->size(); i++)  {
+                v8::Handle<v8::Object> v8ArrayBuffer = V8ArrayBuffer::wrap(arrayBuffers->at(i).get());
+                // Coalesce multiple occurences of the same buffer to the first index.
+                if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
+                    m_transferredArrayBuffers.set(v8ArrayBuffer, i);
+            }
+        }
     }
 
     Status serialize(v8::Handle<v8::Value> value)
@@ -995,6 +1011,8 @@ private:
         ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(object);
         if (!arrayBufferView)
             return 0;
+        if (!arrayBufferView->buffer())
+            return handleError(DataCloneError, next);
         v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer());
         if (underlyingBuffer.IsEmpty())
             return handleError(DataCloneError, next);
@@ -1014,12 +1032,27 @@ private:
         return 0;
     }
 
-    void writeArrayBuffer(v8::Handle<v8::Value> value)
+    StateBase* writeArrayBuffer(v8::Handle<v8::Value> value, StateBase* next)
     {
         ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>());
         if (!arrayBuffer)
-            return;
+            return 0;
+        if (arrayBuffer->isNeutered())
+            return handleError(InvalidStateError, next);
+        ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>()));
         m_writer.writeArrayBuffer(*arrayBuffer);
+        return 0;
+    }
+
+    StateBase* writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t index, StateBase* next)
+    {
+        ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(value.As<v8::Object>());
+        if (!arrayBuffer)
+            return 0;
+        if (arrayBuffer->isNeutered())
+            return handleError(DataCloneError, next);
+        m_writer.writeTransferredArrayBuffer(index);
+        return 0;
     }
 
     static bool shouldSerializeDensely(uint32_t length, uint32_t propertyCount) 
@@ -1071,6 +1104,7 @@ private:
     typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool;
     ObjectPool m_objectPool;
     ObjectPool m_transferredMessagePorts;
+    ObjectPool m_transferredArrayBuffers;
     uint32_t m_nextObjectReference;
 };
 
@@ -1082,6 +1116,7 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
     }
     m_writer.writeReferenceCount(m_nextObjectReference);
     uint32_t objectReference;
+    uint32_t arrayBufferIndex;
     if ((value->IsObject() || value->IsDate() || value->IsRegExp())
         && m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
         // Note that IsObject() also detects wrappers (eg, it will catch the things
@@ -1114,7 +1149,8 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
                 m_writer.writeTransferredMessagePort(messagePortIndex);
             else
                 return handleError(DataCloneError, next);
-        }
+    } else if (V8ArrayBuffer::HasInstance(value) && m_transferredArrayBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex))
+        return writeTransferredArrayBuffer(value, arrayBufferIndex, next);
     else {
         v8::Handle<v8::Object> jsObject = value.As<v8::Object>();
         if (jsObject.IsEmpty())
@@ -1141,7 +1177,7 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat
         else if (value->IsRegExp())
             writeRegExp(value);
         else if (V8ArrayBuffer::HasInstance(value))
-            writeArrayBuffer(value);
+            return writeArrayBuffer(value, next);
         else if (value->IsObject()) {
             if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
                 return handleError(DataCloneError, next);
@@ -1162,6 +1198,7 @@ public:
     virtual void pushObjectReference(const v8::Handle<v8::Value>&) = 0;
     virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>*) = 0;
     virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>*) = 0;
+    virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>*) = 0;
     virtual bool newSparseArray(uint32_t length) = 0;
     virtual bool newDenseArray(uint32_t length) = 0;
     virtual bool newObject() = 0;
@@ -1368,6 +1405,16 @@ public:
                 return false;
             break;
         }
+        case ArrayBufferTransferTag: {
+            if (m_version <= 0)
+                return false;
+            uint32_t index;
+            if (!doReadUint32(&index))
+                return false;
+            if (!creator.tryGetTransferredArrayBuffer(index, value))
+                return false;
+            break;
+        }
         case ObjectReferenceTag: {
             if (m_version <= 0)
                 return false;
@@ -1569,6 +1616,8 @@ private:
             return false;
         if (!creator.consumeTopOfStack(&arrayBufferV8Value))
             return false;
+        if (arrayBufferV8Value.IsEmpty()) 
+            return false;
         arrayBuffer = V8ArrayBuffer::toNative(arrayBufferV8Value.As<v8::Object>());
         if (!arrayBuffer)
             return false;
@@ -1741,11 +1790,17 @@ private:
     uint32_t m_version;
 };
 
+
+typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray;
+
 class Deserializer : public CompositeCreator {
 public:
-    explicit Deserializer(Reader& reader, MessagePortArray* messagePorts)
+    explicit Deserializer(Reader& reader, 
+                          MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents)
         : m_reader(reader)
         , m_transferredMessagePorts(messagePorts)
+        , m_arrayBufferContents(arrayBufferContents)
+        , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
         , m_version(0)
     {
     }
@@ -1890,6 +1945,21 @@ public:
         return true;
     }
 
+    virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>* object)
+    {
+        if (!m_arrayBufferContents)
+            return false;
+        if (index >= m_arrayBuffers.size())
+            return false;
+        v8::Handle<v8::Object> result = m_arrayBuffers.at(index);
+        if (result.IsEmpty()) {
+            result = V8ArrayBuffer::wrap(ArrayBuffer::create(m_arrayBufferContents->at(index)).get());
+            m_arrayBuffers[index] = result;
+        }
+        *object = result;
+        return true;
+    }
+
     virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>* object)
     {
         if (reference >= m_objectPool.size())
@@ -1969,6 +2039,8 @@ private:
     Vector<v8::Handle<v8::Value> > m_objectPool;
     Vector<uint32_t> m_openCompositeReferenceStack;
     MessagePortArray* m_transferredMessagePorts;
+    ArrayBufferContentsArray* m_arrayBufferContents;
+    Vector<v8::Handle<v8::Object> > m_arrayBuffers;
     uint32_t m_version;
 };
 
@@ -1989,16 +2061,16 @@ void SerializedScriptValue::deserializeAndSetProperty(v8::Handle<v8::Object> obj
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value,
-                                                                MessagePortArray* messagePorts, ArrayBufferArray*,
+                                                                MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
                                                                 bool& didThrow)
 {
-    return adoptRef(new SerializedScriptValue(value, messagePorts, didThrow));
+    return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, didThrow));
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value)
 {
     bool didThrow;
-    return adoptRef(new SerializedScriptValue(value, 0, didThrow));
+    return adoptRef(new SerializedScriptValue(value, 0, 0, didThrow));
 }
 
 PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(const String& data)
@@ -2063,14 +2135,60 @@ SerializedScriptValue::SerializedScriptValue()
 {
 }
 
-SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, bool& didThrow)
+static void neuterBinding(void* domObject) 
+{
+    DOMDataList& allStores = DOMDataStore::allStores();
+    for (size_t i = 0; i < allStores.size(); i++) {
+        v8::Handle<v8::Object> obj = allStores[i]->domObjectMap().get(domObject);
+        if (!obj.IsEmpty())
+            obj->SetIndexedPropertiesToExternalArrayData(0, v8::kExternalByteArray, 0);
+    }
+}
+
+PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(ArrayBufferArray& arrayBuffers, bool& didThrow) 
+{
+    for (size_t i = 0; i < arrayBuffers.size(); i++) {
+        if (arrayBuffers[i]->isNeutered()) {
+            throwError(INVALID_STATE_ERR);
+            didThrow = true;
+            return nullptr;
+        }
+    }
+
+    OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
+
+    HashSet<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) {
+            throwError(INVALID_STATE_ERR);
+            didThrow = true;
+            return nullptr;
+        }
+
+        neuterBinding(arrayBuffers[i].get());
+        for (size_t j = 0; j < neuteredViews.size(); j++)
+            neuterBinding(neuteredViews[j].get());
+    }
+    return contents.release();
+}
+
+SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, 
+                                             MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers,
+                                             bool& didThrow)
 {
     didThrow = false;
     Writer writer;
     Serializer::Status status;
     {
         v8::TryCatch tryCatch;
-        Serializer serializer(writer, messagePorts, tryCatch);
+        Serializer serializer(writer, messagePorts, arrayBuffers, tryCatch);
         status = serializer.serialize(value);
         if (status == Serializer::JSException) {
             // If there was a JS exception thrown, re-throw it.
@@ -2087,6 +2205,10 @@ SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, Messag
         didThrow = true;
         throwError(DATA_CLONE_ERR);
         return;
+    case Serializer::InvalidStateError:
+        didThrow = true;
+        throwError(INVALID_STATE_ERR);
+        return;
     case Serializer::JSFailure:
         // If there was a JS failure (but no exception), there's not
         // much we can do except for unwinding the C++ stack by
@@ -2095,6 +2217,8 @@ SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, Messag
         return;
     case Serializer::Success:
         m_data = String(StringImpl::adopt(writer.data())).isolatedCopy();
+        if (arrayBuffers)
+            m_arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, didThrow);
         return;
     case Serializer::JSException:
         // We should never get here because this case was handled above.
@@ -2114,7 +2238,7 @@ v8::Handle<v8::Value> SerializedScriptValue::deserialize(MessagePortArray* messa
         return v8::Null();
     COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
     Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters()), 2 * m_data.length());
-    Deserializer deserializer(reader, messagePorts);
+    Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.get());
     return deserializer.deserialize();
 }
 
index 1b56ed2..25da889 100644 (file)
 #ifndef SerializedScriptValue_h
 #define SerializedScriptValue_h
 
+#include "ArrayBuffer.h"
 #include "ScriptValue.h"
 #include <v8.h>
 #include <wtf/Threading.h>
 
-namespace WTF {
-class ArrayBuffer;
-}
-
 namespace WebCore {
 
 class MessagePort;
@@ -83,12 +80,16 @@ private:
         StringValue,
         WireData
     };
+    typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray;
 
     SerializedScriptValue();
-    SerializedScriptValue(v8::Handle<v8::Value>, MessagePortArray*, bool& didThrow);
+    SerializedScriptValue(v8::Handle<v8::Value>, MessagePortArray*, ArrayBufferArray*, bool& didThrow);
     explicit SerializedScriptValue(const String& wireData);
 
+    static PassOwnPtr<ArrayBufferContentsArray> transferArrayBuffers(ArrayBufferArray&, bool& didThrow);
+
     String m_data;
+    OwnPtr<ArrayBufferContentsArray> m_arrayBufferContentsArray;
 };
 
 } // namespace WebCore