Ignore:
Timestamp:
Mar 28, 2017, 4:12:11 PM (8 years ago)
Author:
[email protected]
Message:

WebAssembly: Make WebAssembly.instantiate/compile truly asynchronous
https://bugs.webkit.org/show_bug.cgi?id=169187

Reviewed by Saam Barati.

JSTests:

  • wasm/assert.js:
  • wasm/js-api/Module-compile.js:

(async.testPromiseAPI):

  • wasm/js-api/web-assembly-compile-parallel.js: Added.

(async.throwExn):
(async.test):

  • wasm/js-api/web-assembly-instantiate-parallel.js: Added.

(async.test):

  • wasm/js-api/web-assembly-instantiate.js:

(assert.eq.async.test):
(assert.eq):
(assert.asyncTest.async.test):
(assert.asyncTest):
(assert.truthy.async.test): Deleted.
(assert.truthy): Deleted.

Source/JavaScriptCore:

This patch allows WebAssembly compilations to happen asynchronously.
To do so, it refactors how much of the compilation happens and adds
new infrastructure for async promises.

First, there is a new class, PromiseDeferredTimer that lives on
the VM. PromiseDeferredTimer will manage the life-cycle of async
pending promises and any dependencies that promise
needs. PromiseDeferredTimer automagically releases the pending
promise and dependencies once the JSPromiseDeferred is resolved or
rejected. Additionally, PromiseDeferredTimer provides a mechanism
to poll the run-loop whenever the async task needs to synchronize
with the JS thread. Normally, that will be whenever the async task
finishes. In the case of Web Assembly we also use this feature for
the compile + instantiate case, where we might have more work
after the first async task completes (more on that later).

The next class is Wasm::Worklist, which is used to manage Wasm
compilation tasks. The worklist class works similarly to the
DFG/FTL Worklists. It has a pool of threads that it manages. One
interesting aspect of Wasm Worklist is that it can synchronously
compile a plan that is already potentially running
asynchronously. This can occur if a user calls
WebAssembly.instantiate() then new WebAssembly.instantiate() on
the same module. In that case the Wasm Worklist will bump the
priority of the running pending Plan and block the JS thread.

This patch also makes some of the Wasm Plan code cleaner. Since we
now defer all compilation to instantiation time, we no longer need
to guess at which memory we are going to get. Also, Wasm Plans now
track the work they have done with a state enum.

Finally, this patch makes renamed HeapTimer to JSRunLoopTimer. It
also adds changes test262AsyncTest to a more generic testing
infrastructure. Now, in addition to the old functionality, you can
call asyncTest() with the number of tests you expect. When the jsc
CLI exits, it will guarantee that asyncTestPassed() is called that
many times.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • heap/GCActivityCallback.h:
  • heap/IncrementalSweeper.cpp:

(JSC::IncrementalSweeper::scheduleTimer):
(JSC::IncrementalSweeper::IncrementalSweeper):

  • heap/IncrementalSweeper.h:
  • heap/StopIfNecessaryTimer.cpp:

(JSC::StopIfNecessaryTimer::StopIfNecessaryTimer):

  • heap/StopIfNecessaryTimer.h:
  • heap/StrongInlines.h:
  • jsc.cpp:

(GlobalObject::finishCreation):
(printInternal):
(functionAsyncTestStart):
(functionAsyncTestPassed):
(functionTestWasmModuleFunctions):
(CommandLine::parseArguments):
(runJSC):

  • runtime/JSPromiseDeferred.cpp:

(JSC::JSPromiseDeferred::resolve):
(JSC::JSPromiseDeferred::reject):

  • runtime/JSPromiseDeferred.h:

(JSC::JSPromiseDeferred::promiseAsyncPending):

  • runtime/JSRunLoopTimer.cpp: Renamed from Source/JavaScriptCore/heap/HeapTimer.cpp.

(JSC::JSRunLoopTimer::JSRunLoopTimer):
(JSC::JSRunLoopTimer::setRunLoop):
(JSC::JSRunLoopTimer::~JSRunLoopTimer):
(JSC::JSRunLoopTimer::timerDidFire):
(JSC::JSRunLoopTimer::scheduleTimer):
(JSC::JSRunLoopTimer::cancelTimer):
(JSC::JSRunLoopTimer::invalidate):

  • runtime/JSRunLoopTimer.h: Copied from Source/JavaScriptCore/heap/HeapTimer.h.
  • runtime/Options.h:
  • runtime/PromiseDeferredTimer.cpp: Added.

(JSC::PromiseDeferredTimer::PromiseDeferredTimer):
(JSC::PromiseDeferredTimer::doWork):
(JSC::PromiseDeferredTimer::runRunLoop):
(JSC::PromiseDeferredTimer::addPendingPromise):
(JSC::PromiseDeferredTimer::cancelPendingPromise):
(JSC::PromiseDeferredTimer::scheduleWorkSoon):
(JSC::PromiseDeferredTimer::scheduleBlockedTask):

  • runtime/PromiseDeferredTimer.h: Renamed from Source/JavaScriptCore/heap/HeapTimer.h.

(JSC::PromiseDeferredTimer::stopRunningTasks):

  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::~VM):

  • runtime/VM.h:
  • wasm/JSWebAssembly.cpp:

(JSC::reject):
(JSC::webAssemblyCompileFunc):
(JSC::resolve):
(JSC::instantiate):
(JSC::compileAndInstantiate):
(JSC::webAssemblyInstantiateFunc):
(JSC::webAssemblyValidateFunc):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::B3IRGenerator::memoryKind):
(JSC::Wasm::parseAndCompile):

  • wasm/WasmB3IRGenerator.h:
  • wasm/WasmFormat.h:

(JSC::Wasm::ModuleInformation::internalFunctionCount):

  • wasm/WasmFunctionParser.h:
  • wasm/WasmMemory.h:
  • wasm/WasmMemoryInformation.cpp:

(JSC::Wasm::MemoryInformation::MemoryInformation):

  • wasm/WasmMemoryInformation.h:

(JSC::Wasm::MemoryInformation::maximum):
(JSC::Wasm::MemoryInformation::hasReservedMemory): Deleted.
(JSC::Wasm::MemoryInformation::takeReservedMemory): Deleted.
(JSC::Wasm::MemoryInformation::mode): Deleted.

  • wasm/WasmModuleParser.cpp:
  • wasm/WasmModuleParser.h:

(JSC::Wasm::ModuleParser::ModuleParser):

  • wasm/WasmPlan.cpp:

(JSC::Wasm::Plan::Plan):
(JSC::Wasm::Plan::stateString):
(JSC::Wasm::Plan::moveToState):
(JSC::Wasm::Plan::fail):
(JSC::Wasm::Plan::parseAndValidateModule):
(JSC::Wasm::Plan::prepare):
(JSC::Wasm::Plan::ThreadCountHolder::ThreadCountHolder):
(JSC::Wasm::Plan::ThreadCountHolder::~ThreadCountHolder):
(JSC::Wasm::Plan::compileFunctions):
(JSC::Wasm::Plan::complete):
(JSC::Wasm::Plan::waitForCompletion):
(JSC::Wasm::Plan::cancel):
(JSC::Wasm::Plan::run): Deleted.
(JSC::Wasm::Plan::initializeCallees): Deleted.

  • wasm/WasmPlan.h:

(JSC::Wasm::Plan::dontFinalize):
(JSC::Wasm::Plan::exports):
(JSC::Wasm::Plan::internalFunctionCount):
(JSC::Wasm::Plan::takeModuleInformation):
(JSC::Wasm::Plan::takeCallLinkInfos):
(JSC::Wasm::Plan::takeWasmExitStubs):
(JSC::Wasm::Plan::setModeAndPromise):
(JSC::Wasm::Plan::mode):
(JSC::Wasm::Plan::pendingPromise):
(JSC::Wasm::Plan::vm):
(JSC::Wasm::Plan::errorMessage):
(JSC::Wasm::Plan::failed):
(JSC::Wasm::Plan::hasWork):
(JSC::Wasm::Plan::hasBeenPrepared):

  • wasm/WasmPlanInlines.h: Copied from Source/JavaScriptCore/wasm/WasmB3IRGenerator.h.

(JSC::Wasm::Plan::initializeCallees):

  • wasm/WasmValidate.cpp:
  • wasm/WasmWorklist.cpp: Added.

(JSC::Wasm::Worklist::priorityString):
(JSC::Wasm::Worklist::QueueElement::setToNextPriority):
(JSC::Wasm::Worklist::iterate):
(JSC::Wasm::Worklist::enqueue):
(JSC::Wasm::Worklist::completePlanSynchronously):
(JSC::Wasm::Worklist::stopAllPlansForVM):
(JSC::Wasm::Worklist::Worklist):
(JSC::Wasm::Worklist::~Worklist):
(JSC::Wasm::existingWorklistOrNull):
(JSC::Wasm::ensureWorklist):

  • wasm/WasmWorklist.h: Added.

(JSC::Wasm::Worklist::nextTicket):
(JSC::Wasm::Worklist::Comparator::operator()):

  • wasm/js/JSWebAssemblyCallee.h:
  • wasm/js/JSWebAssemblyCodeBlock.cpp:

(JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
(JSC::JSWebAssemblyCodeBlock::initialize):
(JSC::JSWebAssemblyCodeBlock::isSafeToRun):

  • wasm/js/JSWebAssemblyCodeBlock.h:

(JSC::JSWebAssemblyCodeBlock::create):
(JSC::JSWebAssemblyCodeBlock::initialized):
(JSC::JSWebAssemblyCodeBlock::plan):
(JSC::JSWebAssemblyCodeBlock::runnable):
(JSC::JSWebAssemblyCodeBlock::errorMessage):
(JSC::JSWebAssemblyCodeBlock::callees):

  • wasm/js/JSWebAssemblyHelpers.h:

(JSC::createSourceBufferFromValue):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::finishCreation):
(JSC::JSWebAssemblyInstance::visitChildren):
(JSC::JSWebAssemblyInstance::addUnitializedCodeBlock):
(JSC::JSWebAssemblyInstance::finalizeCreation):
(JSC::JSWebAssemblyInstance::create):
(JSC::JSWebAssemblyInstance::setMemory): Deleted.

  • wasm/js/JSWebAssemblyInstance.h:

(JSC::JSWebAssemblyInstance::codeBlock):
(JSC::JSWebAssemblyInstance::initialized):
(JSC::JSWebAssemblyInstance::module):
(JSC::JSWebAssemblyInstance::importFunction):
(JSC::JSWebAssemblyInstance::setMemory):
(JSC::JSWebAssemblyInstance::table):
(JSC::JSWebAssemblyInstance::importFunctions):
(JSC::JSWebAssemblyInstance::setImportFunction): Deleted.
(JSC::JSWebAssemblyInstance::setTable): Deleted.

  • wasm/js/JSWebAssemblyModule.cpp:

(JSC::JSWebAssemblyModule::createStub):
(JSC::JSWebAssemblyModule::JSWebAssemblyModule):
(JSC::JSWebAssemblyModule::finishCreation):
(JSC::JSWebAssemblyModule::setCodeBlock):
(JSC::JSWebAssemblyModule::buildCodeBlock): Deleted.
(JSC::JSWebAssemblyModule::create): Deleted.
(JSC::JSWebAssemblyModule::codeBlock): Deleted.

  • wasm/js/JSWebAssemblyModule.h:

(JSC::JSWebAssemblyModule::moduleInformation):
(JSC::JSWebAssemblyModule::codeBlock):
(JSC::JSWebAssemblyModule::source):
(JSC::JSWebAssemblyModule::takeReservedMemory): Deleted.
(JSC::JSWebAssemblyModule::codeBlockFor): Deleted.

  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance):
(JSC::WebAssemblyInstanceConstructor::createInstance): Deleted.

  • wasm/js/WebAssemblyModuleConstructor.cpp:

(JSC::WebAssemblyModuleConstructor::createModule):

  • wasm/js/WebAssemblyModulePrototype.cpp:

(JSC::webAssemblyModuleProtoImports):
(JSC::webAssemblyModuleProtoExports):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::finishCreation):
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

  • wasm/js/WebAssemblyModuleRecord.h:
File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp

    r214502 r214504  
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
    2626#include "config.h"
    27 #include "HeapTimer.h"
     27#include "JSRunLoopTimer.h"
    2828
    2929#include "GCActivityCallback.h"
    3030#include "IncrementalSweeper.h"
     31#include "JSCInlines.h"
    3132#include "JSObject.h"
    3233#include "JSString.h"
    33 #include "JSCInlines.h"
     34
    3435#include <wtf/MainThread.h>
    3536#include <wtf/Threading.h>
     
    4243
    4344#if USE(CF)
    44    
    45 const CFTimeInterval HeapTimer::s_decade = 60 * 60 * 24 * 365 * 10;
    4645
    47 HeapTimer::HeapTimer(VM* vm)
     46const CFTimeInterval JSRunLoopTimer::s_decade = 60 * 60 * 24 * 365 * 10;
     47
     48JSRunLoopTimer::JSRunLoopTimer(VM* vm)
    4849    : m_vm(vm)
    4950    , m_apiLock(&vm->apiLock())
     
    5253}
    5354
    54 void HeapTimer::setRunLoop(CFRunLoopRef runLoop)
     55void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop)
    5556{
    5657    if (m_runLoop) {
     
    6061        m_timer.clear();
    6162    }
    62    
     63
    6364    if (runLoop) {
    6465        m_runLoop = runLoop;
    6566        memset(&m_context, 0, sizeof(CFRunLoopTimerContext));
    6667        m_context.info = this;
    67         m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context));
     68        m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade, s_decade, 0, 0, JSRunLoopTimer::timerDidFire, &m_context));
    6869        CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
    6970    }
    7071}
    7172
    72 HeapTimer::~HeapTimer()
     73JSRunLoopTimer::~JSRunLoopTimer()
    7374{
    7475    setRunLoop(0);
    7576}
    7677
    77 void HeapTimer::timerDidFire(CFRunLoopTimerRef, void* contextPtr)
     78void JSRunLoopTimer::timerDidFire(CFRunLoopTimerRef, void* contextPtr)
    7879{
    79     HeapTimer* timer = static_cast<HeapTimer*>(contextPtr);
     80    JSRunLoopTimer* timer = static_cast<JSRunLoopTimer*>(contextPtr);
    8081    timer->m_apiLock->lock();
    8182
     
    9596}
    9697
    97 void HeapTimer::scheduleTimer(double intervalInSeconds)
     98void JSRunLoopTimer::scheduleTimer(double intervalInSeconds)
    9899{
    99100    CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds);
     
    101102}
    102103
    103 void HeapTimer::cancelTimer()
     104void JSRunLoopTimer::cancelTimer()
    104105{
    105106    CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade);
     
    109110#elif USE(GLIB)
    110111
    111 const long HeapTimer::s_decade = 60 * 60 * 24 * 365 * 10;
     112const long JSRunLoopTimer::s_decade = 60 * 60 * 24 * 365 * 10;
    112113
    113 static GSourceFuncs heapTimerSourceFunctions = {
     114static GSourceFuncs JSRunLoopTimerSourceFunctions = {
    114115    nullptr, // prepare
    115116    nullptr, // check
     
    124125};
    125126
    126 HeapTimer::HeapTimer(VM* vm)
     127JSRunLoopTimer::JSRunLoopTimer(VM* vm)
    127128    : m_vm(vm)
    128129    , m_apiLock(&vm->apiLock())
    129     , m_timer(adoptGRef(g_source_new(&heapTimerSourceFunctions, sizeof(GSource))))
     130    , m_timer(adoptGRef(g_source_new(&JSRunLoopTimerSourceFunctions, sizeof(GSource))))
    130131{
    131     g_source_set_name(m_timer.get(), "[JavaScriptCore] HeapTimer");
     132    g_source_set_name(m_timer.get(), "[JavaScriptCore] JSRunLoopTimer");
    132133    g_source_set_callback(m_timer.get(), [](gpointer userData) -> gboolean {
    133         auto& heapTimer = *static_cast<HeapTimer*>(userData);
    134         g_source_set_ready_time(heapTimer.m_timer.get(), g_get_monotonic_time() + HeapTimer::s_decade * G_USEC_PER_SEC);
    135         heapTimer.timerDidFire();
     134        auto& runLoopTimer = *static_cast<JSRunLoopTimer*>(userData);
     135        g_source_set_ready_time(runLoopTimer.m_timer.get(), g_get_monotonic_time() + JSRunLoopTimer::s_decade * G_USEC_PER_SEC);
     136        runLoopTimer.timerDidFire();
    136137        return G_SOURCE_CONTINUE;
    137138    }, this, nullptr);
     
    139140}
    140141
    141 HeapTimer::~HeapTimer()
     142JSRunLoopTimer::~JSRunLoopTimer()
    142143{
    143144    g_source_destroy(m_timer.get());
    144145}
    145146
    146 void HeapTimer::timerDidFire()
     147void JSRunLoopTimer::timerDidFire()
    147148{
    148149    m_apiLock->lock();
     
    162163}
    163164
    164 void HeapTimer::scheduleTimer(double intervalInSeconds)
     165void JSRunLoopTimer::scheduleTimer(double intervalInSeconds)
    165166{
    166167    g_source_set_ready_time(m_timer.get(), g_get_monotonic_time() + intervalInSeconds * G_USEC_PER_SEC);
     
    168169}
    169170
    170 void HeapTimer::cancelTimer()
     171void JSRunLoopTimer::cancelTimer()
    171172{
    172173    g_source_set_ready_time(m_timer.get(), g_get_monotonic_time() + s_decade * G_USEC_PER_SEC);
     
    174175}
    175176#else
    176 HeapTimer::HeapTimer(VM* vm)
     177JSRunLoopTimer::JSRunLoopTimer(VM* vm)
    177178    : m_vm(vm)
    178179{
    179180}
    180181
    181 HeapTimer::~HeapTimer()
     182JSRunLoopTimer::~JSRunLoopTimer()
    182183{
    183184}
    184185
    185 void HeapTimer::invalidate()
     186void JSRunLoopTimer::invalidate()
    186187{
    187188}
    188189
    189 void HeapTimer::scheduleTimer(double)
     190void JSRunLoopTimer::scheduleTimer(double)
    190191{
    191192}
    192193
    193 void HeapTimer::cancelTimer()
     194void JSRunLoopTimer::cancelTimer()
    194195{
    195196}
    196197#endif
    197198   
    198 
    199199} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.