<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[211194] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/211194">211194</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2017-01-25 18:34:30 -0800 (Wed, 25 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>jsc.cpp should have the $.agent stuff for testing SAB
https://bugs.webkit.org/show_bug.cgi?id=167431

Reviewed by Saam Barati.
        
JSTests:

Add a very basic test of Atomics using $.agent. This is based on
LayoutTests/workers/sab/simple.html.

* stress/lars-sab-workers.js: Added.
(startWorker):
(resources):
(wake):
(else):

Source/JavaScriptCore:

This adds some stuff that the SAB branch of test262 needs. None of this is exposed except for our
own tests and the SAB branch of test262. We now pass all of the Atomics tests in the SAB branch
of test262.
        
* jsc.cpp:
(Message::releaseContents):
(Message::index):
(GlobalObject::finishCreation):
(GlobalObject::addFunction):
(Message::Message):
(Message::~Message):
(Worker::Worker):
(Worker::~Worker):
(Worker::send):
(Worker::receive):
(Worker::current):
(Worker::currentWorker):
(Workers::Workers):
(Workers::~Workers):
(Workers::broadcast):
(Workers::report):
(Workers::tryGetReport):
(Workers::getReport):
(Workers::singleton):
(functionDollarCreateRealm):
(functionDollarDetachArrayBuffer):
(functionDollarEvalScript):
(functionDollarAgentStart):
(functionDollarAgentReceiveBroadcast):
(functionDollarAgentReport):
(functionDollarAgentSleep):
(functionDollarAgentBroadcast):
(functionDollarAgentGetReport):
(functionWaitForReport):
(checkException):
(runWithScripts):
(runJSC):
(jscmain):
* runtime/JSArrayBuffer.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayBufferh">trunk/Source/JavaScriptCore/runtime/JSArrayBuffer.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstresslarssabworkersjs">trunk/JSTests/stress/lars-sab-workers.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (211193 => 211194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/JSTests/ChangeLog        2017-01-26 02:34:30 UTC (rev 211194)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2017-01-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        jsc.cpp should have the $.agent stuff for testing SAB
+        https://bugs.webkit.org/show_bug.cgi?id=167431
+
+        Reviewed by Saam Barati.
+        
+        Add a very basic test of Atomics using $.agent. This is based on
+        LayoutTests/workers/sab/simple.html.
+
+        * stress/lars-sab-workers.js: Added.
+        (startWorker):
+        (resources):
+        (wake):
+        (else):
+
</ins><span class="cx"> 2017-01-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Atomics.store should return the int-converted value according to toInteger
</span></span></pre></div>
<a id="trunkJSTestsstresslarssabworkersjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/lars-sab-workers.js (0 => 211194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/lars-sab-workers.js                                (rev 0)
+++ trunk/JSTests/stress/lars-sab-workers.js        2017-01-26 02:34:30 UTC (rev 211194)
</span><span class="lines">@@ -0,0 +1,127 @@
</span><ins>+//@ defaultRunNoisyTest
+
+var sab = new SharedArrayBuffer(100 * 4);
+
+var memory = new Int32Array(sab);
+
+var numWorkers = 0;
+function startWorker(code)
+{
+    print(&quot;Starting worker!&quot;);
+    
+    numWorkers++;
+    $.agent.start(code);
+}
+
+resources = `
+function wait(memory, index, waitCondition, wakeCondition)
+{
+    while (memory[index] == waitCondition) {
+        var result = Atomics.wait(memory, index, waitCondition);
+        switch (result) {
+        case &quot;not-equal&quot;:
+        case &quot;ok&quot;:
+            break;
+        default:
+            $.agent.report(&quot;Error: bad result from wait: &quot; + result);
+            $.agent.report(&quot;error&quot;);
+            break;
+        }
+        var value = memory[index];
+        if (value != wakeCondition) {
+            $.agent.report(&quot;Error: wait returned not-equal but the memory has a bad value: &quot; + value);
+            $.agent.report(&quot;error&quot;);
+        }
+    }
+    var value = memory[index];
+    if (value != wakeCondition) {
+        $.agent.report(&quot;Error: done waiting but the memory has a bad value: &quot; + value);
+        $.agent.report(&quot;error&quot;);
+    }
+}
+
+function wake(memory, index)
+{
+    var result = Atomics.wake(memory, index, 1);
+    if (result != 0 &amp;&amp; result != 1) {
+        $.agent.report(&quot;Error: bad result from wake: &quot; + result);
+        $.agent.report(&quot;error&quot;);
+    }
+}
+`;
+
+startWorker(
+    resources + `
+    $.agent.receiveBroadcast(sab =&gt; {
+        var memory = new Int32Array(sab);
+        var didStartIdx = 0;
+        var shouldGoIdx = 1;
+        var didEndIdx = 2;
+        
+        $.agent.report(&quot;1: Started!&quot;);
+        $.agent.report(&quot;1: Memory: &quot; + memory);
+        
+        wait(memory, didStartIdx, 0, 1);
+        
+        $.agent.report(&quot;1: It started!&quot;);
+        
+        memory[shouldGoIdx] = 1;
+        wake(memory, shouldGoIdx);
+        
+        wait(memory, didEndIdx, 0, 1);
+        
+        $.agent.report(&quot;1: All done!&quot;);
+        $.agent.report(&quot;1: Memory: &quot; + memory);
+        $.agent.report(&quot;done&quot;);
+    });
+    `);
+
+startWorker(
+    resources + `
+    $.agent.receiveBroadcast(sab =&gt; {
+        var memory = new Int32Array(sab);
+        var didStartIdx = 0;
+        var shouldGoIdx = 1;
+        var didEndIdx = 2;
+        
+        $.agent.report(&quot;2: Started!&quot;);
+        $.agent.report(&quot;2: Memory: &quot; + memory);
+        
+        Atomics.store(memory, didStartIdx, 1);
+        wake(memory, didStartIdx);
+        
+        wait(memory, shouldGoIdx, 0, 1);
+        
+        Atomics.store(memory, didEndIdx, 1);
+        wake(memory, didEndIdx, 1);
+        
+        $.agent.report(&quot;2: Memory: &quot; + memory);
+        $.agent.report(&quot;done&quot;);
+    });
+    `);
+
+$.agent.broadcast(sab);
+
+for (;;) {
+    var report = waitForReport();
+    if (report == &quot;done&quot;) {
+        if (!--numWorkers) {
+            print(&quot;All workers done!&quot;);
+            break;
+        }
+    } else if (report == &quot;error&quot;) {
+        print(&quot;Test failed!&quot;);
+        throw new Error(&quot;Test failed.&quot;);
+    } else
+        print(&quot;report: &quot; + report);
+}
+
+for (var i = 0; i &lt; 3; ++i) {
+    if (memory[i] != 1)
+        throw &quot;Error: Bad value at memory[&quot; + i + &quot;]: &quot; + memory[i];
+}
+for (var i = 3; i &lt; memory.length; ++i) {
+    if (memory[i] != 0)
+        throw &quot;Error: Bad value at memory[&quot; + i + &quot;]: &quot; + memory[i];
+}
+print(&quot;Test passed!&quot;);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (211193 => 211194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-26 02:34:30 UTC (rev 211194)
</span><span class="lines">@@ -1,5 +1,52 @@
</span><span class="cx"> 2017-01-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        jsc.cpp should have the $.agent stuff for testing SAB
+        https://bugs.webkit.org/show_bug.cgi?id=167431
+
+        Reviewed by Saam Barati.
+        
+        This adds some stuff that the SAB branch of test262 needs. None of this is exposed except for our
+        own tests and the SAB branch of test262. We now pass all of the Atomics tests in the SAB branch
+        of test262.
+        
+        * jsc.cpp:
+        (Message::releaseContents):
+        (Message::index):
+        (GlobalObject::finishCreation):
+        (GlobalObject::addFunction):
+        (Message::Message):
+        (Message::~Message):
+        (Worker::Worker):
+        (Worker::~Worker):
+        (Worker::send):
+        (Worker::receive):
+        (Worker::current):
+        (Worker::currentWorker):
+        (Workers::Workers):
+        (Workers::~Workers):
+        (Workers::broadcast):
+        (Workers::report):
+        (Workers::tryGetReport):
+        (Workers::getReport):
+        (Workers::singleton):
+        (functionDollarCreateRealm):
+        (functionDollarDetachArrayBuffer):
+        (functionDollarEvalScript):
+        (functionDollarAgentStart):
+        (functionDollarAgentReceiveBroadcast):
+        (functionDollarAgentReport):
+        (functionDollarAgentSleep):
+        (functionDollarAgentBroadcast):
+        (functionDollarAgentGetReport):
+        (functionWaitForReport):
+        (checkException):
+        (runWithScripts):
+        (runJSC):
+        (jscmain):
+        * runtime/JSArrayBuffer.h:
+
+2017-01-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         ARM/ARM64 stress/atomics-store-return.js fails
</span><span class="cx">         &lt;rdar://problem/30192652&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (211193 => 211194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2017-01-26 02:34:30 UTC (rev 211194)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx"> #include &quot;ParserError.h&quot;
</span><span class="cx"> #include &quot;ProfilerDatabase.h&quot;
</span><span class="cx"> #include &quot;ProtoCallFrame.h&quot;
</span><ins>+#include &quot;ReleaseHeapAccessScope.h&quot;
</ins><span class="cx"> #include &quot;SamplingProfiler.h&quot;
</span><span class="cx"> #include &quot;ShadowChicken.h&quot;
</span><span class="cx"> #include &quot;StackVisitor.h&quot;
</span><span class="lines">@@ -908,6 +909,67 @@
</span><span class="cx"> 
</span><span class="cx"> static bool fillBufferWithContentsOfFile(const String&amp; fileName, Vector&lt;char&gt;&amp; buffer);
</span><span class="cx"> 
</span><ins>+class CommandLine;
+class GlobalObject;
+class Workers;
+
+template&lt;typename Func&gt;
+int runJSC(CommandLine, const Func&amp;);
+static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, const String&amp; uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool&amp; success);
+
+class Message : public ThreadSafeRefCounted&lt;Message&gt; {
+public:
+    Message(ArrayBufferContents&amp;&amp;, int32_t);
+    ~Message();
+    
+    ArrayBufferContents&amp;&amp; releaseContents() { return WTFMove(m_contents); }
+    int32_t index() const { return m_index; }
+
+private:
+    ArrayBufferContents m_contents;
+    int32_t m_index { 0 };
+};
+
+class Worker : public BasicRawSentinelNode&lt;Worker&gt; {
+public:
+    Worker(Workers&amp;);
+    ~Worker();
+    
+    void enqueue(const AbstractLocker&amp;, RefPtr&lt;Message&gt;);
+    RefPtr&lt;Message&gt; dequeue();
+    
+    static Worker&amp; current();
+
+private:
+    static ThreadSpecific&lt;Worker*&gt;&amp; currentWorker();
+
+    Workers&amp; m_workers;
+    Deque&lt;RefPtr&lt;Message&gt;&gt; m_messages;
+};
+
+class Workers {
+public:
+    Workers();
+    ~Workers();
+    
+    template&lt;typename Func&gt;
+    void broadcast(const Func&amp;);
+    
+    void report(String);
+    String tryGetReport();
+    String getReport();
+    
+    static Workers&amp; singleton();
+    
+private:
+    friend class Worker;
+    
+    Lock m_lock;
+    Condition m_condition;
+    SentinelLinkedList&lt;Worker, BasicRawSentinelNode&lt;Worker&gt;&gt; m_workers;
+    Deque&lt;String&gt; m_reports;
+};
+
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
</span><span class="lines">@@ -1012,6 +1074,17 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionDollarCreateRealm(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState*);
</ins><span class="cx"> 
</span><span class="cx"> struct Script {
</span><span class="cx">     enum class StrictMode {
</span><span class="lines">@@ -1266,12 +1339,43 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         putDirect(vm, Identifier::fromString(globalExec(), &quot;console&quot;), jsUndefined());
</span><ins>+        
+        Structure* plainObjectStructure = JSFinalObject::createStructure(vm, this, objectPrototype(), 0);
+        
+        JSObject* dollar = JSFinalObject::create(vm, plainObjectStructure);
+        putDirect(vm, Identifier::fromString(globalExec(), &quot;$&quot;), dollar);
+        
+        addFunction(vm, dollar, &quot;createRealm&quot;, functionDollarCreateRealm, 0);
+        addFunction(vm, dollar, &quot;detachArrayBuffer&quot;, functionDollarDetachArrayBuffer, 1);
+        addFunction(vm, dollar, &quot;evalScript&quot;, functionDollarEvalScript, 1);
+        
+        dollar-&gt;putDirect(vm, Identifier::fromString(globalExec(), &quot;global&quot;), this);
+        
+        JSObject* agent = JSFinalObject::create(vm, plainObjectStructure);
+        dollar-&gt;putDirect(vm, Identifier::fromString(globalExec(), &quot;agent&quot;), agent);
+        
+        // The test262 INTERPRETING.md document says that some of these functions are just in the main
+        // thread and some are in the other threads. We just put them in all threads.
+        addFunction(vm, agent, &quot;start&quot;, functionDollarAgentStart, 1);
+        addFunction(vm, agent, &quot;receiveBroadcast&quot;, functionDollarAgentReceiveBroadcast, 1);
+        addFunction(vm, agent, &quot;report&quot;, functionDollarAgentReport, 1);
+        addFunction(vm, agent, &quot;sleep&quot;, functionDollarAgentSleep, 1);
+        addFunction(vm, agent, &quot;broadcast&quot;, functionDollarAgentBroadcast, 1);
+        addFunction(vm, agent, &quot;getReport&quot;, functionDollarAgentGetReport, 0);
+        addFunction(vm, agent, &quot;leaving&quot;, functionDollarAgentLeaving, 0);
+        
+        addFunction(vm, &quot;waitForReport&quot;, functionWaitForReport, 0);
</ins><span class="cx">     }
</span><ins>+    
+    void addFunction(VM&amp; vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
+    {
+        Identifier identifier = Identifier::fromString(&amp;vm, name);
+        object-&gt;putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
+    }
</ins><span class="cx"> 
</span><span class="cx">     void addFunction(VM&amp; vm, const char* name, NativeFunction function, unsigned arguments)
</span><span class="cx">     {
</span><del>-        Identifier identifier = Identifier::fromString(&amp;vm, name);
-        putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
</del><ins>+        addFunction(vm, this, name, function, arguments);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void addConstructableFunction(VM&amp; vm, const char* name, NativeFunction function, unsigned arguments)
</span><span class="lines">@@ -1662,8 +1766,15 @@
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState* exec)
</span><span class="cx"> {
</span><del>-    if (exec-&gt;argumentCount() &gt;= 1)
-        sleep(exec-&gt;argument(0).toNumber(exec));
</del><ins>+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (exec-&gt;argumentCount() &gt;= 1) {
+        Seconds seconds = Seconds(exec-&gt;argument(0).toNumber(exec));
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        sleep(seconds);
+    }
+    
</ins><span class="cx">     return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2221,6 +2332,307 @@
</span><span class="cx">     return JSValue::encode(numberOfDFGCompiles(exec));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Message::Message(ArrayBufferContents&amp;&amp; contents, int32_t index)
+    : m_contents(WTFMove(contents))
+    , m_index(index)
+{
+}
+
+Message::~Message()
+{
+}
+
+Worker::Worker(Workers&amp; workers)
+    : m_workers(workers)
+{
+    auto locker = holdLock(m_workers.m_lock);
+    m_workers.m_workers.append(this);
+    
+    *currentWorker() = this;
+}
+
+Worker::~Worker()
+{
+    auto locker = holdLock(m_workers.m_lock);
+    RELEASE_ASSERT(isOnList());
+    remove();
+}
+
+void Worker::enqueue(const AbstractLocker&amp;, RefPtr&lt;Message&gt; message)
+{
+    m_messages.append(message);
+}
+
+RefPtr&lt;Message&gt; Worker::dequeue()
+{
+    auto locker = holdLock(m_workers.m_lock);
+    while (m_messages.isEmpty())
+        m_workers.m_condition.wait(m_workers.m_lock);
+    return m_messages.takeFirst();
+}
+
+Worker&amp; Worker::current()
+{
+    return **currentWorker();
+}
+
+ThreadSpecific&lt;Worker*&gt;&amp; Worker::currentWorker()
+{
+    static ThreadSpecific&lt;Worker*&gt;* result;
+    static std::once_flag flag;
+    std::call_once(
+        flag,
+        [] () {
+            result = new ThreadSpecific&lt;Worker*&gt;();
+        });
+    return *result;
+}
+
+Workers::Workers()
+{
+}
+
+Workers::~Workers()
+{
+    UNREACHABLE_FOR_PLATFORM();
+}
+
+template&lt;typename Func&gt;
+void Workers::broadcast(const Func&amp; func)
+{
+    auto locker = holdLock(m_lock);
+    for (Worker* worker = m_workers.begin(); worker != m_workers.end(); worker = worker-&gt;next()) {
+        if (worker != &amp;Worker::current())
+            func(locker, *worker);
+    }
+    m_condition.notifyAll();
+}
+
+void Workers::report(String string)
+{
+    auto locker = holdLock(m_lock);
+    m_reports.append(string.isolatedCopy());
+    m_condition.notifyAll();
+}
+
+String Workers::tryGetReport()
+{
+    auto locker = holdLock(m_lock);
+    if (m_reports.isEmpty())
+        return String();
+    return m_reports.takeFirst();
+}
+
+String Workers::getReport()
+{
+    auto locker = holdLock(m_lock);
+    while (m_reports.isEmpty())
+        m_condition.wait(m_lock);
+    return m_reports.takeFirst();
+}
+
+Workers&amp; Workers::singleton()
+{
+    static Workers* result;
+    static std::once_flag flag;
+    std::call_once(
+        flag,
+        [] {
+            result = new Workers();
+        });
+    return *result;
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarCreateRealm(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    GlobalObject* result = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector&lt;String&gt;());
+    return JSValue::encode(result-&gt;getDirect(vm, Identifier::fromString(exec, &quot;$&quot;)));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState* exec)
+{
+    return functionTransferArrayBuffer(exec);
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String sourceCode = exec-&gt;argument(0).toWTFString(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    GlobalObject* globalObject = jsDynamicCast&lt;GlobalObject*&gt;(
+        exec-&gt;thisValue().get(exec, Identifier::fromString(exec, &quot;global&quot;)));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!globalObject)
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral(&quot;Expected global to point to a global object&quot;))));
+    
+    NakedPtr&lt;Exception&gt; evaluationException;
+    JSValue result = evaluate(globalObject-&gt;globalExec(), makeSource(sourceCode, exec-&gt;callerSourceOrigin()), JSValue(), evaluationException);
+    if (evaluationException)
+        throwException(exec, scope, evaluationException);
+    return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String sourceCode = exec-&gt;argument(0).toWTFString(exec).isolatedCopy();
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    Lock didStartLock;
+    Condition didStartCondition;
+    bool didStart = false;
+    
+    ThreadIdentifier thread = createThread(
+        &quot;JSC Agent&quot;,
+        [sourceCode, &amp;didStartLock, &amp;didStartCondition, &amp;didStart] () {
+            CommandLine commandLine(0, nullptr);
+            commandLine.m_interactive = false;
+            runJSC(
+                commandLine,
+                [&amp;] (VM&amp;, GlobalObject* globalObject) {
+                    // Notify the thread that started us that we have registered a worker.
+                    {
+                        auto locker = holdLock(didStartLock);
+                        didStart = true;
+                        didStartCondition.notifyOne();
+                    }
+                    
+                    NakedPtr&lt;Exception&gt; evaluationException;
+                    bool success = true;
+                    JSValue result;
+                    result = evaluate(globalObject-&gt;globalExec(), makeSource(sourceCode, SourceOrigin(ASCIILiteral(&quot;worker&quot;))), JSValue(), evaluationException);
+                    if (evaluationException)
+                        result = evaluationException-&gt;value();
+                    checkException(globalObject, true, evaluationException, result, String(), false, false, success);
+                    if (!success)
+                        exit(1);
+                    return success;
+                });
+        });
+    detachThread(thread);
+    
+    {
+        auto locker = holdLock(didStartLock);
+        while (!didStart)
+            didStartCondition.wait(didStartLock);
+    }
+    
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentReceiveBroadcast(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue callback = exec-&gt;argument(0);
+    CallData callData;
+    CallType callType = getCallData(callback, callData);
+    if (callType == CallType::None)
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral(&quot;Expected callback&quot;))));
+    
+    RefPtr&lt;Message&gt; message;
+    {
+        ReleaseHeapAccessScope releaseAccess(vm.heap);
+        message = Worker::current().dequeue();
+    }
+    
+    RefPtr&lt;ArrayBuffer&gt; nativeBuffer = ArrayBuffer::create(message-&gt;releaseContents());
+    JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec-&gt;lexicalGlobalObject()-&gt;arrayBufferStructure(nativeBuffer-&gt;sharingMode()), nativeBuffer);
+    
+    MarkedArgumentBuffer args;
+    args.append(jsBuffer);
+    args.append(jsNumber(message-&gt;index()));
+    return JSValue::encode(call(exec, callback, callType, callData, jsNull(), args));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String report = exec-&gt;argument(0).toWTFString(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    Workers::singleton().report(report);
+    
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentSleep(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (exec-&gt;argumentCount() &gt;= 1) {
+        Seconds seconds = Seconds::fromMilliseconds(exec-&gt;argument(0).toNumber(exec));
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        sleep(seconds);
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSArrayBuffer* jsBuffer = jsDynamicCast&lt;JSArrayBuffer*&gt;(exec-&gt;argument(0));
+    if (!jsBuffer || !jsBuffer-&gt;isShared())
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral(&quot;Expected SharedArrayBuffer&quot;))));
+    
+    int32_t index = exec-&gt;argument(1).toInt32(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    Workers::singleton().broadcast(
+        [&amp;] (const AbstractLocker&amp; locker, Worker&amp; worker) {
+            ArrayBuffer* nativeBuffer = jsBuffer-&gt;impl();
+            ArrayBufferContents contents;
+            nativeBuffer-&gt;transferTo(contents); // &quot;transferTo&quot; means &quot;share&quot; if the buffer is shared.
+            RefPtr&lt;Message&gt; message = adoptRef(new Message(WTFMove(contents), index));
+            worker.enqueue(locker, message);
+        });
+    
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+
+    String string = Workers::singleton().tryGetReport();
+    if (!string)
+        return JSValue::encode(jsNull());
+    
+    return JSValue::encode(jsString(&amp;vm, string));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*)
+{
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+
+    String string;
+    {
+        ReleaseHeapAccessScope releaseAccess(vm.heap);
+        string = Workers::singleton().getReport();
+    }
+    if (!string)
+        return JSValue::encode(jsNull());
+    
+    return JSValue::encode(jsString(&amp;vm, string));
+}
+
</ins><span class="cx"> template&lt;typename ValueType&gt;
</span><span class="cx"> typename std::enable_if&lt;!std::is_fundamental&lt;ValueType&gt;::value&gt;::type addOption(VM&amp;, JSObject*, Identifier, ValueType) { }
</span><span class="cx"> 
</span><span class="lines">@@ -2904,6 +3316,19 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const String&amp; uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool&amp; success)
+{
+    VM&amp; vm = globalObject-&gt;vm();
+    if (!uncaughtExceptionName || !isLastFile) {
+        success = success &amp;&amp; !hasException;
+        if (dump &amp;&amp; !hasException)
+            printf(&quot;End: %s\n&quot;, value.toWTFString(globalObject-&gt;globalExec()).utf8().data());
+        if (hasException)
+            dumpException(globalObject, value);
+    } else
+        success = success &amp;&amp; checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
+}
+
</ins><span class="cx"> static bool runWithScripts(GlobalObject* globalObject, const Vector&lt;Script&gt;&amp; scripts, const String&amp; uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
</span><span class="cx"> {
</span><span class="cx">     String fileName;
</span><span class="lines">@@ -2916,17 +3341,6 @@
</span><span class="cx">     auto scope = DECLARE_CATCH_SCOPE(vm);
</span><span class="cx">     bool success = true;
</span><span class="cx"> 
</span><del>-    auto checkException = [&amp;] (bool isLastFile, bool hasException, JSValue value) {
-        if (!uncaughtExceptionName || !isLastFile) {
-            success = success &amp;&amp; !hasException;
-            if (dump &amp;&amp; !hasException)
-                printf(&quot;End: %s\n&quot;, value.toWTFString(globalObject-&gt;globalExec()).utf8().data());
-            if (hasException)
-                dumpException(globalObject, value);
-        } else
-            success = success &amp;&amp; checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
-    };
-
</del><span class="cx"> #if ENABLE(SAMPLING_FLAGS)
</span><span class="cx">     SamplingFlags::start();
</span><span class="cx"> #endif
</span><span class="lines">@@ -2959,12 +3373,12 @@
</span><span class="cx">             scope.clearException();
</span><span class="cx"> 
</span><span class="cx">             JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&amp;, isLastFile](ExecState* exec) {
</span><del>-                checkException(isLastFile, false, exec-&gt;argument(0));
</del><ins>+                checkException(globalObject, isLastFile, false, exec-&gt;argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
</ins><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">             });
</span><span class="cx"> 
</span><span class="cx">             JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&amp;, isLastFile](ExecState* exec) {
</span><del>-                checkException(isLastFile, true, exec-&gt;argument(0));
</del><ins>+                checkException(globalObject, isLastFile, true, exec-&gt;argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
</ins><span class="cx">                 return JSValue::encode(jsUndefined());
</span><span class="cx">             });
</span><span class="cx"> 
</span><span class="lines">@@ -2976,7 +3390,7 @@
</span><span class="cx">             ASSERT(!scope.exception());
</span><span class="cx">             if (evaluationException)
</span><span class="cx">                 returnValue = evaluationException-&gt;value();
</span><del>-            checkException(isLastFile, evaluationException, returnValue);
</del><ins>+            checkException(globalObject, isLastFile, evaluationException, returnValue, uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         scriptBuffer.clear();
</span><span class="lines">@@ -3241,22 +3655,25 @@
</span><span class="cx">         jscExit(EXIT_SUCCESS);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// We make this function no inline so that globalObject won't be on the stack if we do a GC in jscmain.
-static int NEVER_INLINE runJSC(VM* vm, CommandLine options)
</del><ins>+template&lt;typename Func&gt;
+int runJSC(CommandLine options, const Func&amp; func)
</ins><span class="cx"> {
</span><del>-    JSLockHolder locker(vm);
</del><ins>+    Worker worker(Workers::singleton());
+    
+    VM&amp; vm = VM::create(LargeHeap).leakRef();
+    JSLockHolder locker(&amp;vm);
</ins><span class="cx"> 
</span><span class="cx">     int result;
</span><del>-    if (options.m_profile &amp;&amp; !vm-&gt;m_perBytecodeProfiler)
-        vm-&gt;m_perBytecodeProfiler = std::make_unique&lt;Profiler::Database&gt;(*vm);
</del><ins>+    if (options.m_profile &amp;&amp; !vm.m_perBytecodeProfiler)
+        vm.m_perBytecodeProfiler = std::make_unique&lt;Profiler::Database&gt;(vm);
</ins><span class="cx"> 
</span><del>-    GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
</del><ins>+    GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
</ins><span class="cx">     globalObject-&gt;setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
</span><del>-    bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
</del><ins>+    bool success = func(vm, globalObject);
</ins><span class="cx">     if (options.m_interactive &amp;&amp; success)
</span><span class="cx">         runInteractive(globalObject);
</span><span class="cx"> 
</span><del>-    vm-&gt;drainMicrotasks();
</del><ins>+    vm.drainMicrotasks();
</ins><span class="cx">     result = success &amp;&amp; (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
</span><span class="cx"> 
</span><span class="cx">     if (options.m_exitCode)
</span><span class="lines">@@ -3263,7 +3680,7 @@
</span><span class="cx">         printf(&quot;jsc exiting %d\n&quot;, result);
</span><span class="cx"> 
</span><span class="cx">     if (options.m_profile) {
</span><del>-        if (!vm-&gt;m_perBytecodeProfiler-&gt;save(options.m_profilerOutput.utf8().data()))
</del><ins>+        if (!vm.m_perBytecodeProfiler-&gt;save(options.m_profilerOutput.utf8().data()))
</ins><span class="cx">             fprintf(stderr, &quot;could not save profiler output.\n&quot;);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3288,6 +3705,22 @@
</span><span class="cx">         printf(&quot;%40s: %.3lf ms\n&quot;, key.data(), compileTimeStats.get(key));
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (Options::gcAtEnd()) {
+        // We need to hold the API lock to do a GC.
+        JSLockHolder locker(&amp;vm);
+        vm.heap.collectAllGarbage();
+    }
+
+    if (options.m_dumpSamplingProfilerData) {
+#if ENABLE(SAMPLING_PROFILER)
+        JSLockHolder locker(&amp;vm);
+        vm.samplingProfiler()-&gt;reportTopFunctions();
+        vm.samplingProfiler()-&gt;reportTopBytecodes();
+#else
+        dataLog(&quot;Sampling profiler is not enabled on this platform\n&quot;);
+#endif
+    }
+
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -3305,26 +3738,13 @@
</span><span class="cx">     JSC::initializeThreading();
</span><span class="cx">     startTimeoutThreadIfNeeded();
</span><span class="cx"> 
</span><del>-    VM* vm = &amp;VM::create(LargeHeap).leakRef();
</del><span class="cx">     int result;
</span><del>-    result = runJSC(vm, options);
</del><ins>+    result = runJSC(
+        options,
+        [&amp;] (VM&amp;, GlobalObject* globalObject) {
+            return runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
+        });
</ins><span class="cx"> 
</span><del>-    if (Options::gcAtEnd()) {
-        // We need to hold the API lock to do a GC.
-        JSLockHolder locker(vm);
-        vm-&gt;heap.collectAllGarbage();
-    }
-
-    if (options.m_dumpSamplingProfilerData) {
-#if ENABLE(SAMPLING_PROFILER)
-        JSLockHolder locker(vm);
-        vm-&gt;samplingProfiler()-&gt;reportTopFunctions();
-        vm-&gt;samplingProfiler()-&gt;reportTopBytecodes();
-#else
-        dataLog(&quot;Sampling profiler is not enabled on this platform\n&quot;);
-#endif
-    }
-
</del><span class="cx">     printSuperSamplerState();
</span><span class="cx"> 
</span><span class="cx">     return result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArrayBuffer.h (211193 => 211194)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArrayBuffer.h        2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/JavaScriptCore/runtime/JSArrayBuffer.h        2017-01-26 02:34:30 UTC (rev 211194)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">     
</span><span class="cx">     static Structure* createStructure(VM&amp;, JSGlobalObject*, JSValue prototype);
</span><span class="cx"> 
</span><del>-    bool isShared() const;
</del><ins>+    JS_EXPORT_PRIVATE bool isShared() const;
</ins><span class="cx">     ArrayBufferSharingMode sharingMode() const;
</span><span class="cx">     
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span></span></pre>
</div>
</div>

</body>
</html>