Title: [211194] trunk
Revision
211194
Author
[email protected]
Date
2017-01-25 18:34:30 -0800 (Wed, 25 Jan 2017)

Log Message

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/_javascript_Core:

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:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (211193 => 211194)


--- trunk/JSTests/ChangeLog	2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/JSTests/ChangeLog	2017-01-26 02:34:30 UTC (rev 211194)
@@ -1,3 +1,19 @@
+2017-01-25  Filip Pizlo  <[email protected]>
+
+        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):
+
 2017-01-24  Filip Pizlo  <[email protected]>
 
         Atomics.store should return the int-converted value according to toInteger

Added: trunk/JSTests/stress/lars-sab-workers.js (0 => 211194)


--- 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)
@@ -0,0 +1,127 @@
+//@ defaultRunNoisyTest
+
+var sab = new SharedArrayBuffer(100 * 4);
+
+var memory = new Int32Array(sab);
+
+var numWorkers = 0;
+function startWorker(code)
+{
+    print("Starting worker!");
+    
+    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 "not-equal":
+        case "ok":
+            break;
+        default:
+            $.agent.report("Error: bad result from wait: " + result);
+            $.agent.report("error");
+            break;
+        }
+        var value = memory[index];
+        if (value != wakeCondition) {
+            $.agent.report("Error: wait returned not-equal but the memory has a bad value: " + value);
+            $.agent.report("error");
+        }
+    }
+    var value = memory[index];
+    if (value != wakeCondition) {
+        $.agent.report("Error: done waiting but the memory has a bad value: " + value);
+        $.agent.report("error");
+    }
+}
+
+function wake(memory, index)
+{
+    var result = Atomics.wake(memory, index, 1);
+    if (result != 0 && result != 1) {
+        $.agent.report("Error: bad result from wake: " + result);
+        $.agent.report("error");
+    }
+}
+`;
+
+startWorker(
+    resources + `
+    $.agent.receiveBroadcast(sab => {
+        var memory = new Int32Array(sab);
+        var didStartIdx = 0;
+        var shouldGoIdx = 1;
+        var didEndIdx = 2;
+        
+        $.agent.report("1: Started!");
+        $.agent.report("1: Memory: " + memory);
+        
+        wait(memory, didStartIdx, 0, 1);
+        
+        $.agent.report("1: It started!");
+        
+        memory[shouldGoIdx] = 1;
+        wake(memory, shouldGoIdx);
+        
+        wait(memory, didEndIdx, 0, 1);
+        
+        $.agent.report("1: All done!");
+        $.agent.report("1: Memory: " + memory);
+        $.agent.report("done");
+    });
+    `);
+
+startWorker(
+    resources + `
+    $.agent.receiveBroadcast(sab => {
+        var memory = new Int32Array(sab);
+        var didStartIdx = 0;
+        var shouldGoIdx = 1;
+        var didEndIdx = 2;
+        
+        $.agent.report("2: Started!");
+        $.agent.report("2: Memory: " + 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("2: Memory: " + memory);
+        $.agent.report("done");
+    });
+    `);
+
+$.agent.broadcast(sab);
+
+for (;;) {
+    var report = waitForReport();
+    if (report == "done") {
+        if (!--numWorkers) {
+            print("All workers done!");
+            break;
+        }
+    } else if (report == "error") {
+        print("Test failed!");
+        throw new Error("Test failed.");
+    } else
+        print("report: " + report);
+}
+
+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];
+}
+print("Test passed!");

Modified: trunk/Source/_javascript_Core/ChangeLog (211193 => 211194)


--- trunk/Source/_javascript_Core/ChangeLog	2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-01-26 02:34:30 UTC (rev 211194)
@@ -1,5 +1,52 @@
 2017-01-25  Filip Pizlo  <[email protected]>
 
+        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  <[email protected]>
+
         ARM/ARM64 stress/atomics-store-return.js fails
         <rdar://problem/30192652>
 

Modified: trunk/Source/_javascript_Core/jsc.cpp (211193 => 211194)


--- trunk/Source/_javascript_Core/jsc.cpp	2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/_javascript_Core/jsc.cpp	2017-01-26 02:34:30 UTC (rev 211194)
@@ -63,6 +63,7 @@
 #include "ParserError.h"
 #include "ProfilerDatabase.h"
 #include "ProtoCallFrame.h"
+#include "ReleaseHeapAccessScope.h"
 #include "SamplingProfiler.h"
 #include "ShadowChicken.h"
 #include "StackVisitor.h"
@@ -908,6 +909,67 @@
 
 static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
 
+class CommandLine;
+class GlobalObject;
+class Workers;
+
+template<typename Func>
+int runJSC(CommandLine, const Func&);
+static void checkException(GlobalObject*, bool isLastFile, bool hasException, JSValue, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success);
+
+class Message : public ThreadSafeRefCounted<Message> {
+public:
+    Message(ArrayBufferContents&&, int32_t);
+    ~Message();
+    
+    ArrayBufferContents&& 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<Worker> {
+public:
+    Worker(Workers&);
+    ~Worker();
+    
+    void enqueue(const AbstractLocker&, RefPtr<Message>);
+    RefPtr<Message> dequeue();
+    
+    static Worker& current();
+
+private:
+    static ThreadSpecific<Worker*>& currentWorker();
+
+    Workers& m_workers;
+    Deque<RefPtr<Message>> m_messages;
+};
+
+class Workers {
+public:
+    Workers();
+    ~Workers();
+    
+    template<typename Func>
+    void broadcast(const Func&);
+    
+    void report(String);
+    String tryGetReport();
+    String getReport();
+    
+    static Workers& singleton();
+    
+private:
+    friend class Worker;
+    
+    Lock m_lock;
+    Condition m_condition;
+    SentinelLinkedList<Worker, BasicRawSentinelNode<Worker>> m_workers;
+    Deque<String> m_reports;
+};
+
 static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
@@ -1012,6 +1074,17 @@
 static EncodedJSValue JSC_HOST_CALL functionIsRope(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCallerSourceOrigin(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState*);
+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*);
 
 struct Script {
     enum class StrictMode {
@@ -1266,12 +1339,43 @@
         }
 
         putDirect(vm, Identifier::fromString(globalExec(), "console"), jsUndefined());
+        
+        Structure* plainObjectStructure = JSFinalObject::createStructure(vm, this, objectPrototype(), 0);
+        
+        JSObject* dollar = JSFinalObject::create(vm, plainObjectStructure);
+        putDirect(vm, Identifier::fromString(globalExec(), "$"), dollar);
+        
+        addFunction(vm, dollar, "createRealm", functionDollarCreateRealm, 0);
+        addFunction(vm, dollar, "detachArrayBuffer", functionDollarDetachArrayBuffer, 1);
+        addFunction(vm, dollar, "evalScript", functionDollarEvalScript, 1);
+        
+        dollar->putDirect(vm, Identifier::fromString(globalExec(), "global"), this);
+        
+        JSObject* agent = JSFinalObject::create(vm, plainObjectStructure);
+        dollar->putDirect(vm, Identifier::fromString(globalExec(), "agent"), 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, "start", functionDollarAgentStart, 1);
+        addFunction(vm, agent, "receiveBroadcast", functionDollarAgentReceiveBroadcast, 1);
+        addFunction(vm, agent, "report", functionDollarAgentReport, 1);
+        addFunction(vm, agent, "sleep", functionDollarAgentSleep, 1);
+        addFunction(vm, agent, "broadcast", functionDollarAgentBroadcast, 1);
+        addFunction(vm, agent, "getReport", functionDollarAgentGetReport, 0);
+        addFunction(vm, agent, "leaving", functionDollarAgentLeaving, 0);
+        
+        addFunction(vm, "waitForReport", functionWaitForReport, 0);
     }
+    
+    void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
+    {
+        Identifier identifier = Identifier::fromString(&vm, name);
+        object->putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
+    }
 
     void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
     {
-        Identifier identifier = Identifier::fromString(&vm, name);
-        putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function));
+        addFunction(vm, this, name, function, arguments);
     }
     
     void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
@@ -1662,8 +1766,15 @@
 
 EncodedJSValue JSC_HOST_CALL functionSleepSeconds(ExecState* exec)
 {
-    if (exec->argumentCount() >= 1)
-        sleep(exec->argument(0).toNumber(exec));
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (exec->argumentCount() >= 1) {
+        Seconds seconds = Seconds(exec->argument(0).toNumber(exec));
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        sleep(seconds);
+    }
+    
     return JSValue::encode(jsUndefined());
 }
 
@@ -2221,6 +2332,307 @@
     return JSValue::encode(numberOfDFGCompiles(exec));
 }
 
+Message::Message(ArrayBufferContents&& contents, int32_t index)
+    : m_contents(WTFMove(contents))
+    , m_index(index)
+{
+}
+
+Message::~Message()
+{
+}
+
+Worker::Worker(Workers& 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&, RefPtr<Message> message)
+{
+    m_messages.append(message);
+}
+
+RefPtr<Message> 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& Worker::current()
+{
+    return **currentWorker();
+}
+
+ThreadSpecific<Worker*>& Worker::currentWorker()
+{
+    static ThreadSpecific<Worker*>* result;
+    static std::once_flag flag;
+    std::call_once(
+        flag,
+        [] () {
+            result = new ThreadSpecific<Worker*>();
+        });
+    return *result;
+}
+
+Workers::Workers()
+{
+}
+
+Workers::~Workers()
+{
+    UNREACHABLE_FOR_PLATFORM();
+}
+
+template<typename Func>
+void Workers::broadcast(const Func& func)
+{
+    auto locker = holdLock(m_lock);
+    for (Worker* worker = m_workers.begin(); worker != m_workers.end(); worker = worker->next()) {
+        if (worker != &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& 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& vm = exec->vm();
+    GlobalObject* result = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), Vector<String>());
+    return JSValue::encode(result->getDirect(vm, Identifier::fromString(exec, "$")));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarDetachArrayBuffer(ExecState* exec)
+{
+    return functionTransferArrayBuffer(exec);
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarEvalScript(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String sourceCode = exec->argument(0).toWTFString(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    GlobalObject* globalObject = jsDynamicCast<GlobalObject*>(
+        exec->thisValue().get(exec, Identifier::fromString(exec, "global")));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!globalObject)
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected global to point to a global object"))));
+    
+    NakedPtr<Exception> evaluationException;
+    JSValue result = evaluate(globalObject->globalExec(), makeSource(sourceCode, exec->callerSourceOrigin()), JSValue(), evaluationException);
+    if (evaluationException)
+        throwException(exec, scope, evaluationException);
+    return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentStart(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String sourceCode = exec->argument(0).toWTFString(exec).isolatedCopy();
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    Lock didStartLock;
+    Condition didStartCondition;
+    bool didStart = false;
+    
+    ThreadIdentifier thread = createThread(
+        "JSC Agent",
+        [sourceCode, &didStartLock, &didStartCondition, &didStart] () {
+            CommandLine commandLine(0, nullptr);
+            commandLine.m_interactive = false;
+            runJSC(
+                commandLine,
+                [&] (VM&, GlobalObject* globalObject) {
+                    // Notify the thread that started us that we have registered a worker.
+                    {
+                        auto locker = holdLock(didStartLock);
+                        didStart = true;
+                        didStartCondition.notifyOne();
+                    }
+                    
+                    NakedPtr<Exception> evaluationException;
+                    bool success = true;
+                    JSValue result;
+                    result = evaluate(globalObject->globalExec(), makeSource(sourceCode, SourceOrigin(ASCIILiteral("worker"))), JSValue(), evaluationException);
+                    if (evaluationException)
+                        result = evaluationException->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& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue callback = exec->argument(0);
+    CallData callData;
+    CallType callType = getCallData(callback, callData);
+    if (callType == CallType::None)
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected callback"))));
+    
+    RefPtr<Message> message;
+    {
+        ReleaseHeapAccessScope releaseAccess(vm.heap);
+        message = Worker::current().dequeue();
+    }
+    
+    RefPtr<ArrayBuffer> nativeBuffer = ArrayBuffer::create(message->releaseContents());
+    JSArrayBuffer* jsBuffer = JSArrayBuffer::create(vm, exec->lexicalGlobalObject()->arrayBufferStructure(nativeBuffer->sharingMode()), nativeBuffer);
+    
+    MarkedArgumentBuffer args;
+    args.append(jsBuffer);
+    args.append(jsNumber(message->index()));
+    return JSValue::encode(call(exec, callback, callType, callData, jsNull(), args));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentReport(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    String report = exec->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& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (exec->argumentCount() >= 1) {
+        Seconds seconds = Seconds::fromMilliseconds(exec->argument(0).toNumber(exec));
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        sleep(seconds);
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentBroadcast(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0));
+    if (!jsBuffer || !jsBuffer->isShared())
+        return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected SharedArrayBuffer"))));
+    
+    int32_t index = exec->argument(1).toInt32(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    
+    Workers::singleton().broadcast(
+        [&] (const AbstractLocker& locker, Worker& worker) {
+            ArrayBuffer* nativeBuffer = jsBuffer->impl();
+            ArrayBufferContents contents;
+            nativeBuffer->transferTo(contents); // "transferTo" means "share" if the buffer is shared.
+            RefPtr<Message> message = adoptRef(new Message(WTFMove(contents), index));
+            worker.enqueue(locker, message);
+        });
+    
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentGetReport(ExecState* exec)
+{
+    VM& vm = exec->vm();
+
+    String string = Workers::singleton().tryGetReport();
+    if (!string)
+        return JSValue::encode(jsNull());
+    
+    return JSValue::encode(jsString(&vm, string));
+}
+
+EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*)
+{
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState* exec)
+{
+    VM& vm = exec->vm();
+
+    String string;
+    {
+        ReleaseHeapAccessScope releaseAccess(vm.heap);
+        string = Workers::singleton().getReport();
+    }
+    if (!string)
+        return JSValue::encode(jsNull());
+    
+    return JSValue::encode(jsString(&vm, string));
+}
+
 template<typename ValueType>
 typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
 
@@ -2904,6 +3316,19 @@
     return false;
 }
 
+static void checkException(GlobalObject* globalObject, bool isLastFile, bool hasException, JSValue value, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool& success)
+{
+    VM& vm = globalObject->vm();
+    if (!uncaughtExceptionName || !isLastFile) {
+        success = success && !hasException;
+        if (dump && !hasException)
+            printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
+        if (hasException)
+            dumpException(globalObject, value);
+    } else
+        success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
+}
+
 static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool alwaysDumpUncaughtException, bool dump, bool module)
 {
     String fileName;
@@ -2916,17 +3341,6 @@
     auto scope = DECLARE_CATCH_SCOPE(vm);
     bool success = true;
 
-    auto checkException = [&] (bool isLastFile, bool hasException, JSValue value) {
-        if (!uncaughtExceptionName || !isLastFile) {
-            success = success && !hasException;
-            if (dump && !hasException)
-                printf("End: %s\n", value.toWTFString(globalObject->globalExec()).utf8().data());
-            if (hasException)
-                dumpException(globalObject, value);
-        } else
-            success = success && checkUncaughtException(vm, globalObject, (hasException) ? value : JSValue(), uncaughtExceptionName, alwaysDumpUncaughtException);
-    };
-
 #if ENABLE(SAMPLING_FLAGS)
     SamplingFlags::start();
 #endif
@@ -2959,12 +3373,12 @@
             scope.clearException();
 
             JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
-                checkException(isLastFile, false, exec->argument(0));
+                checkException(globalObject, isLastFile, false, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
                 return JSValue::encode(jsUndefined());
             });
 
             JSFunction* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
-                checkException(isLastFile, true, exec->argument(0));
+                checkException(globalObject, isLastFile, true, exec->argument(0), uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
                 return JSValue::encode(jsUndefined());
             });
 
@@ -2976,7 +3390,7 @@
             ASSERT(!scope.exception());
             if (evaluationException)
                 returnValue = evaluationException->value();
-            checkException(isLastFile, evaluationException, returnValue);
+            checkException(globalObject, isLastFile, evaluationException, returnValue, uncaughtExceptionName, alwaysDumpUncaughtException, dump, success);
         }
 
         scriptBuffer.clear();
@@ -3241,22 +3655,25 @@
         jscExit(EXIT_SUCCESS);
 }
 
-// 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)
+template<typename Func>
+int runJSC(CommandLine options, const Func& func)
 {
-    JSLockHolder locker(vm);
+    Worker worker(Workers::singleton());
+    
+    VM& vm = VM::create(LargeHeap).leakRef();
+    JSLockHolder locker(&vm);
 
     int result;
-    if (options.m_profile && !vm->m_perBytecodeProfiler)
-        vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
+    if (options.m_profile && !vm.m_perBytecodeProfiler)
+        vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
 
-    GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
+    GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
     globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
-    bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
+    bool success = func(vm, globalObject);
     if (options.m_interactive && success)
         runInteractive(globalObject);
 
-    vm->drainMicrotasks();
+    vm.drainMicrotasks();
     result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
 
     if (options.m_exitCode)
@@ -3263,7 +3680,7 @@
         printf("jsc exiting %d\n", result);
 
     if (options.m_profile) {
-        if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
+        if (!vm.m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
             fprintf(stderr, "could not save profiler output.\n");
     }
 
@@ -3288,6 +3705,22 @@
         printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
 #endif
 
+    if (Options::gcAtEnd()) {
+        // We need to hold the API lock to do a GC.
+        JSLockHolder locker(&vm);
+        vm.heap.collectAllGarbage();
+    }
+
+    if (options.m_dumpSamplingProfilerData) {
+#if ENABLE(SAMPLING_PROFILER)
+        JSLockHolder locker(&vm);
+        vm.samplingProfiler()->reportTopFunctions();
+        vm.samplingProfiler()->reportTopBytecodes();
+#else
+        dataLog("Sampling profiler is not enabled on this platform\n");
+#endif
+    }
+
     return result;
 }
 
@@ -3305,26 +3738,13 @@
     JSC::initializeThreading();
     startTimeoutThreadIfNeeded();
 
-    VM* vm = &VM::create(LargeHeap).leakRef();
     int result;
-    result = runJSC(vm, options);
+    result = runJSC(
+        options,
+        [&] (VM&, GlobalObject* globalObject) {
+            return runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_alwaysDumpUncaughtException, options.m_dump, options.m_module);
+        });
 
-    if (Options::gcAtEnd()) {
-        // We need to hold the API lock to do a GC.
-        JSLockHolder locker(vm);
-        vm->heap.collectAllGarbage();
-    }
-
-    if (options.m_dumpSamplingProfilerData) {
-#if ENABLE(SAMPLING_PROFILER)
-        JSLockHolder locker(vm);
-        vm->samplingProfiler()->reportTopFunctions();
-        vm->samplingProfiler()->reportTopBytecodes();
-#else
-        dataLog("Sampling profiler is not enabled on this platform\n");
-#endif
-    }
-
     printSuperSamplerState();
 
     return result;

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBuffer.h (211193 => 211194)


--- trunk/Source/_javascript_Core/runtime/JSArrayBuffer.h	2017-01-26 02:18:00 UTC (rev 211193)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBuffer.h	2017-01-26 02:34:30 UTC (rev 211194)
@@ -47,7 +47,7 @@
     
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
 
-    bool isShared() const;
+    JS_EXPORT_PRIVATE bool isShared() const;
     ArrayBufferSharingMode sharingMode() const;
     
     DECLARE_EXPORT_INFO;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to