SharedArrayBuffer does not need to be in the transfer list
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Feb 2017 02:42:20 +0000 (02:42 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Feb 2017 02:42:20 +0000 (02:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=168079

Reviewed by Geoffrey Garen and Keith Miller.
Source/JavaScriptCore:

Exposes a simple shareWith() API for when you know you want to share the contents of
a shared buffer. Also a useful explicit operator bool.

* runtime/ArrayBuffer.cpp:
(JSC::ArrayBuffer::shareWith):
* runtime/ArrayBuffer.h:
(JSC::ArrayBufferContents::operator bool):

Source/WebCore:

Tests: workers/sab/multi-memory-multi-buffer.html
       workers/sab/multi-memory.html
       workers/sab/no-transfer.html
       workers/sab/postMessage-clones.html
       workers/sab/sent-from-worker-no-transfer.html
       workers/sab/sent-from-worker-transfer.html

The SAB API that we originally implemented required that SABs get put in transfer lists
when they are sent to workers.

The new SAB API that everyone is converging towards requires that you do not put the
SAB in the transfer list. That's supposed to be an error. Instead, anytime that a SAB
is part of any message to or from a dedicated worker then it is automatically shared.

The new API provides a lot more clarity about what is supposed to happen in contexts
that support transfering but don't support sharing.

Right now this patch allows both styles to work, but I hope we can disable the transfer
list capability soon.

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::deserializeIDBValueToJSValue):
* bindings/js/JSMessageEventCustom.cpp:
(WebCore::JSMessageEvent::data):
* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::serialize):
(WebCore::CloneSerializer::CloneSerializer):
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneDeserializer::deserialize):
(WebCore::CloneDeserializer::CloneDeserializer):
(WebCore::CloneDeserializer::readTerminal):
(WebCore::SerializedScriptValue::SerializedScriptValue):
(WebCore::SerializedScriptValue::create):
(WebCore::SerializedScriptValue::deserialize):
* bindings/js/SerializedScriptValue.h:
(): Deleted.
* dom/CustomEvent.cpp:
(WebCore::CustomEvent::trySerializeDetail):
* dom/ErrorEvent.cpp:
(WebCore::ErrorEvent::trySerializeError):
* dom/MessageEvent.cpp:
(WebCore::MessageEvent::trySerializeData):
* dom/PopStateEvent.cpp:
(WebCore::PopStateEvent::trySerializeState):
* workers/DedicatedWorkerGlobalScope.cpp:
(WebCore::DedicatedWorkerGlobalScope::postMessage):
* workers/Worker.cpp:
(WebCore::Worker::postMessage):

LayoutTests:

This adds tests that ensure that SABs behave correctly (are either cloned or shared)
depending on context, and that we currently share SABs whether they are in the transfer
list or not. This also adds tests for SABs being passed around via more complicated
data structures.

* workers/sab/multi-memory-expected.txt: Added.
* workers/sab/multi-memory-multi-buffer-expected.txt: Added.
* workers/sab/multi-memory-multi-buffer.html: Added.
* workers/sab/multi-memory-worker-1.js: Added.
(onmessage):
* workers/sab/multi-memory-worker-2.js: Added.
(onmessage):
* workers/sab/multi-memory.html: Added.
* workers/sab/no-transfer-expected.txt: Added.
* workers/sab/no-transfer.html: Added.
* workers/sab/postMessage-clones-expected.txt: Added.
* workers/sab/postMessage-clones.html: Added.
* workers/sab/sab-creator-no-transfer.js: Added.
* workers/sab/sab-creator-transfer.js: Added.
* workers/sab/sent-from-worker-no-transfer-expected.txt: Added.
* workers/sab/sent-from-worker-no-transfer.html: Added.
* workers/sab/sent-from-worker-transfer-expected.txt: Added.
* workers/sab/sent-from-worker-transfer.html: Added.
* workers/sab/worker-resources.js:

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

32 files changed:
LayoutTests/ChangeLog
LayoutTests/workers/sab/multi-memory-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/multi-memory-multi-buffer-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/multi-memory-multi-buffer.html [new file with mode: 0644]
LayoutTests/workers/sab/multi-memory-worker-1.js [new file with mode: 0644]
LayoutTests/workers/sab/multi-memory-worker-2.js [new file with mode: 0644]
LayoutTests/workers/sab/multi-memory.html [new file with mode: 0644]
LayoutTests/workers/sab/no-transfer-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/no-transfer.html [new file with mode: 0644]
LayoutTests/workers/sab/postMessage-clones-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/postMessage-clones.html [new file with mode: 0644]
LayoutTests/workers/sab/sab-creator-no-transfer.js [new file with mode: 0644]
LayoutTests/workers/sab/sab-creator-transfer.js [new file with mode: 0644]
LayoutTests/workers/sab/sent-from-worker-no-transfer-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/sent-from-worker-no-transfer.html [new file with mode: 0644]
LayoutTests/workers/sab/sent-from-worker-transfer-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/sent-from-worker-transfer.html [new file with mode: 0644]
LayoutTests/workers/sab/worker-resources.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayBuffer.cpp
Source/JavaScriptCore/runtime/ArrayBuffer.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/IDBBindingUtilities.cpp
Source/WebCore/bindings/js/JSMessageEventCustom.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.h
Source/WebCore/dom/CustomEvent.cpp
Source/WebCore/dom/ErrorEvent.cpp
Source/WebCore/dom/MessageEvent.cpp
Source/WebCore/dom/PopStateEvent.cpp
Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp
Source/WebCore/workers/Worker.cpp

index ff0450b..1b7f6dc 100644 (file)
@@ -1,3 +1,35 @@
+2017-02-09  Filip Pizlo  <fpizlo@apple.com>
+
+        SharedArrayBuffer does not need to be in the transfer list
+        https://bugs.webkit.org/show_bug.cgi?id=168079
+
+        Reviewed by Geoffrey Garen and Keith Miller.
+        
+        This adds tests that ensure that SABs behave correctly (are either cloned or shared)
+        depending on context, and that we currently share SABs whether they are in the transfer
+        list or not. This also adds tests for SABs being passed around via more complicated
+        data structures.
+
+        * workers/sab/multi-memory-expected.txt: Added.
+        * workers/sab/multi-memory-multi-buffer-expected.txt: Added.
+        * workers/sab/multi-memory-multi-buffer.html: Added.
+        * workers/sab/multi-memory-worker-1.js: Added.
+        (onmessage):
+        * workers/sab/multi-memory-worker-2.js: Added.
+        (onmessage):
+        * workers/sab/multi-memory.html: Added.
+        * workers/sab/no-transfer-expected.txt: Added.
+        * workers/sab/no-transfer.html: Added.
+        * workers/sab/postMessage-clones-expected.txt: Added.
+        * workers/sab/postMessage-clones.html: Added.
+        * workers/sab/sab-creator-no-transfer.js: Added.
+        * workers/sab/sab-creator-transfer.js: Added.
+        * workers/sab/sent-from-worker-no-transfer-expected.txt: Added.
+        * workers/sab/sent-from-worker-no-transfer.html: Added.
+        * workers/sab/sent-from-worker-transfer-expected.txt: Added.
+        * workers/sab/sent-from-worker-transfer.html: Added.
+        * workers/sab/worker-resources.js:
+
 2017-02-09  Chris Dumez  <cdumez@apple.com>
 
         Make sure Event keeps its current target element alive
diff --git a/LayoutTests/workers/sab/multi-memory-expected.txt b/LayoutTests/workers/sab/multi-memory-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/multi-memory-multi-buffer-expected.txt b/LayoutTests/workers/sab/multi-memory-multi-buffer-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/multi-memory-multi-buffer.html b/LayoutTests/workers/sab/multi-memory-multi-buffer.html
new file mode 100644 (file)
index 0000000..547ad5e
--- /dev/null
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var didStart = new Int32Array(new SharedArrayBuffer(4), 0, 1);
+var shouldGo = new Int32Array(new SharedArrayBuffer(4), 0, 1);
+var didEnd = new Int32Array(new SharedArrayBuffer(4), 0, 1);
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage({didStart: didStart, shouldGo: shouldGo, didEnd: didEnd, shouldShareBuffer: false});
+}
+
+function done()
+{
+    if (didStart[0] != 1)
+        throw "Error: Bad value at didStart[0]: " + didStart[0];
+    if (shouldGo[0] != 1)
+        throw "Error: Bad value at shouldGo[0]: " + shouldGo[0];
+    if (didEnd[0] != 1)
+        throw "Error: Bad value at didEnd[0]: " + didEnd[0];
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+startWorker("multi-memory-worker-1.js");
+startWorker("multi-memory-worker-2.js");
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/multi-memory-worker-1.js b/LayoutTests/workers/sab/multi-memory-worker-1.js
new file mode 100644 (file)
index 0000000..53d0f1a
--- /dev/null
@@ -0,0 +1,29 @@
+importScripts("worker-resources.js");
+
+onmessage = function (event) {
+    var didStart = event.data.didStart;
+    var shouldGo = event.data.shouldGo;
+    var didEnd = event.data.didEnd;
+
+    checkBufferSharing(event.data.shouldShareBuffer, didStart, shouldGo, didEnd);
+    
+    postMessage("Started!");
+    postMessage("didStart: " + didStart);
+    postMessage("shouldGo: " + shouldGo);
+    postMessage("didEnd: " + didEnd);
+    
+    wait(didStart, 0, 0, 1);
+    
+    postMessage("It started!");
+    
+    shouldGo[0] = 1;
+    wake(shouldGo, 0);
+    
+    wait(didEnd, 0, 0, 1);
+    
+    postMessage("All done!");
+    postMessage("didStart: " + didStart);
+    postMessage("shouldGo: " + shouldGo);
+    postMessage("didEnd: " + didEnd);
+    postMessage("done");
+}
diff --git a/LayoutTests/workers/sab/multi-memory-worker-2.js b/LayoutTests/workers/sab/multi-memory-worker-2.js
new file mode 100644 (file)
index 0000000..05a8a8c
--- /dev/null
@@ -0,0 +1,27 @@
+importScripts("worker-resources.js");
+
+onmessage = function(event) {
+    var didStart = event.data.didStart;
+    var shouldGo = event.data.shouldGo;
+    var didEnd = event.data.didEnd;
+
+    checkBufferSharing(event.data.shouldShareBuffer, didStart, shouldGo, didEnd);
+    
+    postMessage("Started!");
+    postMessage("didStart: " + didStart);
+    postMessage("shouldGo: " + shouldGo);
+    postMessage("didEnd: " + didEnd);
+    
+    Atomics.store(didStart, 0, 1);
+    wake(didStart, 0);
+
+    wait(shouldGo, 0, 0, 1);
+    
+    Atomics.store(didEnd, 0, 1);
+    wake(didEnd, 0, 1);
+
+    postMessage("didStart: " + didStart);
+    postMessage("shouldGo: " + shouldGo);
+    postMessage("didEnd: " + didEnd);
+    postMessage("done");
+}
diff --git a/LayoutTests/workers/sab/multi-memory.html b/LayoutTests/workers/sab/multi-memory.html
new file mode 100644 (file)
index 0000000..be51a60
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var sab = new SharedArrayBuffer(3 * 4);
+
+var didStart = new Int32Array(sab, 0, 1);
+var shouldGo = new Int32Array(sab, 4, 1);
+var didEnd = new Int32Array(sab, 8, 1);
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage({didStart: didStart, shouldGo: shouldGo, didEnd: didEnd, shouldShareBuffer: true});
+}
+
+function done()
+{
+    if (didStart[0] != 1)
+        throw "Error: Bad value at didStart[0]: " + didStart[0];
+    if (shouldGo[0] != 1)
+        throw "Error: Bad value at shouldGo[0]: " + shouldGo[0];
+    if (didEnd[0] != 1)
+        throw "Error: Bad value at didEnd[0]: " + didEnd[0];
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+startWorker("multi-memory-worker-1.js");
+startWorker("multi-memory-worker-2.js");
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/no-transfer-expected.txt b/LayoutTests/workers/sab/no-transfer-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/no-transfer.html b/LayoutTests/workers/sab/no-transfer.html
new file mode 100644 (file)
index 0000000..36a61f0
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var sab = new SharedArrayBuffer(100 * 4);
+
+var memory = new Int32Array(sab);
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage(memory);
+}
+
+function done()
+{
+    for (var i = 0; i < 3; ++i) {
+        if (memory[i] != 1)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    for (var i = 3; i < memory.length; ++i) {
+        if (memory[i] != 0)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+startWorker("simple-worker-1.js");
+startWorker("simple-worker-2.js");
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/postMessage-clones-expected.txt b/LayoutTests/workers/sab/postMessage-clones-expected.txt
new file mode 100644 (file)
index 0000000..a8a0b45
--- /dev/null
@@ -0,0 +1,13 @@
+Checks that window.postMessage clones SharedArrayBuffers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS memory[0] is 42
+PASS otherMemory[0] is 0
+PASS memory[0] is 42
+PASS otherMemory[0] is 43
+
diff --git a/LayoutTests/workers/sab/postMessage-clones.html b/LayoutTests/workers/sab/postMessage-clones.html
new file mode 100644 (file)
index 0000000..0bb5f92
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description("Checks that window.postMessage clones SharedArrayBuffers");
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+var sab = new SharedArrayBuffer(4);
+var memory = new Int32Array(sab);
+var otherMemory;
+
+window.addEventListener("message", function (event) {
+    otherMemory = event.data;
+    memory[0] = 42;
+    shouldBe("memory[0]", "42");
+    shouldBe("otherMemory[0]", "0");
+    otherMemory[0] = 43;
+    shouldBe("memory[0]", "42");
+    shouldBe("otherMemory[0]", "43");
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+
+postMessage(memory, "*");
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/sab-creator-no-transfer.js b/LayoutTests/workers/sab/sab-creator-no-transfer.js
new file mode 100644 (file)
index 0000000..20bf567
--- /dev/null
@@ -0,0 +1,4 @@
+var sab = new SharedArrayBuffer(100 * 4);
+var memory = new Int32Array(sab);
+postMessage(memory);
+
diff --git a/LayoutTests/workers/sab/sab-creator-transfer.js b/LayoutTests/workers/sab/sab-creator-transfer.js
new file mode 100644 (file)
index 0000000..ebccd28
--- /dev/null
@@ -0,0 +1,4 @@
+var sab = new SharedArrayBuffer(100 * 4);
+var memory = new Int32Array(sab);
+postMessage(memory, [sab]);
+
diff --git a/LayoutTests/workers/sab/sent-from-worker-no-transfer-expected.txt b/LayoutTests/workers/sab/sent-from-worker-no-transfer-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/sent-from-worker-no-transfer.html b/LayoutTests/workers/sab/sent-from-worker-no-transfer.html
new file mode 100644 (file)
index 0000000..188a09d
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var memory;
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage(memory);
+}
+
+function done()
+{
+    for (var i = 0; i < 3; ++i) {
+        if (memory[i] != 1)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    for (var i = 3; i < memory.length; ++i) {
+        if (memory[i] != 0)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+var sabCreator = new Worker("sab-creator-no-transfer.js");
+sabCreator.onmessage = function(event) {
+    memory = event.data;
+    
+    startWorker("simple-worker-1.js");
+    startWorker("simple-worker-2.js");
+};
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/sent-from-worker-transfer-expected.txt b/LayoutTests/workers/sab/sent-from-worker-transfer-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/sent-from-worker-transfer.html b/LayoutTests/workers/sab/sent-from-worker-transfer.html
new file mode 100644 (file)
index 0000000..923af14
--- /dev/null
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var sab;
+var memory;
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage(memory, [sab]);
+}
+
+function done()
+{
+    for (var i = 0; i < 3; ++i) {
+        if (memory[i] != 1)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    for (var i = 3; i < memory.length; ++i) {
+        if (memory[i] != 0)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+var sabCreator = new Worker("sab-creator-transfer.js");
+sabCreator.onmessage = function(event) {
+    memory = event.data;
+    sab = memory.buffer;
+    
+    startWorker("simple-worker-1.js");
+    startWorker("simple-worker-2.js");
+};
+
+</script>
+</body>
+</html>
index 941e87f..d537817 100644 (file)
@@ -33,3 +33,21 @@ function wake(memory, index)
     }
 }
 
+function checkBufferSharing(shouldShareBuffer)
+{
+    var set = new Set();
+    for (var i = 1; i < arguments.length; ++i)
+        set.add(arguments[i].buffer);
+    if (shouldShareBuffer) {
+        if (set.size != 1) {
+            postMessage("Error: buffers should be shared but are not shared (set.size == " + set.size + ")");
+            postMessage("error");
+        }
+    } else {
+        if (set.size != arguments.length - 1) {
+            postMessage("Error: buffers should not be shared but are shared");
+            postMessage("error");
+        }
+    }
+}
+
index c46d8e5..37a106e 100644 (file)
@@ -1,3 +1,18 @@
+2017-02-09  Filip Pizlo  <fpizlo@apple.com>
+
+        SharedArrayBuffer does not need to be in the transfer list
+        https://bugs.webkit.org/show_bug.cgi?id=168079
+
+        Reviewed by Geoffrey Garen and Keith Miller.
+        
+        Exposes a simple shareWith() API for when you know you want to share the contents of
+        a shared buffer. Also a useful explicit operator bool.
+
+        * runtime/ArrayBuffer.cpp:
+        (JSC::ArrayBuffer::shareWith):
+        * runtime/ArrayBuffer.h:
+        (JSC::ArrayBufferContents::operator bool):
+
 2017-02-09  Mark Lam  <mark.lam@apple.com>
 
         B3::Procedure::deleteOrphans() should neutralize upsilons with dead phis.
index a8e3902..bb9cfc4 100644 (file)
@@ -284,6 +284,17 @@ void ArrayBuffer::setSharingMode(ArrayBufferSharingMode newSharingMode)
     makeShared();
 }
 
+bool ArrayBuffer::shareWith(ArrayBufferContents& result)
+{
+    if (!m_contents.m_data || !isShared()) {
+        result.m_data = nullptr;
+        return false;
+    }
+    
+    m_contents.shareWith(result);
+    return true;
+}
+
 bool ArrayBuffer::transferTo(VM& vm, ArrayBufferContents& result)
 {
     Ref<ArrayBuffer> protect(*this);
index d3842e2..46ffdb5 100644 (file)
@@ -65,6 +65,8 @@ public:
     
     JS_EXPORT_PRIVATE void clear();
     
+    explicit operator bool() { return !!m_data; }
+    
     void* data() const { return m_data; }
     unsigned sizeInBytes() const { return m_sizeInBytes; }
     
@@ -131,6 +133,7 @@ public:
     inline void pinAndLock();
 
     JS_EXPORT_PRIVATE bool transferTo(VM&, ArrayBufferContents&);
+    JS_EXPORT_PRIVATE bool shareWith(ArrayBufferContents&);
     bool isNeutered() { return !m_contents.m_data; }
     
     static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); }
index 71ca2c6..3865857 100644 (file)
@@ -1,3 +1,59 @@
+2017-02-09  Filip Pizlo  <fpizlo@apple.com>
+
+        SharedArrayBuffer does not need to be in the transfer list
+        https://bugs.webkit.org/show_bug.cgi?id=168079
+
+        Reviewed by Geoffrey Garen and Keith Miller.
+
+        Tests: workers/sab/multi-memory-multi-buffer.html
+               workers/sab/multi-memory.html
+               workers/sab/no-transfer.html
+               workers/sab/postMessage-clones.html
+               workers/sab/sent-from-worker-no-transfer.html
+               workers/sab/sent-from-worker-transfer.html
+
+        The SAB API that we originally implemented required that SABs get put in transfer lists
+        when they are sent to workers.
+        
+        The new SAB API that everyone is converging towards requires that you do not put the
+        SAB in the transfer list. That's supposed to be an error. Instead, anytime that a SAB
+        is part of any message to or from a dedicated worker then it is automatically shared.
+        
+        The new API provides a lot more clarity about what is supposed to happen in contexts
+        that support transfering but don't support sharing.
+        
+        Right now this patch allows both styles to work, but I hope we can disable the transfer
+        list capability soon.
+
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::deserializeIDBValueToJSValue):
+        * bindings/js/JSMessageEventCustom.cpp:
+        (WebCore::JSMessageEvent::data):
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneSerializer::serialize):
+        (WebCore::CloneSerializer::CloneSerializer):
+        (WebCore::CloneSerializer::dumpIfTerminal):
+        (WebCore::CloneDeserializer::deserialize):
+        (WebCore::CloneDeserializer::CloneDeserializer):
+        (WebCore::CloneDeserializer::readTerminal):
+        (WebCore::SerializedScriptValue::SerializedScriptValue):
+        (WebCore::SerializedScriptValue::create):
+        (WebCore::SerializedScriptValue::deserialize):
+        * bindings/js/SerializedScriptValue.h:
+        (): Deleted.
+        * dom/CustomEvent.cpp:
+        (WebCore::CustomEvent::trySerializeDetail):
+        * dom/ErrorEvent.cpp:
+        (WebCore::ErrorEvent::trySerializeError):
+        * dom/MessageEvent.cpp:
+        (WebCore::MessageEvent::trySerializeData):
+        * dom/PopStateEvent.cpp:
+        (WebCore::PopStateEvent::trySerializeState):
+        * workers/DedicatedWorkerGlobalScope.cpp:
+        (WebCore::DedicatedWorkerGlobalScope::postMessage):
+        * workers/Worker.cpp:
+        (WebCore::Worker::postMessage):
+
 2017-02-09  Brent Fulgham  <bfulgham@apple.com>
 
         Unreviewed build fix after r212025.
index 5195e77..4af636f 100644 (file)
@@ -345,7 +345,7 @@ static JSValue deserializeIDBValueToJSValue(ExecState& state, JSC::JSGlobalObjec
 
     state.vm().apiLock().lock();
     Vector<RefPtr<MessagePort>> messagePorts;
-    JSValue result = serializedValue->deserialize(state, &globalObject, messagePorts, value.blobURLs(), value.blobFilePaths(), NonThrowing);
+    JSValue result = serializedValue->deserialize(state, &globalObject, messagePorts, value.blobURLs(), value.blobFilePaths(), SerializationErrorMode::NonThrowing);
     state.vm().apiLock().unlock();
 
     return result;
index f8b7e01..b5c5fb1 100644 (file)
@@ -80,7 +80,7 @@ JSValue JSMessageEvent::data(ExecState& state) const
         if (RefPtr<SerializedScriptValue> serializedValue = event.dataAsSerializedScriptValue()) {
             Vector<RefPtr<MessagePort>> ports = wrapped().ports();
             // FIXME: Why does this suppress exceptions?
-            result = serializedValue->deserialize(state, globalObject(), ports, NonThrowing);
+            result = serializedValue->deserialize(state, globalObject(), ports, SerializationErrorMode::NonThrowing);
         } else
             result = jsNull();
         break;
index ba951a5..aed6514 100644 (file)
@@ -144,6 +144,7 @@ enum SerializationTag {
 #if ENABLE(SUBTLE_CRYPTO)
     CryptoKeyTag = 33,
 #endif
+    SharedArrayBufferTag = 34,
     ErrorTag = 255
 };
 
@@ -476,9 +477,9 @@ template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8
 
 class CloneSerializer : CloneBase {
 public:
-    static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
+    static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
     {
-        CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out);
+        CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out, context, sharedBuffers);
         return serializer.serialize(value);
     }
 
@@ -525,11 +526,13 @@ public:
 private:
     typedef HashMap<JSObject*, uint32_t> ObjectPool;
 
-    CloneSerializer(ExecState* exec, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out)
+    CloneSerializer(ExecState* exec, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers)
         : CloneBase(exec)
         , m_buffer(out)
         , m_blobURLs(blobURLs)
         , m_emptyIdentifier(Identifier::fromString(exec, emptyString()))
+        , m_context(context)
+        , m_sharedBuffers(sharedBuffers)
     {
         write(CurrentVersion);
         fillTransferMap(messagePorts, m_transferredMessagePorts);
@@ -861,6 +864,19 @@ private:
                 }
                 if (!startObjectInternal(obj)) // handle duplicates
                     return true;
+                
+                if (arrayBuffer->isShared()
+                    && m_context == SerializationContext::WorkerPostMessage) {
+                    uint32_t index = m_sharedBuffers.size();
+                    ArrayBufferContents contents;
+                    if (arrayBuffer->shareWith(contents)) {
+                        write(SharedArrayBufferTag);
+                        m_sharedBuffers.append(WTFMove(contents));
+                        write(index);
+                        return true;
+                    }
+                }
+                
                 write(ArrayBufferTag);
                 write(arrayBuffer->byteLength());
                 write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength());
@@ -880,7 +896,8 @@ private:
                 Vector<String> dummyBlobURLs;
                 Vector<RefPtr<MessagePort>> dummyMessagePorts;
                 Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
-                CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, dummyBlobURLs, serializedKey);
+                ArrayBufferContentsArray dummySharedBuffers;
+                CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, dummyBlobURLs, serializedKey, SerializationContext::Default, dummySharedBuffers);
                 rawKeySerializer.write(key);
                 Vector<uint8_t> wrappedKey;
                 if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey))
@@ -1218,6 +1235,8 @@ private:
     typedef HashMap<RefPtr<UniquedStringImpl>, uint32_t, IdentifierRepHash> StringConstantPool;
     StringConstantPool m_constantPool;
     Identifier m_emptyIdentifier;
+    SerializationContext m_context;
+    ArrayBufferContentsArray& m_sharedBuffers;
 };
 
 SerializationReturnCode CloneSerializer::serialize(JSValue in)
@@ -1489,11 +1508,11 @@ public:
         return str;
     }
 
-    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths)
+    static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers)
     {
         if (!buffer.size())
             return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
-        CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths);
+        CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths, sharedBuffers);
         if (!deserializer.isValid())
             return std::make_pair(JSValue(), SerializationReturnCode::ValidationError);
         return deserializer.deserialize();
@@ -1553,7 +1572,7 @@ private:
             m_version = 0xFFFFFFFF;
     }
 
-    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths)
+    CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers)
         : CloneBase(exec)
         , m_globalObject(globalObject)
         , m_isDOMGlobalObject(globalObject->inherits(globalObject->vm(), JSDOMGlobalObject::info()))
@@ -1565,6 +1584,7 @@ private:
         , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
         , m_blobURLs(blobURLs)
         , m_blobFilePaths(blobFilePaths)
+        , m_sharedBuffers(sharedBuffers)
     {
         if (!read(m_version))
             m_version = 0xFFFFFFFF;
@@ -2387,6 +2407,20 @@ private:
 
             return getJSValue(m_arrayBuffers[index].get());
         }
+        case SharedArrayBufferTag: {
+            uint32_t index = UINT_MAX;
+            bool indexSuccessfullyRead = read(index);
+            if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) {
+                fail();
+                return JSValue();
+            }
+            
+            RELEASE_ASSERT(m_sharedBuffers->at(index));
+            RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index)));
+            JSValue result = getJSValue(buffer.get());
+            m_gcBuffer.append(result);
+            return result;
+        }
         case ArrayBufferViewTag: {
             JSValue arrayBufferView;
             if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) {
@@ -2445,6 +2479,7 @@ private:
     Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers;
     Vector<String> m_blobURLs;
     Vector<String> m_blobFilePaths;
+    ArrayBufferContentsArray* m_sharedBuffers;
 
     String blobFilePathForBlobURL(const String& blobURL)
     {
@@ -2654,9 +2689,10 @@ SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer)
 {
 }
 
-SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray>&& arrayBufferContentsArray)
+SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray, std::unique_ptr<ArrayBufferContentsArray> sharedBufferContentsArray)
     : m_data(WTFMove(buffer))
     , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray))
+    , m_sharedBufferContentsArray(WTFMove(sharedBufferContentsArray))
 {
     // Since this SerializedScriptValue is meant to be passed between threads, its String data members
     // need to be isolatedCopies so we don't run into thread safety issues for the StringImpls.
@@ -2741,18 +2777,19 @@ RefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState& exec, JSV
     Vector<String> blobURLs;
     Vector<RefPtr<MessagePort>> dummyMessagePorts;
     Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
-    auto code = CloneSerializer::serialize(&exec, value, dummyMessagePorts, dummyArrayBuffers, blobURLs, buffer);
+    ArrayBufferContentsArray dummySharedBuffers;
+    auto code = CloneSerializer::serialize(&exec, value, dummyMessagePorts, dummyArrayBuffers, blobURLs, buffer, SerializationContext::Default, dummySharedBuffers);
 
-    if (throwExceptions == Throwing)
+    if (throwExceptions == SerializationErrorMode::Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, code);
 
     if (code != SerializationReturnCode::SuccessfullyCompleted)
         return nullptr;
 
-    return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, nullptr));
+    return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, nullptr, nullptr));
 }
 
-ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState& state, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts)
+ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState& state, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationContext context)
 {
     VM& vm = state.vm();
     Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers;
@@ -2760,6 +2797,8 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState&
         if (auto arrayBuffer = toPossiblySharedArrayBuffer(vm, transferable.get())) {
             if (arrayBuffer->isNeutered())
                 return Exception { DATA_CLONE_ERR };
+            if (arrayBuffer->isShared() && context != SerializationContext::WorkerPostMessage)
+                return Exception { DATA_CLONE_ERR };
             arrayBuffers.append(WTFMove(arrayBuffer));
             continue;
         }
@@ -2774,7 +2813,8 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState&
 
     Vector<uint8_t> buffer;
     Vector<String> blobURLs;
-    auto code = CloneSerializer::serialize(&state, value, messagePorts, arrayBuffers, blobURLs, buffer);
+    std::unique_ptr<ArrayBufferContentsArray> sharedBuffers = std::make_unique<ArrayBufferContentsArray>();
+    auto code = CloneSerializer::serialize(&state, value, messagePorts, arrayBuffers, blobURLs, buffer, context, *sharedBuffers);
 
     if (code != SerializationReturnCode::SuccessfullyCompleted)
         return exceptionForSerializationFailure(code);
@@ -2783,7 +2823,7 @@ ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState&
     if (arrayBufferContentsArray.hasException())
         return arrayBufferContentsArray.releaseException();
 
-    return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, arrayBufferContentsArray.releaseReturnValue()));
+    return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, arrayBufferContentsArray.releaseReturnValue(), context == SerializationContext::WorkerPostMessage ? WTFMove(sharedBuffers) : nullptr));
 }
 
 RefPtr<SerializedScriptValue> SerializedScriptValue::create(StringView string)
@@ -2833,8 +2873,8 @@ JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* glob
 
 JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions)
 {
-    DeserializationResult result = CloneDeserializer::deserialize(&exec, globalObject, messagePorts, m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths);
-    if (throwExceptions == Throwing)
+    DeserializationResult result = CloneDeserializer::deserialize(&exec, globalObject, messagePorts, m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get());
+    if (throwExceptions == SerializationErrorMode::Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, result.second);
     return result.first ? result.first : jsNull();
 }
index 2f5267f..1729011 100644 (file)
@@ -45,15 +45,16 @@ class MessagePort;
 class SharedBuffer;
 enum class SerializationReturnCode;
 
-enum SerializationErrorMode { NonThrowing, Throwing };
+enum class SerializationErrorMode { NonThrowing, Throwing };
+enum class SerializationContext { Default, WorkerPostMessage };
 
 using ArrayBufferContentsArray = Vector<JSC::ArrayBufferContents>;
 
 class SerializedScriptValue : public ThreadSafeRefCounted<SerializedScriptValue> {
 public:
-    WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSC::ExecState&, JSC::JSValue, SerializationErrorMode = Throwing);
+    WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSC::ExecState&, JSC::JSValue, SerializationErrorMode = SerializationErrorMode::Throwing);
 
-    WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::ExecState&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&&, Vector<RefPtr<MessagePort>>&);
+    WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::ExecState&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, Vector<RefPtr<MessagePort>>&, SerializationContext = SerializationContext::Default);
 
     WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(StringView);
     static Ref<SerializedScriptValue> adopt(Vector<uint8_t>&& buffer)
@@ -63,9 +64,9 @@ public:
 
     static Ref<SerializedScriptValue> nullValue();
 
-    WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, SerializationErrorMode = Throwing);
-    WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, SerializationErrorMode = Throwing);
-    JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = Throwing);
+    WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, SerializationErrorMode = SerializationErrorMode::Throwing);
+    WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, SerializationErrorMode = SerializationErrorMode::Throwing);
+    JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing);
 
     static uint32_t wireFormatVersion();
 
@@ -94,10 +95,11 @@ public:
 
 private:
     WEBCORE_EXPORT SerializedScriptValue(Vector<unsigned char>&&);
-    SerializedScriptValue(Vector<unsigned char>&&, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray>&&);
+    SerializedScriptValue(Vector<unsigned char>&&, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray>, std::unique_ptr<ArrayBufferContentsArray> sharedBuffers);
 
     Vector<unsigned char> m_data;
     std::unique_ptr<ArrayBufferContentsArray> m_arrayBufferContentsArray;
+    std::unique_ptr<ArrayBufferContentsArray> m_sharedBufferContentsArray;
     Vector<String> m_blobURLs;
 };
 
index 7557e60..080cab4 100644 (file)
@@ -60,7 +60,7 @@ void CustomEvent::initCustomEvent(JSC::ExecState& state, const AtomicString& typ
 RefPtr<SerializedScriptValue> CustomEvent::trySerializeDetail(JSC::ExecState& state)
 {
     if (!m_triedToSerialize) {
-        m_serializedDetail = SerializedScriptValue::create(state, m_detail, NonThrowing);
+        m_serializedDetail = SerializedScriptValue::create(state, m_detail, SerializationErrorMode::NonThrowing);
         m_triedToSerialize = true;
     }
     return m_serializedDetail;
index 32a95f1..ce7f8ca 100644 (file)
@@ -91,7 +91,7 @@ JSValue ErrorEvent::error(ExecState& exec, JSGlobalObject& globalObject)
 RefPtr<SerializedScriptValue> ErrorEvent::trySerializeError(ExecState& exec)
 {
     if (!m_triedToSerialize) {
-        m_serializedDetail = SerializedScriptValue::create(exec, m_error.get(), NonThrowing);
+        m_serializedDetail = SerializedScriptValue::create(exec, m_error.get(), SerializationErrorMode::NonThrowing);
         m_triedToSerialize = true;
     }
     return m_serializedDetail;
index 5ba37cf..7031833 100644 (file)
@@ -168,7 +168,7 @@ RefPtr<SerializedScriptValue> MessageEvent::trySerializeData(ExecState* exec)
     ASSERT(!m_dataAsScriptValue.hasNoValue());
     
     if (!m_dataAsSerializedScriptValue && !m_triedToSerialize) {
-        m_dataAsSerializedScriptValue = SerializedScriptValue::create(*exec, m_dataAsScriptValue.jsValue(), NonThrowing);
+        m_dataAsSerializedScriptValue = SerializedScriptValue::create(*exec, m_dataAsScriptValue.jsValue(), SerializationErrorMode::NonThrowing);
         m_triedToSerialize = true;
     }
     
index a08294e..e4c6437 100644 (file)
@@ -70,7 +70,7 @@ RefPtr<SerializedScriptValue> PopStateEvent::trySerializeState(JSC::ExecState& e
     ASSERT(!m_state.hasNoValue());
     
     if (!m_serializedState && !m_triedToSerialize) {
-        m_serializedState = SerializedScriptValue::create(executionState, m_state.jsValue(), NonThrowing);
+        m_serializedState = SerializedScriptValue::create(executionState, m_state.jsValue(), SerializationErrorMode::NonThrowing);
         m_triedToSerialize = true;
     }
     
index 233bba2..cb9b634 100644 (file)
@@ -66,7 +66,7 @@ EventTargetInterface DedicatedWorkerGlobalScope::eventTargetInterface() const
 ExceptionOr<void> DedicatedWorkerGlobalScope::postMessage(JSC::ExecState& state, JSC::JSValue messageValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer)
 {
     Vector<RefPtr<MessagePort>> ports;
-    auto message = SerializedScriptValue::create(state, messageValue, WTFMove(transfer), ports);
+    auto message = SerializedScriptValue::create(state, messageValue, WTFMove(transfer), ports, SerializationContext::WorkerPostMessage);
     if (message.hasException())
         return message.releaseException();
 
index d8ee181..51348c2 100644 (file)
@@ -107,7 +107,7 @@ Worker::~Worker()
 ExceptionOr<void> Worker::postMessage(JSC::ExecState& state, JSC::JSValue messageValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer)
 {
     Vector<RefPtr<MessagePort>> ports;
-    auto message = SerializedScriptValue::create(state, messageValue, WTFMove(transfer), ports);
+    auto message = SerializedScriptValue::create(state, messageValue, WTFMove(transfer), ports, SerializationContext::WorkerPostMessage);
     if (message.hasException())
         return message.releaseException();