Communication between MessagePort instances created in a WebWorker thread stops after time. I suspect GC happening. The following test case is in 2 parts. An html page and a worker script. The worker creates a message channel and transfer one of the ports back to the main thread. The ports start communicating then after some 18 exchanges, the communication stops. I finally figured that if I kept the reference of the MessageChannel that create the ports around the problem disappeared. I looks like this shouldn't happen. The test cases creates some arraybuffers and discard them to trigger some GC. Test case: //--------------------------------------------------------------------------- // messagechannel_garbagecollected.html //--------------------------------------------------------------------------- <html> <body> <script> var worker = new Worker("./messagechannel_garbagecollected_worker.js"); var arrays = []; worker.addEventListener("message", (event) => { var port = event.data.port; port.addEventListener("message", (event) => { document.body.innerHTML += event.data + "<br />"; if (arrays.length === 10) { arrays = []; } arrays.push(new ArrayBuffer(500000)); setTimeout(function() { port.postMessage("ping"); }, 50); }); port.start(); port.postMessage("ping"); }); </script> </body> </html> //--------------------------------------------------------------------------- // messagechannel_garbagecollected_worker.js //--------------------------------------------------------------------------- var arrays = []; function startup() { var channel = new MessageChannel(); var port = channel.port1; var id = 0; port.addEventListener("message", (event) => { if (arrays.length === 10) { arrays = []; } arrays.push(new ArrayBuffer(50000)); setTimeout(function() { port.postMessage("pong " + id++); }, 50); }); port.start(); // keeping a dummy reference to the channel keeps it working // port["channel"] = channel; self.postMessage({ port: channel.port2 }, [channel.port2]); } startup();
<rdar://problem/39256714>
Created attachment 337935 [details] Patch
Comment on attachment 337935 [details] Patch Attachment 337935 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://webkit-queues.webkit.org/results/7311332 New failing tests: fast/events/message-channel-gc-4.html
Created attachment 337945 [details] Archive of layout-test-results from ews104 for mac-sierra-wk2 The attached test failures were seen while running run-webkit-tests on the mac-wk2-ews. Bot: ews104 Port: mac-sierra-wk2 Platform: Mac OS X 10.12.6
Comment on attachment 337935 [details] Patch Attachment 337935 [details] did not pass ios-sim-ews (ios-simulator-wk2): Output: http://webkit-queues.webkit.org/results/7311418 New failing tests: fast/events/message-channel-gc-4.html
Created attachment 337948 [details] Archive of layout-test-results from ews122 for ios-simulator-wk2 The attached test failures were seen while running run-webkit-tests on the ios-sim-ews. Bot: ews122 Port: ios-simulator-wk2 Platform: Mac OS X 10.13.4
Created attachment 338028 [details] Patch
Comment on attachment 338028 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=338028&action=review > Source/WebCore/dom/MessagePort.cpp:70 > - allMessagePorts().remove(m_identifier); > + if (allMessagePorts().get(m_identifier) == this) > + allMessagePorts().remove(m_identifier); The correct way to implement this without double hashing is: auto iterator = allMessagePorts().find(m_identifier); if (iterator != allMessagePorts().end() && iterator->value == this) allMessagePorts().remove(iterator); Messier than the above, but avoids a second hash table lookup.
Created attachment 338133 [details] Patch
Comment on attachment 338133 [details] Patch Clearing flags on attachment: 338133 Committed r230735: <https://trac.webkit.org/changeset/230735>
All reviewed patches have been landed. Closing bug.