Changeset 214504 in webkit


Ignore:
Timestamp:
Mar 28, 2017 4:12:11 PM (7 years ago)
Author:
keith_miller@apple.com
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:
Location:
trunk
Files:
5 added
45 edited
2 copied
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r214484 r214504  
     12017-03-28  Keith Miller  <keith_miller@apple.com>
     2
     3        WebAssembly: Make WebAssembly.instantiate/compile truly asynchronous
     4        https://bugs.webkit.org/show_bug.cgi?id=169187
     5
     6        Reviewed by Saam Barati.
     7
     8        * wasm/assert.js:
     9        * wasm/js-api/Module-compile.js:
     10        (async.testPromiseAPI):
     11        * wasm/js-api/web-assembly-compile-parallel.js: Added.
     12        (async.throwExn):
     13        (async.test):
     14        * wasm/js-api/web-assembly-instantiate-parallel.js: Added.
     15        (async.test):
     16        * wasm/js-api/web-assembly-instantiate.js:
     17        (assert.eq.async.test):
     18        (assert.eq):
     19        (assert.asyncTest.async.test):
     20        (assert.asyncTest):
     21        (assert.truthy.async.test): Deleted.
     22        (assert.truthy): Deleted.
     23
    1242017-03-28  JF Bastien  <jfbastien@apple.com>
    225
  • trunk/JSTests/wasm/assert.js

    r214438 r214504  
    145145    _instanceof as instanceof,
    146146};
     147
     148const asyncTestImpl = (promise, thenFunc, catchFunc) => {
     149    asyncTestStart(1);
     150    promise.then(thenFunc).catch(catchFunc);
     151};
     152
     153const printExn = (e) => {
     154    print("Failed: ", e);
     155    print(e.stack);
     156};
     157
     158export const asyncTest = (promise) => asyncTestImpl(promise, asyncTestPassed, printExn);
     159export const asyncTestEq = (promise, expected) => {
     160    const thenCheck = (value) => {
     161        if (value === expected)
     162            return asyncTestPassed();
     163        print("Failed: got ", value, " but expected ", expected);
     164
     165    }
     166    asyncTestImpl(promise, thenCheck, printExn);
     167};
  • trunk/JSTests/wasm/js-api/Module-compile.js

    r211410 r214504  
    22import Builder from '../Builder.js';
    33
    4 let done = false;
    54async function testPromiseAPI() {
    65    {
     
    1514            .End();
    1615
    17         let threw = false;
    1816        try {
    1917            await WebAssembly.compile(builder.WebAssembly().get());
    2018        } catch(e) {
    21             threw = true;
    2219            assert.truthy(e instanceof WebAssembly.CompileError);
    23             assert.truthy(e.message === "WebAssembly.Module doesn't parse at byte 34 / 43: Memory section cannot exist if an Import has a memory (evaluating 'WebAssembly.compile(builder.WebAssembly().get())')");
     20            assert.truthy(e.message === "WebAssembly.Module doesn't parse at byte 34 / 43: Memory section cannot exist if an Import has a memory");
    2421        }
    25         assert.truthy(threw);
    2622    }
    2723
    2824    {
    29         let threw = false;
    3025        try {
    3126            await WebAssembly.compile();
    3227        } catch(e) {
    33             threw = true;
    3428            assert.truthy(e instanceof TypeError);
    3529            assert.eq(e.message, "first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'WebAssembly.compile()')");
    3630        }
    37         assert.truthy(threw);
    3831    }
    3932
    4033    {
    41         let threw = false;
    4234        try {
    4335            await WebAssembly.compile(20);
    4436        } catch(e) {
    45             threw = true;
    4637            assert.truthy(e instanceof TypeError);
    4738            assert.eq(e.message, "first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'WebAssembly.compile(20)')");
    4839        }
    49         assert.truthy(threw);
    5040    }
    5141
     
    6252        assert.truthy(module instanceof WebAssembly.Module);
    6353    }
    64 
    65     done = true;
    6654}
    6755
    68 testPromiseAPI();
    69 drainMicrotasks();
    70 assert.truthy(done);
     56assert.asyncTest(testPromiseAPI());
  • trunk/JSTests/wasm/js-api/web-assembly-instantiate.js

    r213506 r214504  
    2020    const bin = builder.WebAssembly().get();
    2121
    22     let done = false;
    2322    async function test() {
    2423        let {module, instance} = await WebAssembly.instantiate(bin);
     
    2625        assert.truthy(instance instanceof WebAssembly.Instance);
    2726        assert.eq(instance.exports.foo(20), 1);
    28         done = true;
    2927    }
    3028
    31     test();
    32     drainMicrotasks();
    33     assert.truthy(done);
     29    assert.asyncTest(test());
    3430}
    3531
     
    4945    const bin = builder.WebAssembly().get();
    5046
    51     let done = false;
    5247    async function test() {
    5348        try {
     
    5651            assert.eq(e.message, "second argument to WebAssembly.instantiate must be undefined or an Object (evaluating 'WebAssembly.instantiate(bin, null)')");
    5752        }
    58         done = true;
    5953    }
    6054
    61     test();
    62     drainMicrotasks();
    63     assert.truthy(done);
     55    assert.asyncTest(test());
    6456}
    6557
     
    7971    const bin = builder.WebAssembly().get();
    8072
    81     let done = false;
    8273    async function test() {
    8374        try {
     
    8576        } catch(e) {
    8677            assert.truthy(e instanceof WebAssembly.CompileError);
    87             assert.eq(e.message, "WebAssembly.Module doesn't validate: control flow returns with unexpected type, in function at index 0 (evaluating 'WebAssembly.instantiate(bin)')");
     78            assert.eq(e.message, "WebAssembly.Module doesn't validate: control flow returns with unexpected type, in function at index 0");
    8879        }
    89         done = true;
    9080    }
    9181
    92     test();
    93     drainMicrotasks();
    94     assert.truthy(done);
     82    assert.asyncTest(test());
    9583}
    9684
     
    11199    const bin = builder.WebAssembly().get();
    112100
    113     let done = false;
    114101    async function test() {
    115102        try {
    116103            let {module, instance} = await WebAssembly.instantiate(bin, {imp: {memory: 20}});
    117104        } catch(e) {
    118             assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory (evaluating 'WebAssembly.instantiate(bin, {imp: {memory: 20}})')");
     105            assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory");
    119106        }
    120         done = true;
    121107    }
    122108
    123     test();
    124     drainMicrotasks();
    125     assert.truthy(done);
     109    assert.asyncTest(test());
    126110}
    127111
     
    142126    const bin = builder.WebAssembly().get();
    143127
    144     let done = false;
    145128    async function test() {
    146129        try {
     
    148131            let instance = await WebAssembly.instantiate(bin, {imp: {memory: 20}});
    149132        } catch(e) {
    150             assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory (evaluating 'WebAssembly.instantiate(bin, {imp: {memory: 20}})')");
     133            assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory");
    151134        }
    152         done = true;
    153135    }
    154136
    155     test();
    156     drainMicrotasks();
    157     assert.truthy(done);
     137    assert.asyncTest(test());
    158138}
    159139
     
    173153    const bin = builder.WebAssembly().get();
    174154
    175     let done = false;
    176155    async function test() {
    177156        let module = new WebAssembly.Module(bin);
     
    179158        assert.truthy(instance instanceof WebAssembly.Instance);
    180159        assert.eq(instance.exports.foo(20), 1);
    181         done = true;
    182160    }
    183161
    184     test();
    185     drainMicrotasks();
    186     assert.truthy(done);
     162    assert.asyncTest(test());
    187163}
    188164
     
    203179    const bin = builder.WebAssembly().get();
    204180
    205     let done = false;
    206181    async function test() {
    207182        try {
     
    211186            assert.eq(e.message, "first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'WebAssembly.instantiate(25)')");
    212187        }
    213         done = true;
    214188    }
    215189
    216     test();
    217     drainMicrotasks();
    218     assert.truthy(done);
     190    assert.asyncTest(test());
    219191}
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r214410 r214504  
    504504    heap/HeapSnapshot.cpp
    505505    heap/HeapSnapshotBuilder.cpp
    506     heap/HeapTimer.cpp
    507506    heap/IncrementalSweeper.cpp
    508507    heap/JITStubRoutineSet.cpp
     
    803802    runtime/JSPropertyNameIterator.cpp
    804803    runtime/JSProxy.cpp
     804    runtime/JSRunLoopTimer.cpp
    805805    runtime/JSScope.cpp
    806806    runtime/JSScriptFetcher.cpp
     
    852852    runtime/Options.cpp
    853853    runtime/ProgramExecutable.cpp
     854    runtime/PromiseDeferredTimer.cpp
    854855    runtime/PropertyDescriptor.cpp
    855856    runtime/PropertySlot.cpp
     
    945946    wasm/WasmSignature.cpp
    946947    wasm/WasmValidate.cpp
     948    wasm/WasmWorklist.cpp
    947949
    948950    wasm/js/JSWebAssemblyCallee.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r214498 r214504  
     12017-03-28  Keith Miller  <keith_miller@apple.com>
     2
     3        WebAssembly: Make WebAssembly.instantiate/compile truly asynchronous
     4        https://bugs.webkit.org/show_bug.cgi?id=169187
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch allows WebAssembly compilations to happen asynchronously.
     9        To do so, it refactors how much of the compilation happens and adds
     10        new infrastructure for async promises.
     11
     12        First, there is a new class, PromiseDeferredTimer that lives on
     13        the VM.  PromiseDeferredTimer will manage the life-cycle of async
     14        pending promises and any dependencies that promise
     15        needs. PromiseDeferredTimer automagically releases the pending
     16        promise and dependencies once the JSPromiseDeferred is resolved or
     17        rejected. Additionally, PromiseDeferredTimer provides a mechanism
     18        to poll the run-loop whenever the async task needs to synchronize
     19        with the JS thread. Normally, that will be whenever the async task
     20        finishes. In the case of Web Assembly we also use this feature for
     21        the compile + instantiate case, where we might have more work
     22        after the first async task completes (more on that later).
     23
     24        The next class is Wasm::Worklist, which is used to manage Wasm
     25        compilation tasks. The worklist class works similarly to the
     26        DFG/FTL Worklists. It has a pool of threads that it manages. One
     27        interesting aspect of Wasm Worklist is that it can synchronously
     28        compile a plan that is already potentially running
     29        asynchronously. This can occur if a user calls
     30        WebAssembly.instantiate() then new WebAssembly.instantiate() on
     31        the same module. In that case the Wasm Worklist will bump the
     32        priority of the running pending Plan and block the JS thread.
     33
     34        This patch also makes some of the Wasm Plan code cleaner. Since we
     35        now defer all compilation to instantiation time, we no longer need
     36        to guess at which memory we are going to get. Also, Wasm Plans now
     37        track the work they have done with a state enum.
     38
     39        Finally, this patch makes renamed HeapTimer to JSRunLoopTimer. It
     40        also adds changes test262AsyncTest to a more generic testing
     41        infrastructure. Now, in addition to the old functionality, you can
     42        call asyncTest() with the number of tests you expect. When the jsc
     43        CLI exits, it will guarantee that asyncTestPassed() is called that
     44        many times.
     45
     46        * CMakeLists.txt:
     47        * JavaScriptCore.xcodeproj/project.pbxproj:
     48        * heap/GCActivityCallback.h:
     49        * heap/IncrementalSweeper.cpp:
     50        (JSC::IncrementalSweeper::scheduleTimer):
     51        (JSC::IncrementalSweeper::IncrementalSweeper):
     52        * heap/IncrementalSweeper.h:
     53        * heap/StopIfNecessaryTimer.cpp:
     54        (JSC::StopIfNecessaryTimer::StopIfNecessaryTimer):
     55        * heap/StopIfNecessaryTimer.h:
     56        * heap/StrongInlines.h:
     57        * jsc.cpp:
     58        (GlobalObject::finishCreation):
     59        (printInternal):
     60        (functionAsyncTestStart):
     61        (functionAsyncTestPassed):
     62        (functionTestWasmModuleFunctions):
     63        (CommandLine::parseArguments):
     64        (runJSC):
     65        * runtime/JSPromiseDeferred.cpp:
     66        (JSC::JSPromiseDeferred::resolve):
     67        (JSC::JSPromiseDeferred::reject):
     68        * runtime/JSPromiseDeferred.h:
     69        (JSC::JSPromiseDeferred::promiseAsyncPending):
     70        * runtime/JSRunLoopTimer.cpp: Renamed from Source/JavaScriptCore/heap/HeapTimer.cpp.
     71        (JSC::JSRunLoopTimer::JSRunLoopTimer):
     72        (JSC::JSRunLoopTimer::setRunLoop):
     73        (JSC::JSRunLoopTimer::~JSRunLoopTimer):
     74        (JSC::JSRunLoopTimer::timerDidFire):
     75        (JSC::JSRunLoopTimer::scheduleTimer):
     76        (JSC::JSRunLoopTimer::cancelTimer):
     77        (JSC::JSRunLoopTimer::invalidate):
     78        * runtime/JSRunLoopTimer.h: Copied from Source/JavaScriptCore/heap/HeapTimer.h.
     79        * runtime/Options.h:
     80        * runtime/PromiseDeferredTimer.cpp: Added.
     81        (JSC::PromiseDeferredTimer::PromiseDeferredTimer):
     82        (JSC::PromiseDeferredTimer::doWork):
     83        (JSC::PromiseDeferredTimer::runRunLoop):
     84        (JSC::PromiseDeferredTimer::addPendingPromise):
     85        (JSC::PromiseDeferredTimer::cancelPendingPromise):
     86        (JSC::PromiseDeferredTimer::scheduleWorkSoon):
     87        (JSC::PromiseDeferredTimer::scheduleBlockedTask):
     88        * runtime/PromiseDeferredTimer.h: Renamed from Source/JavaScriptCore/heap/HeapTimer.h.
     89        (JSC::PromiseDeferredTimer::stopRunningTasks):
     90        * runtime/VM.cpp:
     91        (JSC::VM::VM):
     92        (JSC::VM::~VM):
     93        * runtime/VM.h:
     94        * wasm/JSWebAssembly.cpp:
     95        (JSC::reject):
     96        (JSC::webAssemblyCompileFunc):
     97        (JSC::resolve):
     98        (JSC::instantiate):
     99        (JSC::compileAndInstantiate):
     100        (JSC::webAssemblyInstantiateFunc):
     101        (JSC::webAssemblyValidateFunc):
     102        * wasm/WasmB3IRGenerator.cpp:
     103        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
     104        (JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
     105        (JSC::Wasm::B3IRGenerator::memoryKind):
     106        (JSC::Wasm::parseAndCompile):
     107        * wasm/WasmB3IRGenerator.h:
     108        * wasm/WasmFormat.h:
     109        (JSC::Wasm::ModuleInformation::internalFunctionCount):
     110        * wasm/WasmFunctionParser.h:
     111        * wasm/WasmMemory.h:
     112        * wasm/WasmMemoryInformation.cpp:
     113        (JSC::Wasm::MemoryInformation::MemoryInformation):
     114        * wasm/WasmMemoryInformation.h:
     115        (JSC::Wasm::MemoryInformation::maximum):
     116        (JSC::Wasm::MemoryInformation::hasReservedMemory): Deleted.
     117        (JSC::Wasm::MemoryInformation::takeReservedMemory): Deleted.
     118        (JSC::Wasm::MemoryInformation::mode): Deleted.
     119        * wasm/WasmModuleParser.cpp:
     120        * wasm/WasmModuleParser.h:
     121        (JSC::Wasm::ModuleParser::ModuleParser):
     122        * wasm/WasmPlan.cpp:
     123        (JSC::Wasm::Plan::Plan):
     124        (JSC::Wasm::Plan::stateString):
     125        (JSC::Wasm::Plan::moveToState):
     126        (JSC::Wasm::Plan::fail):
     127        (JSC::Wasm::Plan::parseAndValidateModule):
     128        (JSC::Wasm::Plan::prepare):
     129        (JSC::Wasm::Plan::ThreadCountHolder::ThreadCountHolder):
     130        (JSC::Wasm::Plan::ThreadCountHolder::~ThreadCountHolder):
     131        (JSC::Wasm::Plan::compileFunctions):
     132        (JSC::Wasm::Plan::complete):
     133        (JSC::Wasm::Plan::waitForCompletion):
     134        (JSC::Wasm::Plan::cancel):
     135        (JSC::Wasm::Plan::run): Deleted.
     136        (JSC::Wasm::Plan::initializeCallees): Deleted.
     137        * wasm/WasmPlan.h:
     138        (JSC::Wasm::Plan::dontFinalize):
     139        (JSC::Wasm::Plan::exports):
     140        (JSC::Wasm::Plan::internalFunctionCount):
     141        (JSC::Wasm::Plan::takeModuleInformation):
     142        (JSC::Wasm::Plan::takeCallLinkInfos):
     143        (JSC::Wasm::Plan::takeWasmExitStubs):
     144        (JSC::Wasm::Plan::setModeAndPromise):
     145        (JSC::Wasm::Plan::mode):
     146        (JSC::Wasm::Plan::pendingPromise):
     147        (JSC::Wasm::Plan::vm):
     148        (JSC::Wasm::Plan::errorMessage):
     149        (JSC::Wasm::Plan::failed):
     150        (JSC::Wasm::Plan::hasWork):
     151        (JSC::Wasm::Plan::hasBeenPrepared):
     152        * wasm/WasmPlanInlines.h: Copied from Source/JavaScriptCore/wasm/WasmB3IRGenerator.h.
     153        (JSC::Wasm::Plan::initializeCallees):
     154        * wasm/WasmValidate.cpp:
     155        * wasm/WasmWorklist.cpp: Added.
     156        (JSC::Wasm::Worklist::priorityString):
     157        (JSC::Wasm::Worklist::QueueElement::setToNextPriority):
     158        (JSC::Wasm::Worklist::iterate):
     159        (JSC::Wasm::Worklist::enqueue):
     160        (JSC::Wasm::Worklist::completePlanSynchronously):
     161        (JSC::Wasm::Worklist::stopAllPlansForVM):
     162        (JSC::Wasm::Worklist::Worklist):
     163        (JSC::Wasm::Worklist::~Worklist):
     164        (JSC::Wasm::existingWorklistOrNull):
     165        (JSC::Wasm::ensureWorklist):
     166        * wasm/WasmWorklist.h: Added.
     167        (JSC::Wasm::Worklist::nextTicket):
     168        (JSC::Wasm::Worklist::Comparator::operator()):
     169        * wasm/js/JSWebAssemblyCallee.h:
     170        * wasm/js/JSWebAssemblyCodeBlock.cpp:
     171        (JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
     172        (JSC::JSWebAssemblyCodeBlock::initialize):
     173        (JSC::JSWebAssemblyCodeBlock::isSafeToRun):
     174        * wasm/js/JSWebAssemblyCodeBlock.h:
     175        (JSC::JSWebAssemblyCodeBlock::create):
     176        (JSC::JSWebAssemblyCodeBlock::initialized):
     177        (JSC::JSWebAssemblyCodeBlock::plan):
     178        (JSC::JSWebAssemblyCodeBlock::runnable):
     179        (JSC::JSWebAssemblyCodeBlock::errorMessage):
     180        (JSC::JSWebAssemblyCodeBlock::callees):
     181        * wasm/js/JSWebAssemblyHelpers.h:
     182        (JSC::createSourceBufferFromValue):
     183        * wasm/js/JSWebAssemblyInstance.cpp:
     184        (JSC::JSWebAssemblyInstance::finishCreation):
     185        (JSC::JSWebAssemblyInstance::visitChildren):
     186        (JSC::JSWebAssemblyInstance::addUnitializedCodeBlock):
     187        (JSC::JSWebAssemblyInstance::finalizeCreation):
     188        (JSC::JSWebAssemblyInstance::create):
     189        (JSC::JSWebAssemblyInstance::setMemory): Deleted.
     190        * wasm/js/JSWebAssemblyInstance.h:
     191        (JSC::JSWebAssemblyInstance::codeBlock):
     192        (JSC::JSWebAssemblyInstance::initialized):
     193        (JSC::JSWebAssemblyInstance::module):
     194        (JSC::JSWebAssemblyInstance::importFunction):
     195        (JSC::JSWebAssemblyInstance::setMemory):
     196        (JSC::JSWebAssemblyInstance::table):
     197        (JSC::JSWebAssemblyInstance::importFunctions):
     198        (JSC::JSWebAssemblyInstance::setImportFunction): Deleted.
     199        (JSC::JSWebAssemblyInstance::setTable): Deleted.
     200        * wasm/js/JSWebAssemblyModule.cpp:
     201        (JSC::JSWebAssemblyModule::createStub):
     202        (JSC::JSWebAssemblyModule::JSWebAssemblyModule):
     203        (JSC::JSWebAssemblyModule::finishCreation):
     204        (JSC::JSWebAssemblyModule::setCodeBlock):
     205        (JSC::JSWebAssemblyModule::buildCodeBlock): Deleted.
     206        (JSC::JSWebAssemblyModule::create): Deleted.
     207        (JSC::JSWebAssemblyModule::codeBlock): Deleted.
     208        * wasm/js/JSWebAssemblyModule.h:
     209        (JSC::JSWebAssemblyModule::moduleInformation):
     210        (JSC::JSWebAssemblyModule::codeBlock):
     211        (JSC::JSWebAssemblyModule::source):
     212        (JSC::JSWebAssemblyModule::takeReservedMemory): Deleted.
     213        (JSC::JSWebAssemblyModule::codeBlockFor): Deleted.
     214        * wasm/js/WebAssemblyInstanceConstructor.cpp:
     215        (JSC::constructJSWebAssemblyInstance):
     216        (JSC::WebAssemblyInstanceConstructor::createInstance): Deleted.
     217        * wasm/js/WebAssemblyModuleConstructor.cpp:
     218        (JSC::WebAssemblyModuleConstructor::createModule):
     219        * wasm/js/WebAssemblyModulePrototype.cpp:
     220        (JSC::webAssemblyModuleProtoImports):
     221        (JSC::webAssemblyModuleProtoExports):
     222        * wasm/js/WebAssemblyModuleRecord.cpp:
     223        (JSC::WebAssemblyModuleRecord::finishCreation):
     224        (JSC::WebAssemblyModuleRecord::link):
     225        (JSC::WebAssemblyModuleRecord::evaluate):
     226        * wasm/js/WebAssemblyModuleRecord.h:
     227
    12282017-03-28  Yusuke Suzuki  <utatane.tea@gmail.com>
    2229
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r214465 r214504  
    13221322                52F6C35D1E71EB080081F4CC /* WebAssemblyWrapperFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52F6C35B1E71EB080081F4CC /* WebAssemblyWrapperFunction.cpp */; };
    13231323                52F6C35E1E71EB080081F4CC /* WebAssemblyWrapperFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1324                530FB3021E7A0B6E003C19DD /* WasmWorklist.h in Headers */ = {isa = PBXBuildFile; fileRef = 530FB3011E7A0B6E003C19DD /* WasmWorklist.h */; };
     1325                530FB3041E7A1146003C19DD /* WasmWorklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 530FB3031E7A1146003C19DD /* WasmWorklist.cpp */; };
    13241326                531374BD1D5CE67600AF7A0B /* WasmPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 531374BC1D5CE67600AF7A0B /* WasmPlan.h */; };
    13251327                531374BF1D5CE95000AF7A0B /* WasmPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */; };
     
    13271329                5341FC701DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */; };
    13281330                5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; };
     1331                534638711E70CF3D00F12AC1 /* JSRunLoopTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1332                534638731E70D01500F12AC1 /* JSRunLoopTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534638721E70D01500F12AC1 /* JSRunLoopTimer.cpp */; };
     1333                534638751E70DDEC00F12AC1 /* PromiseDeferredTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 534638741E70DDEC00F12AC1 /* PromiseDeferredTimer.h */; };
     1334                534638771E71E06E00F12AC1 /* PromiseDeferredTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534638761E71E06E00F12AC1 /* PromiseDeferredTimer.cpp */; };
    13291335                53486BB71C1795C300F6F3AF /* JSTypedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 53486BB61C1795C300F6F3AF /* JSTypedArray.h */; settings = {ATTRIBUTES = (Public, ); }; };
    13301336                53486BBB1C18E84500F6F3AF /* JSTypedArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53486BBA1C18E84500F6F3AF /* JSTypedArray.cpp */; };
     
    13601366                53F40E971D5A7BEC0099A1B6 /* WasmModuleParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F40E961D5A7BEC0099A1B6 /* WasmModuleParser.cpp */; };
    13611367                53F6BF6D1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1368                53F8D2001E8387D400D21116 /* WasmPlanInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F8D1FF1E8387D400D21116 /* WasmPlanInlines.h */; };
    13621369                53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
    13631370                53FA2AE31CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */; };
     
    22392246                C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */; };
    22402247                C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DA778218E259990066FCB6 /* HeapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2241                 C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E526BB1590EF000054E48D /* HeapTimer.cpp */; };
    2242                 C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E526BC1590EF000054E48D /* HeapTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
    22432248                C2F0F2D116BAEEE900187C19 /* StructureRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F0F2D016BAEEE900187C19 /* StructureRareData.cpp */; };
    22442249                C2FCAE1017A9C24E0034C735 /* BytecodeBasicBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */; };
     
    38113816                52F6C35B1E71EB080081F4CC /* WebAssemblyWrapperFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyWrapperFunction.cpp; path = js/WebAssemblyWrapperFunction.cpp; sourceTree = "<group>"; };
    38123817                52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyWrapperFunction.h; path = js/WebAssemblyWrapperFunction.h; sourceTree = "<group>"; };
     3818                530FB3011E7A0B6E003C19DD /* WasmWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmWorklist.h; sourceTree = "<group>"; };
     3819                530FB3031E7A1146003C19DD /* WasmWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmWorklist.cpp; sourceTree = "<group>"; };
    38133820                531374BC1D5CE67600AF7A0B /* WasmPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmPlan.h; sourceTree = "<group>"; };
    38143821                531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmPlan.cpp; sourceTree = "<group>"; };
     
    38163823                5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3WasmBoundsCheckValue.cpp; path = b3/B3WasmBoundsCheckValue.cpp; sourceTree = "<group>"; };
    38173824                5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3WasmBoundsCheckValue.h; path = b3/B3WasmBoundsCheckValue.h; sourceTree = "<group>"; };
     3825                534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRunLoopTimer.h; sourceTree = "<group>"; };
     3826                534638721E70D01500F12AC1 /* JSRunLoopTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRunLoopTimer.cpp; sourceTree = "<group>"; };
     3827                534638741E70DDEC00F12AC1 /* PromiseDeferredTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PromiseDeferredTimer.h; sourceTree = "<group>"; };
     3828                534638761E71E06E00F12AC1 /* PromiseDeferredTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PromiseDeferredTimer.cpp; sourceTree = "<group>"; };
    38183829                53486BB61C1795C300F6F3AF /* JSTypedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArray.h; sourceTree = "<group>"; };
    38193830                53486BBA1C18E84500F6F3AF /* JSTypedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArray.cpp; sourceTree = "<group>"; };
     
    38553866                53F40E961D5A7BEC0099A1B6 /* WasmModuleParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmModuleParser.cpp; sourceTree = "<group>"; };
    38563867                53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InternalFunctionAllocationProfile.h; sourceTree = "<group>"; };
     3868                53F8D1FF1E8387D400D21116 /* WasmPlanInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmPlanInlines.h; sourceTree = "<group>"; };
    38573869                53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
    38583870                53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
     
    47994811                C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAPIWrapperObject.h; sourceTree = "<group>"; };
    48004812                C2DA778218E259990066FCB6 /* HeapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapInlines.h; sourceTree = "<group>"; };
    4801                 C2E526BB1590EF000054E48D /* HeapTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapTimer.cpp; sourceTree = "<group>"; };
    4802                 C2E526BC1590EF000054E48D /* HeapTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapTimer.h; sourceTree = "<group>"; };
    48034813                C2F0F2D016BAEEE900187C19 /* StructureRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureRareData.cpp; sourceTree = "<group>"; };
    48044814                C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeBasicBlock.cpp; sourceTree = "<group>"; };
     
    59205930                                A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */,
    59215931                                A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */,
    5922                                 C2E526BB1590EF000054E48D /* HeapTimer.cpp */,
    5923                                 C2E526BC1590EF000054E48D /* HeapTimer.h */,
    59245932                                0FADE6721D4D23BC00768457 /* HeapUtil.h */,
    59255933                                C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */,
     
    62896297                                531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */,
    62906298                                531374BC1D5CE67600AF7A0B /* WasmPlan.h */,
     6299                                53F8D1FF1E8387D400D21116 /* WasmPlanInlines.h */,
    62916300                                53F40E841D58F9770099A1B6 /* WasmSections.h */,
    62926301                                AD7438BE1E04579200FD0C2A /* WasmSignature.cpp */,
     
    62946303                                53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */,
    62956304                                53FF7F981DBFCD9000A26CCC /* WasmValidate.h */,
     6305                                530FB3031E7A1146003C19DD /* WasmWorklist.cpp */,
     6306                                530FB3011E7A0B6E003C19DD /* WasmWorklist.h */,
    62966307                        );
    62976308                        path = wasm;
     
    64506461                                BCD203470E17135E002C7E82 /* DatePrototype.cpp */,
    64516462                                BCD203480E17135E002C7E82 /* DatePrototype.h */,
     6463                                534638761E71E06E00F12AC1 /* PromiseDeferredTimer.cpp */,
     6464                                534638741E70DDEC00F12AC1 /* PromiseDeferredTimer.h */,
    64526465                                169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */,
    64536466                                0FE0500F1AA9091100D33B33 /* DirectArguments.cpp */,
     
    68386851                                BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */,
    68396852                                BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */,
     6853                                534638721E70D01500F12AC1 /* JSRunLoopTimer.cpp */,
     6854                                534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */,
    68406855                                70B0A9D01A9B66200001306A /* RuntimeFlags.h */,
    68416856                                527773DD1AAF83AC00BDE7E8 /* RuntimeType.cpp */,
     
    81318146                                0FEC85081BDACDAC0080FF74 /* B3CheckValue.h in Headers */,
    81328147                                0FEC850A1BDACDAC0080FF74 /* B3Common.h in Headers */,
     8148                                530FB3021E7A0B6E003C19DD /* WasmWorklist.h in Headers */,
    81338149                                0FEC850C1BDACDAC0080FF74 /* B3Commutativity.h in Headers */,
    81348150                                0F338E0C1BF0276C0013C88F /* B3Compilation.h in Headers */,
     
    82518267                                0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */,
    82528268                                1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */,
     8269                                534638751E70DDEC00F12AC1 /* PromiseDeferredTimer.h in Headers */,
    82538270                                62EC9BB71B7EB07C00303AD1 /* CallFrameShuffleData.h in Headers */,
    82548271                                0FF4B4BD1E88449A00DBBE86 /* AirRegLiveness.h in Headers */,
     
    85388555                                E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */,
    85398556                                E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */,
     8557                                534638711E70CF3D00F12AC1 /* JSRunLoopTimer.h in Headers */,
    85408558                                FE6F56DE1E64EAD600D17801 /* VMTraps.h in Headers */,
    85418559                                E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */,
     
    87088726                                A54C2AB11C6544F200A18D78 /* HeapSnapshot.h in Headers */,
    87098727                                A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */,
    8710                                 C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
    87118728                                0FD0E5EA1E43D34D0006AB08 /* GCConductor.h in Headers */,
    87128729                                0FADE6731D4D23BE00768457 /* HeapUtil.h in Headers */,
     
    91589175                                A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */,
    91599176                                BCD202C20E1706A7002C7E82 /* RegExpConstructor.h in Headers */,
     9177                                53F8D2001E8387D400D21116 /* WasmPlanInlines.h in Headers */,
    91609178                                BCD202D60E170708002C7E82 /* RegExpConstructor.lut.h in Headers */,
    91619179                                0F7C39FB1C8F629300480151 /* RegExpInlines.h in Headers */,
     
    99789996                                0FF4B4CA1E889D7B00DBBE86 /* B3VariableLiveness.cpp in Sources */,
    99799997                                0FEC85111BDACDAC0080FF74 /* B3ConstDoubleValue.cpp in Sources */,
     9998                                530FB3041E7A1146003C19DD /* WasmWorklist.cpp in Sources */,
    99809999                                43422A621C158E6A00E2EB98 /* B3ConstFloatValue.cpp in Sources */,
    998110000                                0F338DF51BE93D550013C88F /* B3ConstrainedValue.cpp in Sources */,
     
    1027110290                                147341E21DC2CE9600AA29BA /* EvalExecutable.cpp in Sources */,
    1027210291                                A54982031891D0B00081E5B8 /* EventLoop.cpp in Sources */,
     10292                                534638731E70D01500F12AC1 /* JSRunLoopTimer.cpp in Sources */,
    1027310293                                FE1C0FFF1B194FD100B53FCA /* Exception.cpp in Sources */,
    1027410294                                FE80C19B1D776A98008510C0 /* ExceptionEventLocation.cpp in Sources */,
     
    1034810368                                A54C2AB01C6544EE00A18D78 /* HeapSnapshot.cpp in Sources */,
    1034910369                                A5311C371C77CECA00E6B1B6 /* HeapSnapshotBuilder.cpp in Sources */,
    10350                                 C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */,
    1035110370                                0F4680D414BBD24900BFE272 /* HostCallReturnValue.cpp in Sources */,
    1035210371                                DC2143081CA32E58000A8869 /* ICStats.cpp in Sources */,
     
    1067310692                                992F56B41E4E84A40035953B /* RemoteConnectionToTargetCocoa.mm in Sources */,
    1067410693                                998ED6741BED70AC00DD8017 /* RemoteControllableTarget.cpp in Sources */,
     10694                                534638771E71E06E00F12AC1 /* PromiseDeferredTimer.cpp in Sources */,
    1067510695                                A594558F18245EFD00CC3843 /* RemoteInspectionTarget.cpp in Sources */,
    1067610696                                995566861E4E8B0F00AAE13C /* RemoteInspector.cpp in Sources */,
  • trunk/Source/JavaScriptCore/heap/GCActivityCallback.h

    r212541 r214504  
    2929#pragma once
    3030
    31 #include "HeapTimer.h"
     31#include "JSRunLoopTimer.h"
    3232#include <wtf/RefPtr.h>
    3333
     
    4141class Heap;
    4242
    43 class JS_EXPORT_PRIVATE GCActivityCallback : public HeapTimer {
     43class JS_EXPORT_PRIVATE GCActivityCallback : public JSRunLoopTimer {
    4444public:
     45    using Base = JSRunLoopTimer;
    4546    static RefPtr<FullGCActivityCallback> createFullTimer(Heap*);
    4647    static RefPtr<GCActivityCallback> createEdenTimer(Heap*);
     
    7172#if USE(CF)
    7273    GCActivityCallback(VM* vm)
    73         : HeapTimer(vm)
     74        : Base(vm)
    7475        , m_enabled(true)
    7576        , m_delay(s_decade)
     
    7879#elif USE(GLIB)
    7980    GCActivityCallback(VM* vm)
    80         : HeapTimer(vm)
     81        : Base(vm)
    8182        , m_enabled(true)
    8283        , m_delay(s_decade)
     
    8586#else
    8687    GCActivityCallback(VM* vm)
    87         : HeapTimer(vm)
     88        : Base(vm)
    8889        , m_enabled(true)
    8990    {
  • trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp

    r212778 r214504  
    4242void IncrementalSweeper::scheduleTimer()
    4343{
    44     HeapTimer::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier);
     44    Base::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier);
    4545}
    4646
    4747IncrementalSweeper::IncrementalSweeper(Heap* heap)
    48     : HeapTimer(heap->vm())
     48    : Base(heap->vm())
    4949    , m_currentAllocator(nullptr)
    5050{
  • trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h

    r212778 r214504  
    2626#pragma once
    2727
    28 #include "HeapTimer.h"
     28#include "JSRunLoopTimer.h"
    2929#include <wtf/Vector.h>
    3030
     
    3434class MarkedAllocator;
    3535
    36 class IncrementalSweeper : public HeapTimer {
     36class IncrementalSweeper : public JSRunLoopTimer {
    3737public:
     38    using Base = JSRunLoopTimer;
    3839    JS_EXPORT_PRIVATE explicit IncrementalSweeper(Heap*);
    3940
  • trunk/Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp

    r208306 r214504  
    3232
    3333StopIfNecessaryTimer::StopIfNecessaryTimer(VM* vm)
    34     : HeapTimer(vm)
     34    : Base(vm)
    3535{
    3636}
  • trunk/Source/JavaScriptCore/heap/StopIfNecessaryTimer.h

    r208306 r214504  
    2626#pragma once
    2727
    28 #include "HeapTimer.h"
     28#include "JSRunLoopTimer.h"
    2929
    3030namespace JSC {
     
    3232class Heap;
    3333
    34 class StopIfNecessaryTimer : public HeapTimer {
     34class StopIfNecessaryTimer : public JSRunLoopTimer {
    3535public:
     36    using Base = JSRunLoopTimer;
    3637    explicit StopIfNecessaryTimer(VM*);
    3738   
  • trunk/Source/JavaScriptCore/heap/StrongInlines.h

    r206525 r214504  
    2626#pragma once
    2727
     28#include "JSCJSValueInlines.h"
    2829#include "VM.h"
    2930
  • trunk/Source/JavaScriptCore/jsc.cpp

    r214289 r214504  
    6363#include "ParserError.h"
    6464#include "ProfilerDatabase.h"
     65#include "PromiseDeferredTimer.h"
    6566#include "ProtoCallFrame.h"
    6667#include "ReleaseHeapAccessScope.h"
     
    7475#include "TypeProfilerLog.h"
    7576#include "WasmFaultSignalHandler.h"
    76 #include "WasmPlan.h"
    7777#include "WasmMemory.h"
     78#include "WasmPlanInlines.h"
     79#include "WasmWorklist.h"
    7880#include <locale.h>
    7981#include <math.h>
     
    908910const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RuntimeArray) };
    909911const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(SimpleObject) };
    910 static bool test262AsyncPassed { false };
    911 static bool test262AsyncTest { false };
     912static unsigned asyncTestPasses { 0 };
     913static unsigned asyncTestExpectedPasses { 0 };
    912914
    913915ElementHandleOwner* Element::handleOwner()
     
    10781080
    10791081static EncodedJSValue JSC_HOST_CALL functionMaxArguments(ExecState*);
     1082static EncodedJSValue JSC_HOST_CALL functionAsyncTestStart(ExecState*);
     1083static EncodedJSValue JSC_HOST_CALL functionAsyncTestPassed(ExecState*);
    10801084
    10811085#if ENABLE(WEBASSEMBLY)
     
    13491353
    13501354        addFunction(vm, "maxArguments", functionMaxArguments, 0);
     1355
     1356        addFunction(vm, "asyncTestStart", functionAsyncTestStart, 1);
     1357        addFunction(vm, "asyncTestPassed", functionAsyncTestPassed, 1);
    13511358
    13521359#if ENABLE(WEBASSEMBLY)
     
    17331740    auto scope = DECLARE_THROW_SCOPE(vm);
    17341741
    1735     if (test262AsyncTest) {
     1742    if (asyncTestExpectedPasses) {
    17361743        JSValue value = exec->argument(0);
    1737         if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete"))
    1738             test262AsyncPassed = true;
    1739         return JSValue::encode(jsUndefined());
     1744        if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete")) {
     1745            asyncTestPasses++;
     1746            return JSValue::encode(jsUndefined());
     1747        }
    17401748    }
    17411749
     
    30503058}
    30513059
     3060EncodedJSValue JSC_HOST_CALL functionAsyncTestStart(ExecState* exec)
     3061{
     3062    VM& vm = exec->vm();
     3063    auto scope = DECLARE_THROW_SCOPE(vm);
     3064
     3065    JSValue numberOfAsyncPasses = exec->argument(0);
     3066    if (!numberOfAsyncPasses.isUInt32())
     3067        return throwVMError(exec, scope, ASCIILiteral("Expected first argument to a uint32"));
     3068
     3069    asyncTestExpectedPasses += numberOfAsyncPasses.asUInt32();
     3070    return encodedJSUndefined();
     3071}
     3072
     3073EncodedJSValue JSC_HOST_CALL functionAsyncTestPassed(ExecState*)
     3074{
     3075    asyncTestPasses++;
     3076    return encodedJSUndefined();
     3077}
     3078
    30523079#if ENABLE(WEBASSEMBLY)
    30533080
     
    31603187        CRASH();
    31613188
    3162     Wasm::Plan plan(&vm, static_cast<uint8_t*>(source->vector()), source->length());
    3163     plan.run();
    3164     if (plan.failed()) {
    3165         dataLogLn("failed to parse module: ", plan.errorMessage());
     3189    Ref<Wasm::Plan> plan = adoptRef(*new Wasm::Plan(vm, static_cast<uint8_t*>(source->vector()), source->length(), Wasm::Plan::FullCompile, Wasm::Plan::dontFinalize));
     3190    Wasm::ensureWorklist().enqueue(plan.copyRef());
     3191    Wasm::ensureWorklist().completePlanSynchronously(plan.get());
     3192    if (plan->failed()) {
     3193        dataLogLn("failed to parse module: ", plan->errorMessage());
    31663194        CRASH();
    31673195    }
    31683196
    3169     if (plan.internalFunctionCount() != functionCount)
     3197    if (plan->internalFunctionCount() != functionCount)
    31703198        CRASH();
    31713199
     
    31743202    {
    31753203        unsigned lastIndex = UINT_MAX;
    3176         plan.initializeCallees(exec->lexicalGlobalObject(),
     3204        plan->initializeCallees(
    31773205            [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
    31783206                RELEASE_ASSERT(!calleeIndex || (calleeIndex - 1 == lastIndex));
     
    31823210            });
    31833211    }
    3184     std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan.takeModuleInformation();
     3212    std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan->takeModuleInformation();
    31853213    RELEASE_ASSERT(!moduleInformation->memory);
    31863214
     
    36673695
    36683696        if (!strcmp(arg, "--test262-async")) {
    3669             test262AsyncTest = true;
     3697            asyncTestExpectedPasses++;
    36703698            continue;
    36713699        }
     
    37393767   
    37403768    VM& vm = VM::create(LargeHeap).leakRef();
    3741     JSLockHolder locker(&vm);
    3742 
    37433769    int result;
    3744     if (options.m_profile && !vm.m_perBytecodeProfiler)
    3745         vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
    3746 
    3747     GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
    3748     globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
    3749     bool success = func(vm, globalObject);
    3750     if (options.m_interactive && success)
    3751         runInteractive(globalObject);
    3752 
    3753     vm.drainMicrotasks();
    3754     result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
    3755 
    3756     if (options.m_exitCode)
    3757         printf("jsc exiting %d\n", result);
     3770    bool success;
     3771    {
     3772        JSLockHolder locker(vm);
     3773
     3774        if (options.m_profile && !vm.m_perBytecodeProfiler)
     3775            vm.m_perBytecodeProfiler = std::make_unique<Profiler::Database>(vm);
     3776
     3777        GlobalObject* globalObject = GlobalObject::create(vm, GlobalObject::createStructure(vm, jsNull()), options.m_arguments);
     3778        globalObject->setRemoteDebuggingEnabled(options.m_enableRemoteDebugging);
     3779        success = func(vm, globalObject);
     3780        if (options.m_interactive && success)
     3781            runInteractive(globalObject);
     3782
     3783        vm.drainMicrotasks();
     3784    }
     3785#if USE(CF)
     3786    vm.promiseDeferredTimer->runRunLoop();
     3787#endif
     3788
     3789    result = success && (asyncTestExpectedPasses == asyncTestPasses) ? 0 : 3;
     3790
     3791    if (options.m_exitCode) {
     3792        printf("jsc exiting %d", result);
     3793        if (asyncTestExpectedPasses != asyncTestPasses)
     3794            printf(" because expected: %d async test passes but got: %d async test passes", asyncTestExpectedPasses, asyncTestPasses);
     3795        printf("\n");
     3796    }
    37583797
    37593798    if (options.m_profile) {
     3799        JSLockHolder locker(vm);
    37603800        if (!vm.m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
    37613801            fprintf(stderr, "could not save profiler output.\n");
     
    37633803
    37643804#if ENABLE(JIT)
    3765     if (Options::useExceptionFuzz())
    3766         printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
    3767     bool fireAtEnabled =
    3768     Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
    3769     if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
    3770         printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
    3771     if (Options::useOSRExitFuzz()) {
    3772         printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
    3773         printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
    3774     }
    3775 
    3776     auto compileTimeStats = JIT::compileTimeStats();
    3777     Vector<CString> compileTimeKeys;
    3778     for (auto& entry : compileTimeStats)
    3779         compileTimeKeys.append(entry.key);
    3780     std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
    3781     for (CString key : compileTimeKeys)
    3782         printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
     3805    {
     3806        JSLockHolder locker(vm);
     3807        if (Options::useExceptionFuzz())
     3808            printf("JSC EXCEPTION FUZZ: encountered %u checks.\n", numberOfExceptionFuzzChecks());
     3809        bool fireAtEnabled =
     3810        Options::fireExecutableAllocationFuzzAt() || Options::fireExecutableAllocationFuzzAtOrAfter();
     3811        if (Options::useExecutableAllocationFuzz() && (!fireAtEnabled || Options::verboseExecutableAllocationFuzz()))
     3812            printf("JSC EXECUTABLE ALLOCATION FUZZ: encountered %u checks.\n", numberOfExecutableAllocationFuzzChecks());
     3813        if (Options::useOSRExitFuzz()) {
     3814            printf("JSC OSR EXIT FUZZ: encountered %u static checks.\n", numberOfStaticOSRExitFuzzChecks());
     3815            printf("JSC OSR EXIT FUZZ: encountered %u dynamic checks.\n", numberOfOSRExitFuzzChecks());
     3816        }
     3817
     3818       
     3819        auto compileTimeStats = JIT::compileTimeStats();
     3820        Vector<CString> compileTimeKeys;
     3821        for (auto& entry : compileTimeStats)
     3822            compileTimeKeys.append(entry.key);
     3823        std::sort(compileTimeKeys.begin(), compileTimeKeys.end());
     3824        for (CString key : compileTimeKeys)
     3825            printf("%40s: %.3lf ms\n", key.data(), compileTimeStats.get(key));
     3826    }
    37833827#endif
    37843828
  • trunk/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp

    r214218 r214504  
    3434#include "JSPromise.h"
    3535#include "JSPromiseConstructor.h"
     36#include "PromiseDeferredTimer.h"
    3637
    3738namespace JSC {
     
    100101{
    101102    callFunction(exec, m_resolve.get(), value);
     103    bool wasPending = exec->vm().promiseDeferredTimer->cancelPendingPromise(this);
     104    ASSERT_UNUSED(wasPending, wasPending == m_promiseIsAsyncPending);
    102105}
    103106
     
    105108{
    106109    callFunction(exec, m_reject.get(), reason);
     110    bool wasPending = exec->vm().promiseDeferredTimer->cancelPendingPromise(this);
     111    ASSERT_UNUSED(wasPending, wasPending == m_promiseIsAsyncPending);
    107112}
    108113
  • trunk/Source/JavaScriptCore/runtime/JSPromiseDeferred.h

    r214218 r214504  
    5757    JS_EXPORT_PRIVATE void reject(ExecState*, Exception*);
    5858
     59#ifndef NDEBUG
     60    void promiseAsyncPending() { m_promiseIsAsyncPending = true; }
     61#endif
     62
    5963protected:
    6064    JSPromiseDeferred(VM&, Structure*);
     
    6468private:
    6569    JSPromiseDeferred(VM&);
     70
     71#ifndef NDEBUG
     72    bool m_promiseIsAsyncPending { false };
     73#endif
    6674
    6775    WriteBarrier<JSObject> m_promise;
  • 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
  • trunk/Source/JavaScriptCore/runtime/JSRunLoopTimer.h

    r214502 r214504  
    11/*
    2  * Copyright (C) 2012, 2015-2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012, 2015-2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    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
     
    4545class VM;
    4646
    47 class HeapTimer : public ThreadSafeRefCounted<HeapTimer> {
     47class JSRunLoopTimer : public ThreadSafeRefCounted<JSRunLoopTimer> {
    4848public:
    49     HeapTimer(VM*);
     49    JSRunLoopTimer(VM*);
    5050#if USE(CF)
    5151    static void timerDidFire(CFRunLoopTimerRef, void*);
    5252#endif
    53    
    54     JS_EXPORT_PRIVATE virtual ~HeapTimer();
     53
     54    JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer();
    5555    virtual void doWork() = 0;
    5656
     
    6262    JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
    6363#endif // USE(CF)
    64    
     64
    6565protected:
    6666    VM* m_vm;
     
    7373    RetainPtr<CFRunLoopTimerRef> m_timer;
    7474    RetainPtr<CFRunLoopRef> m_runLoop;
    75    
     75
    7676    CFRunLoopTimerContext m_context;
    7777
     
    8686    void invalidate();
    8787};
    88 
     88   
    8989} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r214384 r214504  
    253253    v(int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
    254254    v(int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), Normal, nullptr) \
     255    v(int32, priorityDeltaOfWasmCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
    255256    \
    256257    v(bool, useProfiler, false, Normal, nullptr) \
     
    429430    \
    430431    v(bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
     432    \
     433    v(bool, failToCompileWebAssemblyCode, false, Normal, "If true, no Wasm::Plan will sucessfully compile a function.") \
     434    \
    431435    v(bool, simulateWebAssemblyLowMemory, false, Normal, "If true, the Memory object won't mmap the full 'maximum' range and instead will allocate the minimum required amount.") \
    432436    v(bool, useWebAssemblyFastMemory, true, Normal, "If true, we will try to use a 32-bit address space with a signal handler to bounds check wasm memory.") \
  • trunk/Source/JavaScriptCore/runtime/PromiseDeferredTimer.h

    r214502 r214504  
    11/*
    2  * Copyright (C) 2012, 2015-2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    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#pragma once
    2727
     28#include "JSRunLoopTimer.h"
     29#include "Strong.h"
     30#include "WriteBarrier.h"
     31
     32#include <wtf/HashMap.h>
    2833#include <wtf/Lock.h>
    29 #include <wtf/RefPtr.h>
    30 #include <wtf/RetainPtr.h>
    31 #include <wtf/ThreadSafeRefCounted.h>
    32 #include <wtf/Threading.h>
    33 
    34 #if USE(CF)
    35 #include <CoreFoundation/CoreFoundation.h>
    36 #endif
    37 
    38 #if USE(GLIB)
    39 #include <wtf/glib/GRefPtr.h>
    40 #endif
     34#include <wtf/SharedTask.h>
     35#include <wtf/Vector.h>
    4136
    4237namespace JSC {
    4338
    44 class JSLock;
     39class JSPromiseDeferred;
    4540class VM;
     41class JSCell;
    4642
    47 class HeapTimer : public ThreadSafeRefCounted<HeapTimer> {
     43class PromiseDeferredTimer : public JSRunLoopTimer {
    4844public:
    49     HeapTimer(VM*);
     45    using Base = JSRunLoopTimer;
     46
     47    PromiseDeferredTimer(VM&);
     48
     49    void doWork() override;
     50
     51    void addPendingPromise(JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies);
     52    // JSPromiseDeferred should handle canceling when the promise is resolved or rejected.
     53    bool cancelPendingPromise(JSPromiseDeferred*);
     54
     55    typedef std::function<void()> Task;
     56    void scheduleWorkSoon(JSPromiseDeferred*, Task&&);
     57
     58    // Blocked tasks should only be registered while holding the JS API lock. If we didn't require holding the
     59    // JS API lock then there might be a race where the promise you are waiting on is run before your task is
     60    // registered.
     61    void scheduleBlockedTask(JSPromiseDeferred*, Task&&);
     62
     63    void stopRunningTasks() { m_runTasks = false; }
    5064#if USE(CF)
    51     static void timerDidFire(CFRunLoopTimerRef, void*);
     65    JS_EXPORT_PRIVATE void runRunLoop();
    5266#endif
    53    
    54     JS_EXPORT_PRIVATE virtual ~HeapTimer();
    55     virtual void doWork() = 0;
    5667
    57     void scheduleTimer(double intervalInSeconds);
    58     void cancelTimer();
    59     bool isScheduled() const { return m_isScheduled; }
    60 
     68private:
     69    HashMap<JSPromiseDeferred*, Vector<Strong<JSCell>>> m_pendingPromises;
     70    Lock m_taskLock;
     71    bool m_runTasks { true };
    6172#if USE(CF)
    62     JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
    63 #endif // USE(CF)
    64    
    65 protected:
    66     VM* m_vm;
    67 
    68     RefPtr<JSLock> m_apiLock;
    69     bool m_isScheduled { false };
    70 #if USE(CF)
    71     static const CFTimeInterval s_decade;
    72 
    73     RetainPtr<CFRunLoopTimerRef> m_timer;
    74     RetainPtr<CFRunLoopRef> m_runLoop;
    75    
    76     CFRunLoopTimerContext m_context;
    77 
    78     Lock m_shutdownMutex;
    79 #elif USE(GLIB)
    80     static const long s_decade;
    81     void timerDidFire();
    82     GRefPtr<GSource> m_timer;
     73    bool m_shouldStopRunLoopWhenAllPromisesFinish { false };
    8374#endif
    84    
    85 private:
    86     void invalidate();
     75    Vector<std::tuple<JSPromiseDeferred*, Task>> m_tasks;
     76    HashMap<JSPromiseDeferred*, Vector<Task>> m_blockedTasks;
    8777};
    8878
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r214498 r214504  
    8686#include "ProfilerDatabase.h"
    8787#include "ProgramCodeBlock.h"
     88#include "PromiseDeferredTimer.h"
    8889#include "PropertyMapHashTable.h"
    8990#include "RegExpCache.h"
     
    104105#include "VMEntryScope.h"
    105106#include "VMInspector.h"
     107#include "WasmWorklist.h"
    106108#include "Watchdog.h"
    107109#include "WeakGCMapInlines.h"
     
    178180    , topVMEntryFrame(nullptr)
    179181    , topCallFrame(CallFrame::noCaller())
     182    , promiseDeferredTimer(std::make_unique<PromiseDeferredTimer>(*this))
    180183    , m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable)
    181184    , propertyNames(nullptr)
     
    356359VM::~VM()
    357360{
     361    promiseDeferredTimer->stopRunningTasks();
     362#if ENABLE(WEBASSEMBLY)
     363    if (Wasm::existingWorklistOrNull())
     364        Wasm::ensureWorklist().stopAllPlansForVM(*this);
     365#endif
    358366    if (UNLIKELY(m_watchdog))
    359367        m_watchdog->willDestroyVM(this);
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r214498 r214504  
    107107class LLIntOffsetsExtractor;
    108108class NativeExecutable;
     109class PromiseDeferredTimer;
    109110class RegExpCache;
    110111class Register;
     
    380381    std::unique_ptr<Wasm::SignatureInformation> m_wasmSignatureInformation;
    381382#endif
     383    std::unique_ptr<PromiseDeferredTimer> promiseDeferredTimer;
    382384   
    383385    JSCell* currentlyDestructingCallbackObject;
  • trunk/Source/JavaScriptCore/wasm/JSWebAssembly.cpp

    r213506 r214504  
    3434#include "JSPromiseDeferred.h"
    3535#include "JSWebAssemblyHelpers.h"
     36#include "JSWebAssemblyInstance.h"
     37#include "JSWebAssemblyModule.h"
    3638#include "ObjectConstructor.h"
     39#include "PromiseDeferredTimer.h"
     40#include "StrongInlines.h"
    3741#include "WasmPlan.h"
     42#include "WasmWorklist.h"
    3843#include "WebAssemblyModuleConstructor.h"
     44
     45using JSC::Wasm::Plan;
    3946
    4047namespace JSC {
     
    4653EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState*);
    4754
     55static EncodedJSValue reject(ExecState* exec, CatchScope& catchScope, JSPromiseDeferred* promise)
     56{
     57    Exception* exception = catchScope.exception();
     58    ASSERT(exception);
     59    catchScope.clearException();
     60    promise->reject(exec, exception->value());
     61    return JSValue::encode(promise->promise());
     62}
     63
    4864EncodedJSValue JSC_HOST_CALL webAssemblyCompileFunc(ExecState* exec)
     65{
     66    VM& vm = exec->vm();
     67    auto scope = DECLARE_CATCH_SCOPE(vm);
     68    auto* globalObject = exec->lexicalGlobalObject();
     69
     70    JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, globalObject);
     71    RETURN_IF_EXCEPTION(scope, { });
     72
     73    RefPtr<ArrayBuffer> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
     74    RETURN_IF_EXCEPTION(scope, { });
     75
     76    Vector<Strong<JSCell>> dependencies;
     77    dependencies.append(Strong<JSCell>(vm, globalObject));
     78    vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
     79
     80    Ref<Plan> plan = adoptRef(*new Plan(vm, *source, Plan::Validation, [source, promise, globalObject] (Plan& p) mutable {
     81        RefPtr<Plan> plan = makeRef(p);
     82        plan->vm().promiseDeferredTimer->scheduleWorkSoon(promise, [source, promise, globalObject, plan = WTFMove(plan)] () mutable {
     83            VM& vm = plan->vm();
     84            auto scope = DECLARE_CATCH_SCOPE(vm);
     85            ExecState* exec = globalObject->globalExec();
     86            JSValue module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(source), WTFMove(plan));
     87            if (scope.exception()) {
     88                reject(exec, scope, promise);
     89                return;
     90            }
     91
     92            promise->resolve(exec, module);
     93        });
     94    }));
     95
     96    Wasm::ensureWorklist().enqueue(WTFMove(plan));
     97    return JSValue::encode(promise->promise());
     98}
     99
     100enum class Resolve { WithInstance, WithModuleAndInstance };
     101static void resolve(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyInstance* instance, JSWebAssemblyModule* module, Resolve entries)
     102{
     103    auto scope = DECLARE_CATCH_SCOPE(vm);
     104    instance->finalizeCreation(vm, exec);
     105    if (scope.exception()) {
     106        reject(exec, scope, promise);
     107        return;
     108    }
     109
     110    if (entries == Resolve::WithInstance)
     111        promise->resolve(exec, instance);
     112    else {
     113        JSObject* result = constructEmptyObject(exec);
     114        result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("module")), module);
     115        result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("instance")), instance);
     116        promise->resolve(exec, result);
     117    }
     118}
     119
     120static void instantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyModule* module, JSObject* importObject, Resolve entries)
     121{
     122    auto scope = DECLARE_CATCH_SCOPE(vm);
     123    // In order to avoid potentially recompiling a module. We first gather all the import/memory information prior to compiling code.
     124    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
     125    if (scope.exception()) {
     126        reject(exec, scope, promise);
     127        return;
     128    }
     129
     130    // There are three possible cases:
     131    // 1) The instance already has an initialized CodeBlock, so we have no more work to do.
     132    // 2) The instance has no CodeBlock, so we need to make one and compile the code for it.
     133    // 3) The instance already has an uninitialized CodeBlock, so someone else is compiling code and we just need to wait for them.
     134
     135    if (instance->initialized()) {
     136        resolve(vm, exec, promise, instance, module, entries);
     137        return;
     138    }
     139
     140    Vector<Strong<JSCell>> dependencies;
     141    // The instance keeps the module alive.
     142    dependencies.append(Strong<JSCell>(vm, instance));
     143    vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
     144
     145    if (instance->codeBlock()) {
     146        vm.promiseDeferredTimer->scheduleBlockedTask(instance->codeBlock()->plan().pendingPromise(), [&vm, promise, instance, module, entries] () {
     147            auto* globalObject = instance->globalObject();
     148            ExecState* exec = globalObject->globalExec();
     149            resolve(vm, exec, promise, instance, module, entries);
     150        });
     151        return;
     152    }
     153    ASSERT(!instance->codeBlock());
     154
     155    // FIXME: This re-parses the module header, which shouldn't be necessary.
     156    // https://bugs.webkit.org/show_bug.cgi?id=170205
     157    Ref<Plan> plan = adoptRef(*new Plan(vm, module->source(), Plan::FullCompile, [promise, instance, module, entries] (Plan& p) {
     158        RefPtr<Plan> plan = makeRef(p);
     159        plan->vm().promiseDeferredTimer->scheduleWorkSoon(promise, [promise, instance, module, entries, plan = WTFMove(plan)] () {
     160            VM& vm = plan->vm();
     161            ExecState* exec = instance->globalObject()->globalExec();
     162            resolve(vm, exec, promise, instance, module, entries);
     163        });
     164    }));
     165
     166    instance->addUnitializedCodeBlock(vm, plan.copyRef());
     167    plan->setModeAndPromise(instance->memoryMode(), promise);
     168    Wasm::ensureWorklist().enqueue(WTFMove(plan));
     169}
     170
     171static void compileAndInstantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSValue buffer, JSObject* importObject)
     172{
     173    auto scope = DECLARE_THROW_SCOPE(vm);
     174    RefPtr<ArrayBuffer> source = createSourceBufferFromValue(vm, exec, buffer);
     175    RETURN_IF_EXCEPTION(scope, void());
     176
     177    auto* globalObject = exec->lexicalGlobalObject();
     178
     179    Vector<Strong<JSCell>> dependencies;
     180    dependencies.append(Strong<JSCell>(vm, importObject));
     181    vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
     182
     183    Ref<Plan> plan = adoptRef(*new Plan(vm, *source, Plan::Validation, [source, promise, importObject, globalObject] (Plan& p) mutable {
     184        RefPtr<Plan> plan = makeRef(p);
     185        plan->vm().promiseDeferredTimer->scheduleWorkSoon(promise, [source, promise, importObject, globalObject, plan = WTFMove(plan)] () mutable {
     186            VM& vm = plan->vm();
     187            auto scope = DECLARE_CATCH_SCOPE(vm);
     188            ExecState* exec = globalObject->globalExec();
     189            JSWebAssemblyModule* module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(source), plan.copyRef());
     190            if (scope.exception()) {
     191                reject(exec, scope, promise);
     192                return;
     193            }
     194
     195            instantiate(vm, exec, promise, module, importObject, Resolve::WithModuleAndInstance);
     196        });
     197    }));
     198
     199    Wasm::ensureWorklist().enqueue(WTFMove(plan));
     200}
     201
     202EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState* exec)
    49203{
    50204    VM& vm = exec->vm();
     
    53207    JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject());
    54208    RETURN_IF_EXCEPTION(catchScope, encodedJSValue());
    55 
    56     // FIXME: Make this truly asynchronous:
    57     // https://bugs.webkit.org/show_bug.cgi?id=166016
    58     JSValue module = WebAssemblyModuleConstructor::createModule(exec, exec->argument(0), exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
    59     if (Exception* exception = catchScope.exception()) {
    60         catchScope.clearException();
    61         promise->reject(exec, exception->value());
    62         return JSValue::encode(promise->promise());
    63     }
    64 
    65     promise->resolve(exec, module);
    66     return JSValue::encode(promise->promise());
    67 }
    68 
    69 EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState* exec)
    70 {
    71     VM& vm = exec->vm();
    72     auto catchScope = DECLARE_CATCH_SCOPE(vm);
    73 
    74     // FIXME: Make this API truly asynchronous: https://bugs.webkit.org/show_bug.cgi?id=169187
    75 
    76     JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject());
    77     RETURN_IF_EXCEPTION(catchScope, encodedJSValue());
    78 
    79     auto reject = [&] () {
    80         Exception* exception = catchScope.exception();
    81         ASSERT(exception);
    82         catchScope.clearException();
    83         promise->reject(exec, exception->value());
    84         return JSValue::encode(promise->promise());
    85     };
    86209
    87210    JSValue importArgument = exec->argument(1);
     
    94217
    95218    JSValue firstArgument = exec->argument(0);
    96     JSValue module;
    97     bool firstArgumentIsModule = false;
    98     if (firstArgument.inherits(vm, JSWebAssemblyModule::info())) {
    99         firstArgumentIsModule = true;
    100         module = firstArgument;
    101     } else {
    102         module = WebAssemblyModuleConstructor::createModule(exec, firstArgument, exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
    103         if (catchScope.exception())
    104             return reject();
    105     }
    106 
    107     JSWebAssemblyInstance* instance = WebAssemblyInstanceConstructor::createInstance(exec, jsCast<JSWebAssemblyModule*>(module), importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
    108     if (catchScope.exception())
    109         return reject();
    110 
    111     if (firstArgumentIsModule)
    112         promise->resolve(exec, instance);
    113     else {
    114         JSObject* result = constructEmptyObject(exec);
    115         result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("module")), module);
    116         result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("instance")), instance);
    117         promise->resolve(exec, result);
    118     }
     219    if (auto* module = jsDynamicCast<JSWebAssemblyModule*>(vm, firstArgument))
     220        instantiate(vm, exec, promise, module, importObject, Resolve::WithInstance);
     221    else
     222        compileAndInstantiate(vm, exec, promise, firstArgument, importObject);
    119223
    120224    return JSValue::encode(promise->promise());
     
    130234    uint8_t* base = getWasmBufferFromValue(exec, exec->argument(0), byteOffset, byteSize);
    131235    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    132     Wasm::Plan plan(&vm, base + byteOffset, byteSize);
     236    Wasm::Plan plan(vm, base + byteOffset, byteSize, Plan::Validation, Plan::dontFinalize);
    133237    // FIXME: We might want to throw an OOM exception here if we detect that something will OOM.
    134238    // https://bugs.webkit.org/show_bug.cgi?id=166015
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r214498 r214504  
    158158    } while (0)
    159159
    160     B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&);
     160    B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode);
    161161
    162162    PartialResult WARN_UNUSED_RETURN addArguments(const Signature*);
     
    226226    VM& m_vm;
    227227    const ModuleInformation& m_info;
     228    MemoryMode m_mode;
    228229    Procedure& m_proc;
    229230    BasicBlock* m_currentBlock;
     
    291292}
    292293
    293 B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls)
     294B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode)
    294295    : m_vm(vm)
    295296    , m_info(info)
     297    , m_mode(mode)
    296298    , m_proc(procedure)
    297299    , m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
     
    521523{
    522524    ASSERT(m_memoryBaseGPR);
    523     if (m_info.memory.mode() == MemoryMode::BoundsChecking) {
     525    if (m_mode == MemoryMode::BoundsChecking) {
    524526        ASSERT(m_memorySizeGPR);
    525527        ASSERT(sizeOfOperation + offset > offset);
     
    557559inline B3::Kind B3IRGenerator::memoryKind(B3::Opcode memoryOp)
    558560{
    559     if (m_info.memory.mode() == MemoryMode::Signaling)
     561    if (m_mode == MemoryMode::Signaling)
    560562        return trapping(memoryOp);
    561563    return memoryOp;
     
    12781280}
    12791281
    1280 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, const Vector<SignatureIndex>& moduleSignatureIndicesToUniquedSignatureIndices, unsigned optLevel)
     1282Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, const Vector<SignatureIndex>& moduleSignatureIndicesToUniquedSignatureIndices, MemoryMode mode, unsigned optLevel)
    12811283{
    12821284    auto result = std::make_unique<WasmInternalFunction>();
     
    12861288
    12871289    Procedure procedure;
    1288     B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls);
     1290    B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, mode);
    12891291    FunctionParser<B3IRGenerator> parser(&vm, context, functionStart, functionLength, signature, info, moduleSignatureIndicesToUniquedSignatureIndices);
    12901292    WASM_FAIL_IF_HELPER_FAILS(parser.parse());
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h

    r210229 r214504  
    3232#include "VM.h"
    3333#include "WasmFormat.h"
     34#include "WasmMemory.h"
    3435#include <wtf/Expected.h>
    3536
     
    4849};
    4950
    50 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, const Vector<SignatureIndex>&, unsigned optLevel = 1);
     51Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, const Vector<SignatureIndex>&, MemoryMode, unsigned optLevel = 1);
    5152
    5253} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r214484 r214504  
    103103
    104104struct Import {
    105     Identifier module;
    106     Identifier field;
     105    String module;
     106    String field;
    107107    ExternalKind kind;
    108108    unsigned kindIndex; // Index in the vector of the corresponding kind.
     
    110110
    111111struct Export {
    112     Identifier field;
     112    String field;
    113113    ExternalKind kind;
    114114    unsigned kindIndex; // Index in the vector of the corresponding kind.
     
    261261
    262262    uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); }
     263    uint32_t internalFunctionCount() const { return internalFunctionSignatureIndices.size(); }
    263264
    264265    ~ModuleInformation();
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r213067 r214504  
    116116        WASM_PARSER_FAIL_IF(numberOfLocals == std::numeric_limits<uint32_t>::max(), "Function section's ", i, "th local group count is too big ", numberOfLocals);
    117117        WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
    118         WASM_PARSER_FAIL_IF(!m_context.addLocal(typeOfLocal, numberOfLocals), "can't add ", numberOfLocals, " Function locals from group ", i);
     118        WASM_TRY_ADD_TO_CONTEXT(addLocal(typeOfLocal, numberOfLocals));
    119119    }
    120120
     
    268268        ExpressionType result;
    269269        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
    270         WASM_PARSER_FAIL_IF(!m_context.getLocal(index, result), "can't get_local at index", index);
     270        WASM_TRY_ADD_TO_CONTEXT(getLocal(index, result));
    271271        m_expressionStack.append(result);
    272272        return { };
     
    305305        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
    306306        WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
    307         return m_context.setGlobal(index, value);
     307        return { };
    308308    }
    309309
  • trunk/Source/JavaScriptCore/wasm/WasmMemory.h

    r214380 r214504  
    4646
    4747// FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
    48 enum class MemoryMode {
     48enum class MemoryMode : uint8_t {
    4949    BoundsChecking,
    5050    Signaling,
  • trunk/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp

    r214498 r214504  
    8989}
    9090
    91 MemoryInformation::MemoryInformation(VM& vm, PageCount initial, PageCount maximum, std::optional<MemoryMode> recompileMode, bool isImport)
     91MemoryInformation::MemoryInformation(PageCount initial, PageCount maximum, bool isImport)
    9292    : m_initial(initial)
    9393    , m_maximum(maximum)
     
    9797    RELEASE_ASSERT(!m_maximum || m_maximum >= m_initial);
    9898    ASSERT(!!*this);
    99 
    100     if (!recompileMode) {
    101         if (!isImport) {
    102             if (maximum && maximum.bytes() == 0) {
    103                 m_reservedMemory = Memory::create(vm, initial, maximum, MemoryMode::BoundsChecking);
    104                 RELEASE_ASSERT(m_reservedMemory);
    105                 RELEASE_ASSERT(m_reservedMemory->maximum());
    106                 RELEASE_ASSERT(m_reservedMemory->maximum().bytes() == 0);
    107                 m_mode = m_reservedMemory->mode();
    108                 return;
    109             }
    110 
    111             m_reservedMemory = Memory::create(vm, initial, maximum, MemoryMode::Signaling);
    112             if (m_reservedMemory) {
    113                 ASSERT(!!*m_reservedMemory);
    114                 m_mode = m_reservedMemory->mode();
    115                 return;
    116             }
    117         }
    118         m_mode = Memory::lastAllocatedMode();
    119     } else
    120         m_mode = *recompileMode;
    12199}
    122100
  • trunk/Source/JavaScriptCore/wasm/WasmMemoryInformation.h

    r214498 r214504  
    6868    }
    6969
    70     MemoryInformation(VM&, PageCount initial, PageCount maximum, std::optional<MemoryMode>, bool isImport);
     70    MemoryInformation(PageCount initial, PageCount maximum, bool isImport);
    7171
    7272    PageCount initial() const { return m_initial; }
    7373    PageCount maximum() const { return m_maximum; }
    74     bool hasReservedMemory() const { return m_reservedMemory; }
    75     RefPtr<Memory> takeReservedMemory() { ASSERT(hasReservedMemory()); return m_reservedMemory.release(); }
    76     MemoryMode mode() const { return m_mode; }
    7774    bool isImport() const { return m_isImport; }
    7875
     
    8077
    8178private:
    82     RefPtr<Memory> m_reservedMemory;
    8379    PageCount m_initial { };
    8480    PageCount m_maximum { };
    85     MemoryMode m_mode { MemoryMode::BoundsChecking };
    8681    bool m_isImport { false };
    8782};
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r213465 r214504  
    163163        WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length");
    164164        WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen);
    165         imp.module = Identifier::fromString(m_vm, moduleString);
     165        imp.module = moduleString;
    166166
    167167        WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'");
    168168        WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'");
    169         imp.field = Identifier::fromString(m_vm, fieldString);
     169        imp.field = fieldString;
    170170
    171171        WASM_PARSER_FAIL_IF(!parseExternalKind(imp.kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'");
     
    317317    ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
    318318
    319     m_result.module->memory = MemoryInformation(*m_vm, initialPageCount, maximumPageCount, m_mode, isImport);
     319    m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, isImport);
    320320    return { };
    321321}
     
    377377        WASM_PARSER_FAIL_IF(exportNames.contains(fieldString), "duplicate export: '", fieldString, "'");
    378378        exportNames.add(fieldString);
    379         exp.field = Identifier::fromString(m_vm, fieldString);
     379        exp.field = fieldString;
    380380
    381381        WASM_PARSER_FAIL_IF(!parseExternalKind(exp.kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'");
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h

    r214380 r214504  
    4545public:
    4646
    47     ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength, std::optional<MemoryMode> mode)
     47
     48    ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
    4849        : Parser(vm, sourceBuffer, sourceLength)
    49         , m_mode(mode)
    5050    {
    5151    }
     
    6767
    6868    ModuleParserResult m_result;
    69     std::optional<MemoryMode> m_mode { std::nullopt };
    7069    bool m_hasTable { false };
    7170};
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r214380 r214504  
    4343#include <wtf/Locker.h>
    4444#include <wtf/MonotonicTime.h>
    45 #include <wtf/NumberOfCores.h>
    4645#include <wtf/StdLibExtras.h>
    4746#include <wtf/SystemTracing.h>
     
    5150
    5251static const bool verbose = false;
    53    
    54 Plan::Plan(VM* vm, Vector<uint8_t> source)
    55     : Plan(vm, source.data(), source.size())
    56 {
    57 }
    58 
    59 Plan::Plan(VM* vm, const uint8_t* source, size_t sourceLength)
     52
     53Plan::Plan(VM& vm, ArrayBuffer& source, AsyncWork work, CompletionTask&& task)
     54    : Plan(vm, reinterpret_cast<uint8_t*>(source.data()), source.byteLength(), work, WTFMove(task))
     55{
     56}
     57
     58Plan::Plan(VM& vm, Vector<uint8_t>& source, AsyncWork work, CompletionTask&& task)
     59    : Plan(vm, source.data(), source.size(), work, WTFMove(task))
     60{
     61}
     62
     63Plan::Plan(VM& vm, const uint8_t* source, size_t sourceLength, AsyncWork work, CompletionTask&& task)
    6064    : m_vm(vm)
     65    , m_completionTask(task)
    6166    , m_source(source)
    6267    , m_sourceLength(sourceLength)
    63 {
    64 }
    65 
    66 bool Plan::parseAndValidateModule(std::optional<MemoryMode> recompileMode)
    67 {
     68    , m_asyncWork(work)
     69{
     70}
     71
     72const char* Plan::stateString(State state)
     73{
     74    switch (state) {
     75    case State::Initial: return "Initial";
     76    case State::Validated: return "Validated";
     77    case State::Prepared: return "Prepared";
     78    case State::Compiled: return "Compiled";
     79    case State::Completed: return "Completed";
     80    }
     81    RELEASE_ASSERT_NOT_REACHED();
     82}
     83
     84void Plan::moveToState(State state)
     85{
     86    ASSERT(state > m_state);
     87    dataLogLnIf(verbose, "moving to state: ", stateString(state), " from state: ", stateString(m_state));
     88    m_state = state;
     89}
     90
     91void Plan::fail(const AbstractLocker& locker, String&& errorMessage)
     92{
     93    dataLogLnIf(verbose, "failing with message: ", errorMessage);
     94    m_errorMessage = WTFMove(errorMessage);
     95    complete(locker);
     96}
     97
     98bool Plan::parseAndValidateModule()
     99{
     100    ASSERT(m_state == State::Initial);
     101    dataLogLnIf(verbose, "starting validation");
    68102    MonotonicTime startTime;
    69103    if (verbose || Options::reportCompileTimes())
     
    71105
    72106    {
    73         ModuleParser moduleParser(m_vm, m_source, m_sourceLength, recompileMode);
     107        ModuleParser moduleParser(&m_vm, m_source, m_sourceLength);
    74108        auto parseResult = moduleParser.parse();
    75109        if (!parseResult) {
    76             m_errorMessage = parseResult.error();
     110            fail(holdLock(m_lock), WTFMove(parseResult.error()));
    77111            return false;
    78112        }
     
    83117
    84118    for (unsigned functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); ++functionIndex) {
    85         if (verbose)
    86             dataLogLn("Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", m_functionLocationInBinary[functionIndex].end);
     119        dataLogLnIf(verbose, "Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", m_functionLocationInBinary[functionIndex].end);
    87120        const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
    88121        size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
    89122        ASSERT(functionLength <= m_sourceLength);
    90123        SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
    91         const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
    92 
    93         auto validationResult = validateFunction(m_vm, functionStart, functionLength, signature, *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices);
     124        const Signature* signature = SignatureInformation::get(&m_vm, signatureIndex);
     125
     126        auto validationResult = validateFunction(&m_vm, functionStart, functionLength, signature, *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices);
    94127        if (!validationResult) {
    95128            if (verbose) {
     
    98131                dataLogLn();
    99132            }
    100             m_errorMessage = makeString(validationResult.error(), ", in function at index ", String::number(functionIndex)); // FIXME make this an Expected.
     133            fail(holdLock(m_lock), makeString(validationResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
    101134            return false;
    102135        }
     
    105138    if (verbose || Options::reportCompileTimes())
    106139        dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(), " us to validate module");
     140    if (m_asyncWork == Validation)
     141        complete(holdLock(m_lock));
     142    else
     143        moveToState(State::Validated);
    107144    return true;
    108145}
    109146
    110 // We are creating a bunch of threads that touch the main thread's stack. This will make ASAN unhappy.
    111 // The reason this is OK is that we guarantee that the main thread doesn't continue until all threads
    112 // that could touch its stack are done executing.
    113 SUPPRESS_ASAN
    114 void Plan::run(std::optional<MemoryMode> recompileMode)
    115 {
    116     if (!parseAndValidateModule(recompileMode))
    117         return;
     147void Plan::prepare()
     148{
     149    ASSERT(m_state == State::Validated);
     150    dataLogLnIf(verbose, "Starting preparation");
    118151
    119152    TraceScope traceScope(WebAssemblyCompileStart, WebAssemblyCompileEnd);
    120 
    121     if (recompileMode)
    122         ASSERT(m_moduleInformation->memory.mode() == recompileMode);
    123153
    124154    auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
     
    128158            builder.appendNumber(size);
    129159            builder.append(what);
    130             m_errorMessage = builder.toString();
     160            fail(holdLock(m_lock), builder.toString());
    131161            return false;
    132162        }
     
    149179            continue;
    150180        unsigned importFunctionIndex = m_wasmExitStubs.size();
    151         if (verbose)
    152             dataLogLn("Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
     181        dataLogLnIf(verbose, "Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
    153182        SignatureIndex signatureIndex = m_moduleInformation->importFunctionSignatureIndices.at(import->kindIndex);
    154         m_wasmExitStubs.uncheckedAppend(exitStubGenerator(m_vm, m_callLinkInfos, signatureIndex, importFunctionIndex));
    155     }
    156 
    157     m_currentIndex = 0;
    158 
    159     auto doWork = [this] {
    160         while (true) {
    161             uint32_t functionIndex;
     183        m_wasmExitStubs.uncheckedAppend(exitStubGenerator(&m_vm, m_callLinkInfos, signatureIndex, importFunctionIndex));
     184    }
     185
     186    moveToState(State::Prepared);
     187}
     188
     189// We don't have a semaphore class... and this does kinda interesting things.
     190class Plan::ThreadCountHolder {
     191public:
     192    ThreadCountHolder(Plan& plan)
     193        : m_plan(plan)
     194    {
     195        LockHolder locker(m_plan.m_lock);
     196        m_plan.m_numberOfActiveThreads++;
     197    }
     198
     199    ~ThreadCountHolder()
     200    {
     201        LockHolder locker(m_plan.m_lock);
     202        m_plan.m_numberOfActiveThreads--;
     203
     204        if (!m_plan.m_numberOfActiveThreads)
     205            m_plan.complete(locker);
     206    }
     207
     208    Plan& m_plan;
     209};
     210
     211void Plan::compileFunctions()
     212{
     213    ASSERT(m_state >= State::Prepared);
     214    dataLogLnIf(verbose, "Starting compilation");
     215
     216    if (m_state >= State::Compiled)
     217        return;
     218    ThreadCountHolder holder(*this);
     219    while (true) {
     220        uint32_t functionIndex;
     221        {
     222            auto locker = holdLock(m_lock);
     223            if (m_currentIndex >= m_functionLocationInBinary.size())
     224                return;
     225            functionIndex = m_currentIndex;
     226            ++m_currentIndex;
     227            if (m_currentIndex == m_functionLocationInBinary.size())
     228                moveToState(State::Compiled);
     229        }
     230
     231        const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
     232        size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
     233        ASSERT(functionLength <= m_sourceLength);
     234        SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
     235        const Signature* signature = SignatureInformation::get(&m_vm, signatureIndex);
     236        unsigned functionIndexSpace = m_wasmExitStubs.size() + functionIndex;
     237        ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex);
     238        ASSERT(validateFunction(&m_vm, functionStart, functionLength, signature, *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices));
     239
     240        m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
     241        auto parseAndCompileResult = parseAndCompile(m_vm, m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices, m_mode);
     242
     243        if (UNLIKELY(!parseAndCompileResult)) {
     244            auto locker = holdLock(m_lock);
     245            if (!m_errorMessage) {
     246                // Multiple compiles could fail simultaneously. We arbitrarily choose the first.
     247                fail(locker, makeString(parseAndCompileResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
     248            }
     249            m_currentIndex = m_functionLocationInBinary.size();
     250            return;
     251        }
     252
     253        m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
     254    }
     255}
     256
     257void Plan::complete(const AbstractLocker&)
     258{
     259    ASSERT(m_state != State::Compiled || m_currentIndex >= m_functionLocationInBinary.size());
     260    dataLogLnIf(verbose, "Starting Completion");
     261
     262    if (m_state == State::Compiled) {
     263        for (uint32_t functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); functionIndex++) {
    162264            {
    163                 auto locker = holdLock(m_lock);
    164                 if (m_currentIndex >= m_functionLocationInBinary.size())
    165                     return;
    166                 functionIndex = m_currentIndex;
    167                 ++m_currentIndex;
     265                CompilationContext& context = m_compilationContexts[functionIndex];
     266                SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
     267                String signatureDescription = SignatureInformation::get(&m_vm, signatureIndex)->toString();
     268                {
     269                    LinkBuffer linkBuffer(m_vm, *context.wasmEntrypointJIT, nullptr);
     270                    m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation =
     271                    std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("WebAssembly function[%i] %s", functionIndex, signatureDescription.ascii().data())), WTFMove(context.wasmEntrypointByproducts));
     272                }
     273
     274                {
     275                    LinkBuffer linkBuffer(m_vm, *context.jsEntrypointJIT, nullptr);
     276                    linkBuffer.link(context.jsEntrypointToWasmEntrypointCall, FunctionPtr(m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress()));
     277
     278                    m_wasmInternalFunctions[functionIndex]->jsToWasmEntrypoint.compilation =
     279                    std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("JavaScript->WebAssembly entrypoint[%i] %s", functionIndex, signatureDescription.ascii().data())), WTFMove(context.jsEntrypointByproducts));
     280                }
    168281            }
    169282
    170             const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
    171             size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
    172             ASSERT(functionLength <= m_sourceLength);
    173             SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
    174             const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
    175             unsigned functionIndexSpace = m_wasmExitStubs.size() + functionIndex;
    176             ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex);
    177             ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices));
    178 
    179             m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
    180             auto parseAndCompileResult = parseAndCompile(*m_vm, m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], *m_moduleInformation, m_moduleSignatureIndicesToUniquedSignatureIndices);
    181 
    182             if (UNLIKELY(!parseAndCompileResult)) {
    183                 auto locker = holdLock(m_lock);
    184                 if (!m_errorMessage) {
    185                     // Multiple compiles could fail simultaneously. We arbitrarily choose the first.
    186                     m_errorMessage = makeString(parseAndCompileResult.error(), ", in function at index ", String::number(functionIndex)); // FIXME make this an Expected.
    187                 }
    188                 m_currentIndex = m_functionLocationInBinary.size();
    189 
    190                 // We will terminate on the next execution.
    191                 continue;
    192             }
    193 
    194             m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
    195         }
    196     };
    197 
    198     MonotonicTime startTime;
    199     if (verbose || Options::reportCompileTimes())
    200         startTime = MonotonicTime::now();
    201 
    202     uint32_t threadCount = Options::useConcurrentJIT() ? WTF::numberOfProcessorCores() : 1;
    203     uint32_t numWorkerThreads = threadCount - 1;
    204     Vector<ThreadIdentifier> threads;
    205     threads.reserveCapacity(numWorkerThreads);
    206     for (uint32_t i = 0; i < numWorkerThreads; i++)
    207         threads.uncheckedAppend(createThread("jsc.wasm-b3-compilation.thread", doWork));
    208 
    209     doWork(); // Let the main thread do some work too.
    210 
    211     for (uint32_t i = 0; i < numWorkerThreads; i++)
    212         waitForThreadCompletion(threads[i]);
    213 
    214     for (uint32_t functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); functionIndex++) {
    215         {
    216             CompilationContext& context = m_compilationContexts[functionIndex];
    217             SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
    218             String signatureDescription = SignatureInformation::get(m_vm, signatureIndex)->toString();
    219             {
    220                 LinkBuffer linkBuffer(*m_vm, *context.wasmEntrypointJIT, nullptr);
    221                 m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation =
    222                     std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("WebAssembly function[%i] %s", functionIndex, signatureDescription.ascii().data())), WTFMove(context.wasmEntrypointByproducts));
    223             }
    224 
    225             {
    226                 LinkBuffer linkBuffer(*m_vm, *context.jsEntrypointJIT, nullptr);
    227                 linkBuffer.link(context.jsEntrypointToWasmEntrypointCall, FunctionPtr(m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress()));
    228 
    229                 m_wasmInternalFunctions[functionIndex]->jsToWasmEntrypoint.compilation =
    230                     std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("JavaScript->WebAssembly entrypoint[%i] %s", functionIndex, signatureDescription.ascii().data())), WTFMove(context.jsEntrypointByproducts));
    231             }
    232         }
    233     }
    234 
    235     if (verbose || Options::reportCompileTimes()) {
    236         dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(),
    237             " us to compile and link the module");
    238     }
    239 
    240     // Patch the call sites for each WebAssembly function.
    241     for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
    242         for (auto& call : unlinked) {
    243             void* executableAddress;
    244             if (m_moduleInformation->isImportedFunctionFromFunctionIndexSpace(call.functionIndex)) {
    245                 // FIXME imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT. https://bugs.webkit.org/show_bug.cgi?id=166462
    246                 executableAddress = call.target == UnlinkedWasmToWasmCall::Target::ToJs
     283        }
     284
     285        for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
     286            for (auto& call : unlinked) {
     287                void* executableAddress;
     288                if (m_moduleInformation->isImportedFunctionFromFunctionIndexSpace(call.functionIndex)) {
     289                    // FIXME imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT. https://bugs.webkit.org/show_bug.cgi?id=166462
     290                    executableAddress = call.target == UnlinkedWasmToWasmCall::Target::ToJs
    247291                    ? m_wasmExitStubs.at(call.functionIndex).wasmToJs.code().executableAddress()
    248292                    : m_wasmExitStubs.at(call.functionIndex).wasmToWasm.code().executableAddress();
    249             } else {
    250                 ASSERT(call.target != UnlinkedWasmToWasmCall::Target::ToJs);
    251                 executableAddress = m_wasmInternalFunctions.at(call.functionIndex - m_wasmExitStubs.size())->wasmEntrypoint.compilation->code().executableAddress();
     293                } else {
     294                    ASSERT(call.target != UnlinkedWasmToWasmCall::Target::ToJs);
     295                    executableAddress = m_wasmInternalFunctions.at(call.functionIndex - m_wasmExitStubs.size())->wasmEntrypoint.compilation->code().executableAddress();
     296                }
     297                MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(executableAddress));
    252298            }
    253             MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(executableAddress));
    254         }
    255     }
    256 
    257     m_failed = false;
    258 }
    259 
    260 void Plan::initializeCallees(JSGlobalObject* globalObject, std::function<void(unsigned, JSWebAssemblyCallee*, JSWebAssemblyCallee*)> callback)
    261 {
    262     ASSERT(!failed());
    263     for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
    264         WasmInternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
    265 
    266         JSWebAssemblyCallee* jsEntrypointCallee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->jsToWasmEntrypoint));
    267         MacroAssembler::repatchPointer(function->jsToWasmCalleeMoveLocation, jsEntrypointCallee);
    268 
    269         JSWebAssemblyCallee* wasmEntrypointCallee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->wasmEntrypoint));
    270         MacroAssembler::repatchPointer(function->wasmCalleeMoveLocation, wasmEntrypointCallee);
    271 
    272         callback(internalFunctionIndex, jsEntrypointCallee, wasmEntrypointCallee);
     299        }
     300    }
     301
     302    if (m_state != State::Completed) {
     303        moveToState(State::Completed);
     304        m_completionTask(*this);
     305        m_completed.notifyAll();
     306    }
     307}
     308
     309void Plan::waitForCompletion()
     310{
     311    LockHolder locker(m_lock);
     312    if (m_state != State::Completed) {
     313        // FIXME: We should have a wait conditionally so we don't have to hold the lock to complete / fail.
     314        m_completed.wait(m_lock);
     315    }
     316}
     317
     318void Plan::cancel()
     319{
     320    LockHolder locker(m_lock);
     321    if (m_state != State::Completed) {
     322        m_currentIndex = m_functionLocationInBinary.size();
     323        fail(locker, ASCIILiteral("WebAssembly Plan was canceled. If you see this error message please file a bug at bugs.webkit.org!"));
    273324    }
    274325}
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.h

    r214380 r214504  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4141class JSGlobalObject;
    4242class JSWebAssemblyCallee;
     43class JSPromiseDeferred;
    4344
    4445namespace Wasm {
    4546
    46 class Plan {
     47class Plan : public ThreadSafeRefCounted<Plan> {
    4748public:
    48     JS_EXPORT_PRIVATE Plan(VM*, Vector<uint8_t>);
    49     JS_EXPORT_PRIVATE Plan(VM*, const uint8_t*, size_t);
     49    static void dontFinalize(Plan&) { }
     50    typedef std::function<void(Plan&)> CompletionTask;
     51    enum AsyncWork : uint8_t { FullCompile, Validation };
     52    // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
     53    Plan(VM&, ArrayBuffer&, AsyncWork, CompletionTask&&);
     54    JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t>&, AsyncWork, CompletionTask&&);
     55    JS_EXPORT_PRIVATE Plan(VM&, const uint8_t*, size_t, AsyncWork, CompletionTask&&);
    5056    JS_EXPORT_PRIVATE ~Plan();
    5157
    52     bool parseAndValidateModule(std::optional<MemoryMode> = std::nullopt);
     58    bool parseAndValidateModule();
    5359
    54     JS_EXPORT_PRIVATE void run(std::optional<MemoryMode> = std::nullopt);
     60    JS_EXPORT_PRIVATE void prepare();
     61    void compileFunctions();
    5562
    56     JS_EXPORT_PRIVATE void initializeCallees(JSGlobalObject*, std::function<void(unsigned, JSWebAssemblyCallee*, JSWebAssemblyCallee*)>);
    57 
    58     bool WARN_UNUSED_RETURN failed() const { return m_failed; }
    59     const String& errorMessage() const
    60     {
    61         RELEASE_ASSERT(failed());
    62         return m_errorMessage;
    63     }
     63    template<typename Functor>
     64    void initializeCallees(const Functor&);
    6465
    6566    Vector<Export>& exports() const
    6667    {
    67         RELEASE_ASSERT(!failed());
     68        RELEASE_ASSERT(!failed() && !hasWork());
    6869        return m_moduleInformation->exports;
    6970    }
     
    7172    size_t internalFunctionCount() const
    7273    {
    73         RELEASE_ASSERT(!failed());
    74         return m_wasmInternalFunctions.size();
     74        RELEASE_ASSERT(!failed() && !hasWork());
     75        return m_functionLocationInBinary.size();
    7576    }
    7677
    7778    std::unique_ptr<ModuleInformation>&& takeModuleInformation()
    7879    {
    79         RELEASE_ASSERT(!failed());
     80        RELEASE_ASSERT(!failed() && !hasWork());
    8081        return WTFMove(m_moduleInformation);
    8182    }
     
    8384    Bag<CallLinkInfo>&& takeCallLinkInfos()
    8485    {
    85         RELEASE_ASSERT(!failed());
     86        RELEASE_ASSERT(!failed() && !hasWork());
    8687        return WTFMove(m_callLinkInfos);
    8788    }
     
    8990    Vector<WasmExitStubs>&& takeWasmExitStubs()
    9091    {
    91         RELEASE_ASSERT(!failed());
     92        RELEASE_ASSERT(!failed() && !hasWork());
    9293        return WTFMove(m_wasmExitStubs);
    9394    }
    9495
    95     MemoryMode mode() const { return m_moduleInformation->memory.mode(); }
     96    void setModeAndPromise(MemoryMode mode, JSPromiseDeferred* promise)
     97    {
     98        m_mode = mode;
     99        m_pendingPromise = promise;
     100    }
     101    MemoryMode mode() const { return m_mode; }
     102    JSPromiseDeferred* pendingPromise() { return m_pendingPromise; }
     103    VM& vm() const { return m_vm; }
     104
     105    enum class State : uint8_t {
     106        Initial,
     107        Validated,
     108        Prepared,
     109        Compiled,
     110        Completed // We should only move to Completed if we are holding the lock.
     111    };
     112
     113    const String& errorMessage() const { return m_errorMessage; }
     114
     115    bool WARN_UNUSED_RETURN failed() const { return !errorMessage().isNull(); }
     116    bool hasWork() const { return m_state < State::Compiled; }
     117    bool hasBeenPrepared() const { return m_state >= State::Prepared; }
     118
     119    void waitForCompletion();
     120    void cancel();
    96121
    97122private:
     123    class ThreadCountHolder;
     124    friend class ThreadCountHolder;
     125
     126    void complete(const AbstractLocker&);
     127
     128    void moveToState(State);
     129    void fail(const AbstractLocker&, String&& errorMessage);
     130
     131    const char* stateString(State);
     132
    98133    std::unique_ptr<ModuleInformation> m_moduleInformation;
    99134    Vector<FunctionLocationInBinary> m_functionLocationInBinary;
     
    104139    Vector<CompilationContext> m_compilationContexts;
    105140
    106     VM* m_vm;
     141    VM& m_vm;
     142    JSPromiseDeferred* m_pendingPromise { nullptr };
     143    CompletionTask m_completionTask;
     144
    107145    Vector<Vector<UnlinkedWasmToWasmCall>> m_unlinkedWasmToWasmCalls;
    108146    const uint8_t* m_source;
    109147    const size_t m_sourceLength;
    110     bool m_failed { true };
    111148    String m_errorMessage;
    112     uint32_t m_currentIndex;
     149    MemoryMode m_mode { MemoryMode::BoundsChecking };
    113150    Lock m_lock;
     151    Condition m_completed;
     152    State m_state { State::Initial };
     153    const AsyncWork m_asyncWork;
     154    uint8_t m_numberOfActiveThreads { 0 };
     155    uint32_t m_currentIndex { 0 };
    114156};
     157
    115158
    116159} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmPlanInlines.h

    r214502 r214504  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "B3Compilation.h"
    31 #include "CCallHelpers.h"
    32 #include "VM.h"
    33 #include "WasmFormat.h"
    34 #include <wtf/Expected.h>
    35 
    36 extern "C" void dumpProcedure(void*);
     30#include "JSWebAssemblyCallee.h"
     31#include "WasmPlan.h"
    3732
    3833namespace JSC { namespace Wasm {
    3934
    40 class MemoryInformation;
     35template<typename Functor>
     36void Plan::initializeCallees(const Functor& callback)
     37{
     38    ASSERT(!failed());
     39    for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
     40        WasmInternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
    4141
    42 struct CompilationContext {
    43     std::unique_ptr<CCallHelpers> jsEntrypointJIT;
    44     std::unique_ptr<B3::OpaqueByproducts> jsEntrypointByproducts;
    45     std::unique_ptr<CCallHelpers> wasmEntrypointJIT;
    46     std::unique_ptr<B3::OpaqueByproducts> wasmEntrypointByproducts;
    47     CCallHelpers::Call jsEntrypointToWasmEntrypointCall;
    48 };
     42        JSWebAssemblyCallee* jsEntrypointCallee = JSWebAssemblyCallee::create(m_vm, WTFMove(function->jsToWasmEntrypoint));
     43        MacroAssembler::repatchPointer(function->jsToWasmCalleeMoveLocation, jsEntrypointCallee);
    4944
    50 Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, const Vector<SignatureIndex>&, unsigned optLevel = 1);
     45        JSWebAssemblyCallee* wasmEntrypointCallee = JSWebAssemblyCallee::create(m_vm, WTFMove(function->wasmEntrypoint));
     46        MacroAssembler::repatchPointer(function->wasmCalleeMoveLocation, wasmEntrypointCallee);
     47
     48        callback(internalFunctionIndex, jsEntrypointCallee, wasmEntrypointCallee);
     49    }
     50}
    5151
    5252} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp

    r210229 r214504  
    272272            return { };
    273273
    274         WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), "branch to block on empty expression stack");
     274        WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), target.type() == BlockType::TopLevel ? "branch out of function" : "branch to block", " on empty expression stack, but expected ", target.signature());
    275275        WASM_VALIDATOR_FAIL_IF(target.signature() != expressionStack.last(), "branch's stack type doesn't match block's type");
    276276
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.h

    r209696 r214504  
    6161
    6262private:
    63     void finishCreation(VM&, Wasm::Entrypoint&&);
    64     JSWebAssemblyCallee(VM&);
     63    JS_EXPORT_PRIVATE void finishCreation(VM&, Wasm::Entrypoint&&);
     64    JS_EXPORT_PRIVATE JSWebAssemblyCallee(VM&);
    6565
    6666    Wasm::Entrypoint m_entrypoint;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp

    r214380 r214504  
    3030
    3131#include "JSCInlines.h"
     32#include "JSWebAssemblyLinkError.h"
    3233#include "JSWebAssemblyMemory.h"
    3334#include "JSWebAssemblyModule.h"
     35#include "WasmPlanInlines.h"
    3436
    3537namespace JSC {
     
    3739const ClassInfo JSWebAssemblyCodeBlock::s_info = { "WebAssemblyCodeBlock", nullptr, 0, CREATE_METHOD_TABLE(JSWebAssemblyCodeBlock) };
    3840
    39 JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock(VM& vm, JSWebAssemblyModule* owner, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, Wasm::MemoryMode mode, unsigned calleeCount)
     41JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock(VM& vm, JSWebAssemblyModule* owner,  Wasm::MemoryMode mode, Ref<Wasm::Plan>&& plan, unsigned calleeCount)
    4042    : Base(vm, vm.webAssemblyCodeBlockStructure.get())
    41     , m_callLinkInfos(WTFMove(callLinkInfos))
    42     , m_wasmExitStubs(WTFMove(wasmExitStubs))
     43    , m_plan(WTFMove(plan))
    4344    , m_mode(mode)
    4445    , m_calleeCount(calleeCount)
    4546{
    4647    m_module.set(vm, this, owner);
     48    ASSERT(!module()->codeBlock(mode));
     49    module()->setCodeBlock(vm, mode, this);
     50
    4751    memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>) * 2);
     52}
     53
     54void JSWebAssemblyCodeBlock::initialize()
     55{
     56    if (initialized())
     57        return;
     58
     59    VM& vm = plan().vm();
     60    ASSERT(vm.currentThreadIsHoldingAPILock());
     61    RELEASE_ASSERT(!plan().hasWork());
     62
     63    if (plan().failed()) {
     64        m_errorMessage = plan().errorMessage();
     65        m_plan = nullptr;
     66        return;
     67    }
     68
     69    RELEASE_ASSERT(plan().mode() == mode());
     70    ASSERT(plan().internalFunctionCount() == m_calleeCount);
     71
     72    m_callLinkInfos = plan().takeCallLinkInfos();
     73    m_wasmExitStubs = plan().takeWasmExitStubs();
     74
     75    plan().initializeCallees([&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
     76        setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);
     77        setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee);
     78    });
     79
     80    m_plan = nullptr;
    4881}
    4982
     
    5386}
    5487
    55 bool JSWebAssemblyCodeBlock::isSafeToRun(JSWebAssemblyMemory* memory)
     88bool JSWebAssemblyCodeBlock::isSafeToRun(JSWebAssemblyMemory* memory) const
    5689{
     90    if (!runnable())
     91        return false;
     92
    5793    Wasm::MemoryMode codeMode = mode();
    5894    Wasm::MemoryMode memoryMode = memory->memory().mode();
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h

    r214465 r214504  
    3030#include "JSCell.h"
    3131#include "JSWebAssemblyCallee.h"
     32#include "PromiseDeferredTimer.h"
    3233#include "UnconditionalFinalizer.h"
    3334#include "WasmFormat.h"
     
    4041class JSWebAssemblyMemory;
    4142
     43namespace Wasm {
     44class Plan;
     45}
     46
    4247class JSWebAssemblyCodeBlock : public JSCell {
    4348public:
     
    4550    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
    4651
    47     static JSWebAssemblyCodeBlock* create(VM& vm, JSWebAssemblyModule* owner, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& exitStubs, Wasm::MemoryMode mode, unsigned calleeCount)
     52    static JSWebAssemblyCodeBlock* create(VM& vm, JSWebAssemblyModule* owner, Wasm::MemoryMode mode, Ref<Wasm::Plan>&& plan, unsigned calleeCount)
    4853    {
    49         auto* result = new (NotNull, allocateCell<JSWebAssemblyCodeBlock>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyCodeBlock(vm, owner, std::forward<Bag<CallLinkInfo>>(callLinkInfos), std::forward<Vector<Wasm::WasmExitStubs>>(exitStubs), mode, calleeCount);
     54        auto* result = new (NotNull, allocateCell<JSWebAssemblyCodeBlock>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyCodeBlock(vm, owner, mode, WTFMove(plan), calleeCount);
    5055        result->finishCreation(vm);
    5156        return result;
     
    6065    Wasm::MemoryMode mode() const { return m_mode; }
    6166    JSWebAssemblyModule* module() const { return m_module.get(); }
    62     bool isSafeToRun(JSWebAssemblyMemory*);
     67
     68    // Don't call intialize directly, this should be called for you, as needed, by JSWebAssemblyInstance::finalizeCreation.
     69    void initialize();
     70    bool initialized() const { return !m_plan; }
     71
     72    Wasm::Plan& plan() const { ASSERT(!initialized()); return *m_plan; }
     73
     74    bool runnable() const { return initialized() && !m_errorMessage; }
     75    String& errorMessage() { ASSERT(!runnable()); return m_errorMessage; }
     76    bool isSafeToRun(JSWebAssemblyMemory*) const;
    6377
    6478    JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     
    90104    }
    91105
    92     WriteBarrier<JSWebAssemblyCallee>* callees()
    93     {
    94         return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
    95     }
     106    WriteBarrier<JSWebAssemblyCallee>* callees() { return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees()); }
    96107
    97108    void* wasmToJsCallStubForImport(unsigned importIndex)
     
    102113
    103114private:
    104     JSWebAssemblyCodeBlock(VM&, JSWebAssemblyModule*, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, Wasm::MemoryMode, unsigned calleeCount);
     115    JSWebAssemblyCodeBlock(VM&, JSWebAssemblyModule*, Wasm::MemoryMode, Ref<Wasm::Plan>&&, unsigned calleeCount);
    105116    DECLARE_EXPORT_INFO;
    106117    static const bool needsDestruction = true;
     
    126137    Bag<CallLinkInfo> m_callLinkInfos;
    127138    Vector<Wasm::WasmExitStubs> m_wasmExitStubs;
     139    // The plan that is compiling this code block.
     140    RefPtr<Wasm::Plan> m_plan;
     141    String m_errorMessage;
    128142    Wasm::MemoryMode m_mode;
    129143    unsigned m_calleeCount;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h

    r213745 r214504  
    7474}
    7575
     76ALWAYS_INLINE RefPtr<ArrayBuffer> createSourceBufferFromValue(VM& vm, ExecState* exec, JSValue value)
     77{
     78    auto throwScope = DECLARE_THROW_SCOPE(vm);
     79    size_t byteOffset;
     80    size_t byteSize;
     81    uint8_t* data = getWasmBufferFromValue(exec, value, byteOffset, byteSize);
     82    RETURN_IF_EXCEPTION(throwScope, nullptr);
     83
     84    auto buffer = ArrayBuffer::tryCreate(data + byteOffset, byteSize);
     85    if (buffer)
     86        return buffer;
     87
     88    throwException(exec, throwScope, createOutOfMemoryError(exec));
     89    return nullptr;
     90}
     91
    7692ALWAYS_INLINE bool isWebAssemblyHostFunction(VM& vm, JSObject* object, WebAssemblyFunction*& wasmFunction, WebAssemblyWrapperFunction*& wasmWrapperFunction)
    7793{
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r214498 r214504  
    3333#include "JSModuleEnvironment.h"
    3434#include "JSModuleNamespaceObject.h"
     35#include "JSWebAssemblyHelpers.h"
     36#include "JSWebAssemblyLinkError.h"
    3537#include "JSWebAssemblyMemory.h"
    3638#include "JSWebAssemblyModule.h"
     39#include "WebAssemblyModuleRecord.h"
    3740#include "WebAssemblyToJSCallee.h"
    3841#include <wtf/StdLibExtras.h>
     
    4043namespace JSC {
    4144
    42 void JSWebAssemblyInstance::setMemory(VM& vm, ExecState* exec, JSWebAssemblyMemory* memory)
    43 {
    44     auto scope = DECLARE_THROW_SCOPE(vm);
    45     // We create stub memories even for modules that should eventually get a memory so we want to avoid recompling there.
    46     if (memory->memory()) {
    47         auto codeBlock = m_codeBlock->module()->codeBlock(vm, exec, memory);
    48         RETURN_IF_EXCEPTION(scope,);
    49         m_codeBlock.set(vm, this, codeBlock);
    50     }
    51     m_memory.set(vm, this, memory);
    52 }
    53 
    54 JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
    55 {
    56     // FIXME: These objects could be pretty big we should try to throw OOM here.
    57     auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(module->moduleInformation().importFunctionSignatureIndices.size()))) JSWebAssemblyInstance(vm, structure, module->moduleInformation().importFunctionSignatureIndices.size());
    58     instance->finishCreation(vm, module, moduleNamespaceObject);
    59     return instance;
    60 }
     45const ClassInfo JSWebAssemblyInstance::s_info = { "WebAssembly.Instance", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyInstance) };
    6146
    6247Structure* JSWebAssemblyInstance::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     
    7762    ASSERT(inherits(vm, info()));
    7863
     64    m_module.set(vm, this, module);
    7965    const size_t extraMemorySize = module->moduleInformation().globals.size() * sizeof(Register);
    8066    m_globals = MallocPtr<uint64_t>::malloc(extraMemorySize);
    8167    heap()->reportExtraMemoryAllocated(extraMemorySize);
    8268
    83     m_codeBlock.set(vm, this, module->codeBlock());
    8469    m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
    8570    m_callee.set(vm, this, module->callee());
     
    9883
    9984    Base::visitChildren(thisObject, visitor);
     85    visitor.append(thisObject->m_module);
    10086    visitor.append(thisObject->m_codeBlock);
    10187    visitor.append(thisObject->m_moduleNamespaceObject);
     
    10591    visitor.reportExtraMemoryVisited(thisObject->module()->moduleInformation().globals.size());
    10692    for (unsigned i = 0; i < thisObject->m_numImportFunctions; ++i)
    107         visitor.append(*thisObject->importFunction(i));
    108 }
    109 
    110 const ClassInfo JSWebAssemblyInstance::s_info = { "WebAssembly.Instance", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyInstance) };
     93        visitor.append(thisObject->importFunctions()[i]);
     94}
     95
     96void JSWebAssemblyInstance::addUnitializedCodeBlock(VM& vm, Ref<Wasm::Plan> plan)
     97{
     98    auto* codeBlock = JSWebAssemblyCodeBlock::create(vm, module(), memoryMode(), WTFMove(plan), module()->moduleInformation().internalFunctionCount());
     99    m_codeBlock.set(vm, this, codeBlock);
     100    ASSERT(!codeBlock->initialized());
     101}
     102
     103void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec)
     104{
     105    auto scope = DECLARE_THROW_SCOPE(vm);
     106    codeBlock()->initialize();
     107
     108    if (!codeBlock()->runnable()) {
     109        throwException(exec, scope, JSWebAssemblyLinkError::create(exec, vm, globalObject()->WebAssemblyLinkErrorStructure(), codeBlock()->errorMessage()));
     110        return;
     111    }
     112    RELEASE_ASSERT(codeBlock()->isSafeToRun(memory()));
     113
     114    auto* moduleRecord = jsCast<WebAssemblyModuleRecord*>(m_moduleNamespaceObject->moduleRecord());
     115    moduleRecord->link(exec, module(), this);
     116    RETURN_IF_EXCEPTION(scope, void());
     117
     118    JSValue startResult = moduleRecord->evaluate(exec);
     119    UNUSED_PARAM(startResult);
     120    RETURN_IF_EXCEPTION(scope, void());
     121}
     122
     123JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure)
     124{
     125    auto throwScope = DECLARE_THROW_SCOPE(vm);
     126    auto* globalObject = exec->lexicalGlobalObject();
     127
     128    const Wasm::ModuleInformation& moduleInformation = jsModule->moduleInformation();
     129
     130    auto exception = [&] (JSObject* error) {
     131        throwException(exec, throwScope, error);
     132        return nullptr;
     133    };
     134
     135    // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
     136    if (moduleInformation.imports.size() && !importObject)
     137        return exception(createTypeError(exec, ASCIILiteral("can't make WebAssembly.Instance because there is no imports Object and the WebAssembly.Module requires imports")));
     138
     139    Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
     140    WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(exec, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, moduleInformation);
     141    RETURN_IF_EXCEPTION(throwScope, nullptr);
     142
     143    JSModuleNamespaceObject* moduleNamespace = moduleRecord->getModuleNamespace(exec);
     144    // FIXME: These objects could be pretty big we should try to throw OOM here.
     145    auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(moduleInformation.importFunctionCount()))) JSWebAssemblyInstance(vm, instanceStructure, moduleInformation.importFunctionCount());
     146    instance->finishCreation(vm, jsModule, moduleNamespace);
     147    RETURN_IF_EXCEPTION(throwScope, nullptr);
     148
     149    // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
     150    // Let imports be an initially-empty list of external values.
     151    unsigned numImportFunctions = 0;
     152    unsigned numImportGlobals = 0;
     153
     154    bool hasMemoryImport = false;
     155    bool hasTableImport = false;
     156    // For each import i in module.imports:
     157    for (auto& import : moduleInformation.imports) {
     158        // 1. Let o be the resultant value of performing Get(importObject, i.module_name).
     159        JSValue importModuleValue = importObject->get(exec, Identifier::fromString(&vm, import.module));
     160        RETURN_IF_EXCEPTION(throwScope, nullptr);
     161        // 2. If Type(o) is not Object, throw a TypeError.
     162        if (!importModuleValue.isObject())
     163            return exception(createTypeError(exec, ASCIILiteral("import must be an object"), defaultSourceAppender, runtimeTypeForValue(importModuleValue)));
     164
     165        // 3. Let v be the value of performing Get(o, i.item_name)
     166        JSObject* object = jsCast<JSObject*>(importModuleValue);
     167        JSValue value = object->get(exec, Identifier::fromString(&vm, import.field));
     168        RETURN_IF_EXCEPTION(throwScope, nullptr);
     169
     170        switch (import.kind) {
     171        case Wasm::ExternalKind::Function: {
     172            // 4. If i is a function import:
     173            // i. If IsCallable(v) is false, throw a WebAssembly.LinkError.
     174            if (!value.isFunction())
     175                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("import function must be callable")));
     176
     177            JSObject* function = jsCast<JSObject*>(value);
     178            // ii. If v is an Exported Function Exotic Object:
     179            WebAssemblyFunction* wasmFunction;
     180            WebAssemblyWrapperFunction* wasmWrapperFunction;
     181            if (isWebAssemblyHostFunction(vm, function, wasmFunction, wasmWrapperFunction)) {
     182                // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError.
     183                Wasm::SignatureIndex importedSignatureIndex;
     184                if (wasmFunction)
     185                    importedSignatureIndex = wasmFunction->signatureIndex();
     186                else {
     187                    importedSignatureIndex = wasmWrapperFunction->signatureIndex();
     188                    // b. Let closure be v.[[Closure]].
     189                    function = wasmWrapperFunction->function();
     190                }
     191                Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex];
     192                if (importedSignatureIndex != expectedSignatureIndex)
     193                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported function's signature doesn't match the provided WebAssembly function's signature")));
     194            }
     195            // iii. Otherwise:
     196            // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue.
     197            // Note: done as part of Plan compilation.
     198            // iv. Append v to funcs.
     199            // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction).
     200
     201            ASSERT(numImportFunctions == import.kindIndex);
     202            instance->importFunctions()[numImportFunctions++].set(vm, instance, function);
     203            // v. Append closure to imports.
     204            break;
     205        }
     206        case Wasm::ExternalKind::Table: {
     207            RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
     208            // 7. Otherwise (i is a table import):
     209            hasTableImport = true;
     210            JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
     211            // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
     212            if (!table)
     213                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import is not an instance of WebAssembly.Table")));
     214
     215            uint32_t expectedInitial = moduleInformation.tableInformation.initial();
     216            uint32_t actualInitial = table->size();
     217            if (actualInitial < expectedInitial)
     218                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import provided an 'initial' that is too small")));
     219
     220            if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
     221                std::optional<uint32_t> actualMaximum = table->maximum();
     222                if (!actualMaximum)
     223                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does")));
     224                if (*actualMaximum > *expectedMaximum)
     225                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'")));
     226            }
     227
     228            // ii. Append v to tables.
     229            // iii. Append v.[[Table]] to imports.
     230            instance->m_table.set(vm, instance, table);
     231            break;
     232        }
     233
     234        case Wasm::ExternalKind::Memory: {
     235            // 6. If i is a memory import:
     236            RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
     237            RELEASE_ASSERT(moduleInformation.memory);
     238            hasMemoryImport = true;
     239            JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value);
     240            // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError.
     241            if (!memory)
     242                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import is not an instance of WebAssembly.Memory")));
     243
     244            Wasm::PageCount declaredInitial = moduleInformation.memory.initial();
     245            Wasm::PageCount importedInitial = memory->memory().initial();
     246            if (importedInitial < declaredInitial)
     247                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size")));
     248
     249            if (Wasm::PageCount declaredMaximum = moduleInformation.memory.maximum()) {
     250                Wasm::PageCount importedMaximum = memory->memory().maximum();
     251                if (!importedMaximum)
     252                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import did not have a 'maximum' but the module requires that it does")));
     253
     254                if (importedMaximum > declaredMaximum)
     255                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided a 'maximum' that is larger than the module's declared 'maximum' import memory size")));
     256            }
     257
     258            // ii. Append v to memories.
     259            // iii. Append v.[[Memory]] to imports.
     260            ASSERT(!instance->m_memory);
     261            instance->m_memory.set(vm, instance, memory);
     262            RETURN_IF_EXCEPTION(throwScope, nullptr);
     263            break;
     264        }
     265        case Wasm::ExternalKind::Global: {
     266            // 5. If i is a global import:
     267            // i. If i is not an immutable global, throw a TypeError.
     268            ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
     269            // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
     270            if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
     271                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global cannot be an i64")));
     272            if (!value.isNumber())
     273                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global must be a number")));
     274            // iii. Append ToWebAssemblyValue(v) to imports.
     275            ASSERT(numImportGlobals == import.kindIndex);
     276            switch (moduleInformation.globals[import.kindIndex].type) {
     277            case Wasm::I32:
     278                instance->setGlobal(numImportGlobals++, value.toInt32(exec));
     279                break;
     280            case Wasm::F32:
     281                instance->setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec)));
     282                break;
     283            case Wasm::F64:
     284                instance->setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber()));
     285                break;
     286            default:
     287                RELEASE_ASSERT_NOT_REACHED();
     288            }
     289            ASSERT(!throwScope.exception());
     290            break;
     291        }
     292        }
     293    }
     294
     295    {
     296        if (!!moduleInformation.memory && moduleInformation.memory.isImport()) {
     297            // We should either have a Memory import or we should have thrown an exception.
     298            RELEASE_ASSERT(hasMemoryImport);
     299        }
     300
     301        if (moduleInformation.memory && !hasMemoryImport) {
     302            RELEASE_ASSERT(!moduleInformation.memory.isImport());
     303            // We create a memory when it's a memory definition.
     304            RefPtr<Wasm::Memory> memory = Wasm::Memory::create(vm, moduleInformation.memory.initial(), moduleInformation.memory.maximum());
     305            if (!memory)
     306                return exception(createOutOfMemoryError(exec));
     307
     308            instance->m_memory.set(vm, instance,
     309                JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), memory.releaseNonNull()));
     310            RETURN_IF_EXCEPTION(throwScope, nullptr);
     311        }
     312    }
     313
     314    {
     315        if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
     316            // We should either have a Table import or we should have thrown an exception.
     317            RELEASE_ASSERT(hasTableImport);
     318        }
     319
     320        if (!!moduleInformation.tableInformation && !hasTableImport) {
     321            RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
     322            // We create a Table when it's a Table definition.
     323            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(),
     324                moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
     325            // We should always be able to allocate a JSWebAssemblyTable we've defined.
     326            // If it's defined to be too large, we should have thrown a validation error.
     327            ASSERT(!throwScope.exception());
     328            ASSERT(table);
     329            instance->m_table.set(vm, instance, table);
     330        }
     331    }
     332   
     333    if (!instance->memory()) {
     334        // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
     335        instance->m_memory.set(vm, instance, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*(new Wasm::Memory()))));
     336    }
     337   
     338    // Globals
     339    {
     340        ASSERT(numImportGlobals == moduleInformation.firstInternalGlobal);
     341        for (size_t globalIndex = numImportGlobals; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
     342            const auto& global = moduleInformation.globals[globalIndex];
     343            ASSERT(global.initializationType != Wasm::Global::IsImport);
     344            if (global.initializationType == Wasm::Global::FromGlobalImport) {
     345                ASSERT(global.initialBitsOrImportNumber < numImportGlobals);
     346                instance->setGlobal(globalIndex, instance->loadI64Global(global.initialBitsOrImportNumber));
     347            } else
     348                instance->setGlobal(globalIndex, global.initialBitsOrImportNumber);
     349        }
     350    }
     351
     352    ASSERT(!instance->codeBlock());
     353    instance->m_codeBlock.setMayBeNull(vm, instance, jsModule->codeBlock(instance->memoryMode()));
     354
     355    return instance;
     356}
     357
    111358
    112359} // namespace JSC
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

    r214498 r214504  
    4040class WebAssemblyToJSCallee;
    4141
     42namespace Wasm {
     43class Plan;
     44}
     45
     46
    4247class JSWebAssemblyInstance : public JSDestructibleObject {
    4348public:
    4449    typedef JSDestructibleObject Base;
    4550
    46 
    47     static JSWebAssemblyInstance* create(VM&, Structure*, JSWebAssemblyModule*, JSModuleNamespaceObject*);
     51    static JSWebAssemblyInstance* create(VM&, ExecState*, JSWebAssemblyModule*, JSObject* importObject, Structure*);
    4852    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4953
    5054    DECLARE_INFO;
    5155
    52     JSWebAssemblyModule* module() const
    53     {
    54         ASSERT(m_codeBlock);
    55         return m_codeBlock->module();
    56     }
     56    JSWebAssemblyCodeBlock* codeBlock() const { return m_codeBlock.get(); }
     57    bool initialized() const { return codeBlock() && codeBlock()->initialized(); }
     58    void addUnitializedCodeBlock(VM&, Ref<Wasm::Plan>);
     59    void finalizeCreation(VM&, ExecState*);
    5760
    58     JSWebAssemblyCodeBlock* codeBlock() const
    59     {
    60         ASSERT(m_codeBlock);
    61         return m_codeBlock.get();
    62     }
     61    JSWebAssemblyModule* module() const { return m_module.get(); }
    6362
    64     WriteBarrier<JSObject>* importFunction(unsigned idx)
    65     {
    66         RELEASE_ASSERT(idx < m_numImportFunctions);
    67         return &importFunctions()[idx];
    68     }
    69 
    70     WriteBarrier<JSObject>* importFunctions()
    71     {
    72         return bitwise_cast<WriteBarrier<JSObject>*>(bitwise_cast<char*>(this) + offsetOfImportFunctions());
    73     }
    74 
    75     void setImportFunction(VM& vm, JSObject* value, unsigned idx)
    76     {
    77         importFunction(idx)->set(vm, this, value);
    78     }
     63    JSObject* importFunction(unsigned idx) { RELEASE_ASSERT(idx < m_numImportFunctions); return importFunctions()[idx].get(); }
    7964
    8065    JSWebAssemblyMemory* memory() { return m_memory.get(); }
    81     // Calling this might trigger a recompile.
    82     void setMemory(VM&, ExecState*, JSWebAssemblyMemory*);
     66    void setMemory(VM& vm, JSWebAssemblyMemory* value) { ASSERT(!memory()); m_memory.set(vm, this, value); }
    8367    Wasm::MemoryMode memoryMode() { return memory()->memory().mode(); }
    8468
    8569    JSWebAssemblyTable* table() { return m_table.get(); }
    86     void setTable(VM& vm, JSWebAssemblyTable* table) { m_table.set(vm, this, table); }
    8770
    8871    int32_t loadI32Global(unsigned i) const { return m_globals.get()[i]; }
     
    9174    double loadF64Global(unsigned i) const { return bitwise_cast<double>(loadI64Global(i)); }
    9275    void setGlobal(unsigned i, int64_t bits) { m_globals.get()[i] = bits; }
    93 
    94     static size_t offsetOfImportFunction(unsigned idx)
    95     {
    96         return offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * idx;
    97     }
    9876
    9977    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_memory); }
     
    11694
    11795private:
     96    WriteBarrier<JSObject>* importFunctions() { return bitwise_cast<WriteBarrier<JSObject>*>(bitwise_cast<char*>(this) + offsetOfImportFunctions()); }
     97
     98    WriteBarrier<JSWebAssemblyModule> m_module;
    11899    WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
    119100    WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

    r214498 r214504  
    4444const ClassInfo JSWebAssemblyModule::s_info = { "WebAssembly.Module", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyModule) };
    4545
    46 JSWebAssemblyCodeBlock* JSWebAssemblyModule::buildCodeBlock(VM& vm, ExecState* exec, Wasm::Plan& plan, std::optional<Wasm::MemoryMode> mode)
     46JSWebAssemblyModule* JSWebAssemblyModule::createStub(VM& vm, ExecState* exec, Structure* structure, RefPtr<ArrayBuffer>&& source, RefPtr<Wasm::Plan>&& plan)
    4747{
     48    ASSERT(!plan->hasWork());
    4849    auto scope = DECLARE_THROW_SCOPE(vm);
    49     // On failure, a new WebAssembly.CompileError is thrown.
    50     plan.run(mode);
    51     if (plan.failed()) {
    52         throwException(exec, scope, createJSWebAssemblyCompileError(exec, vm, plan.errorMessage()));
     50    if (plan->failed()) {
     51        throwException(exec, scope, JSWebAssemblyCompileError::create(exec, vm, structure->globalObject()->WebAssemblyCompileErrorStructure(), plan->errorMessage()));
    5352        return nullptr;
    5453    }
    55     if (mode)
    56         ASSERT(*mode == plan.mode());
    5754
    58     unsigned calleeCount = plan.internalFunctionCount();
    59     auto* codeBlock = JSWebAssemblyCodeBlock::create(vm, this, plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), plan.mode(), calleeCount);
    60 
    61     plan.initializeCallees(exec->jsCallee()->globalObject(),
    62         [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
    63             codeBlock->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);
    64             codeBlock->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee);
    65         });
    66     return codeBlock;
    67 }
    68 
    69 JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, ExecState* exec, Structure* structure, uint8_t* source, size_t byteSize)
    70 {
    71     auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure);
    72 
    73     instance->finishCreation(vm, exec, source, byteSize);
    74     return instance;
     55    auto* module = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure, WTFMove(source));
     56    module->finishCreation(vm, WTFMove(plan));
     57    return module;
    7558}
    7659
     
    8063}
    8164
    82 JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure)
     65JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, RefPtr<ArrayBuffer>&& source)
    8366    : Base(vm, structure)
     67    , m_sourceBuffer(source.releaseNonNull())
    8468{
    8569}
    8670
    87 JSWebAssemblyCodeBlock* JSWebAssemblyModule::codeBlock(VM& vm, ExecState* exec, JSWebAssemblyMemory* memory)
    88 {
    89     Wasm::MemoryMode mode = memory->memory().mode();
    90 
    91     for (unsigned i = 0; i < Wasm::NumberOfMemoryModes; ++i) {
    92         if (m_codeBlocks[i] && m_codeBlocks[i]->isSafeToRun(memory))
    93             return m_codeBlocks[i].get();
    94     }
    95 
    96     ASSERT(!codeBlockFor(mode));
    97     auto scope = DECLARE_THROW_SCOPE(vm);
    98     // We don't have a code block for this mode, we need to recompile...
    99     Wasm::Plan plan(&vm, static_cast<uint8_t*>(m_sourceBuffer->data()), m_sourceBuffer->byteLength());
    100 
    101     auto* codeBlock = buildCodeBlock(vm, exec, plan, mode);
    102     RETURN_IF_EXCEPTION(scope, nullptr);
    103 
    104     ASSERT(plan.exports().size() == m_exportSymbolTable->size());
    105     if (!ASSERT_DISABLED) {
    106         for (auto& exp : plan.exports())
    107             ASSERT_UNUSED(exp, m_exportSymbolTable->contains(exp.field.impl()));
    108     }
    109 
    110     ASSERT(mode == codeBlock->mode());
    111     codeBlockFor(mode).set(vm, this, codeBlock);
    112     return codeBlock;
    113 }
    114 
    115 void JSWebAssemblyModule::finishCreation(VM& vm, ExecState* exec, uint8_t* source, size_t byteSize)
     71void JSWebAssemblyModule::finishCreation(VM& vm, RefPtr<Wasm::Plan>&& plan)
    11672{
    11773    Base::finishCreation(vm);
    11874    ASSERT(inherits(vm, info()));
    11975
    120     auto scope = DECLARE_THROW_SCOPE(vm);
    121     Wasm::Plan plan(&vm, source, byteSize);
     76    std::unique_ptr<Wasm::ModuleInformation> moduleInformation = plan->takeModuleInformation();
     77    for (auto& exp : moduleInformation->exports) {
     78        ASSERT(exp.field.isSafeToSendToAnotherThread());
     79        exp.field = AtomicString(exp.field);
     80    }
     81    for (auto& imp : moduleInformation->imports) {
     82        ASSERT(imp.field.isSafeToSendToAnotherThread());
     83        imp.field = AtomicString(imp.field);
     84        ASSERT(imp.module.isSafeToSendToAnotherThread());
     85        imp.module = AtomicString(imp.module);
     86    }
    12287
    123     auto* codeBlock = buildCodeBlock(vm, exec, plan);
    124     RETURN_IF_EXCEPTION(scope,);
     88    m_moduleInformation = WTFMove(moduleInformation);
    12589
    12690    // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module.
    12791    SymbolTable* exportSymbolTable = SymbolTable::create(vm);
    128     for (auto& exp : plan.exports()) {
     92    for (auto& exp : m_moduleInformation->exports) {
    12993        auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary);
    130         exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset)));
     94        ASSERT(exp.field.impl()->isAtomic());
     95        exportSymbolTable->set(NoLockingNecessary, static_cast<AtomicStringImpl*>(exp.field.impl()), SymbolTableEntry(VarOffset(offset)));
    13196    }
    13297
    133     m_sourceBuffer = ArrayBuffer::create(source, byteSize);
    134     m_moduleInformation = plan.takeModuleInformation();
    13598    m_exportSymbolTable.set(vm, this, exportSymbolTable);
    13699    m_callee.set(vm, this, WebAssemblyToJSCallee::create(vm, vm.webAssemblyToJSCalleeStructure.get(), this));
    137     codeBlockFor(codeBlock->mode()).set(vm, this, codeBlock);
    138100}
    139101
     
    141103{
    142104    static_cast<JSWebAssemblyModule*>(cell)->JSWebAssemblyModule::~JSWebAssemblyModule();
     105}
     106
     107void JSWebAssemblyModule::setCodeBlock(VM& vm, Wasm::MemoryMode mode, JSWebAssemblyCodeBlock* codeBlock)
     108{
     109    m_codeBlocks[static_cast<size_t>(mode)].set(vm, this, codeBlock);
    143110}
    144111
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

    r214498 r214504  
    5050    typedef JSDestructibleObject Base;
    5151
    52     static JSWebAssemblyModule* create(VM&, ExecState*, Structure*, uint8_t* source, size_t byteSize);
     52    static JSWebAssemblyModule* createStub(VM&, ExecState*, Structure*, RefPtr<ArrayBuffer>&& source, RefPtr<Wasm::Plan>&&);
    5353    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    5454
     
    5656
    5757    const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
    58     RefPtr<Wasm::Memory> takeReservedMemory() { return m_moduleInformation->memory.takeReservedMemory(); }
    5958    SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
    6059    Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
     
    6463    WebAssemblyToJSCallee* callee() const { return m_callee.get(); }
    6564
    66     // Returns the code block that this module was originally compiled expecting to use. This won't need to recompile.
    67     JSWebAssemblyCodeBlock* codeBlock() { return codeBlockFor(m_moduleInformation->memory.mode()).get(); }
    68     // Returns the appropriate code block for the given memory, possibly triggering a recompile.
    69     JSWebAssemblyCodeBlock* codeBlock(VM&, ExecState*, JSWebAssemblyMemory*);
     65    JSWebAssemblyCodeBlock* codeBlock(Wasm::MemoryMode mode) { return m_codeBlocks[static_cast<size_t>(mode)].get(); }
     66
     67    ArrayBuffer& source() const { return m_sourceBuffer.get(); }
    7068
    7169private:
    72     WriteBarrier<JSWebAssemblyCodeBlock>& codeBlockFor(Wasm::MemoryMode mode) { return m_codeBlocks[static_cast<size_t>(mode)]; }
    73     JSWebAssemblyCodeBlock* buildCodeBlock(VM&, ExecState*, Wasm::Plan&, std::optional<Wasm::MemoryMode> mode = std::nullopt);
     70    friend class JSWebAssemblyCodeBlock;
    7471
    75     JSWebAssemblyModule(VM&, Structure*);
    76     void finishCreation(VM&, ExecState*, uint8_t* source, size_t byteSize);
     72    void setCodeBlock(VM&, Wasm::MemoryMode, JSWebAssemblyCodeBlock*);
     73
     74    JSWebAssemblyModule(VM&, Structure*, RefPtr<ArrayBuffer>&&);
     75    void finishCreation(VM&, RefPtr<Wasm::Plan>&&);
    7776    static void destroy(JSCell*);
    7877    static void visitChildren(JSCell*, SlotVisitor&);
    7978
    80     RefPtr<ArrayBuffer> m_sourceBuffer;
    81     std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
     79    Ref<ArrayBuffer> m_sourceBuffer;
     80    std::unique_ptr<const Wasm::ModuleInformation> m_moduleInformation;
    8281    WriteBarrier<SymbolTable> m_exportSymbolTable;
    8382    WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlocks[Wasm::NumberOfMemoryModes];
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

    r214438 r214504  
    3838#include "JSWebAssemblyMemory.h"
    3939#include "JSWebAssemblyModule.h"
     40#include "WasmPlan.h"
     41#include "WasmWorklist.h"
    4042#include "WebAssemblyFunction.h"
    4143#include "WebAssemblyInstancePrototype.h"
     
    4648namespace JSC {
    4749
    48 static const bool verbose = false;
    49 
    5050const ClassInfo WebAssemblyInstanceConstructor::s_info = { "Function", &Base::s_info, &constructorTableWebAssemblyInstance, CREATE_METHOD_TABLE(WebAssemblyInstanceConstructor) };
    5151
     
    5555 */
    5656
     57using Wasm::Plan;
     58
    5759static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* exec)
    5860{
    5961    auto& vm = exec->vm();
    60     auto throwScope = DECLARE_THROW_SCOPE(vm);
     62    auto scope = DECLARE_THROW_SCOPE(vm);
    6163
    6264    // If moduleObject is not a WebAssembly.Module instance, a TypeError is thrown.
    63     JSWebAssemblyModule* jsModule = jsDynamicCast<JSWebAssemblyModule*>(vm, exec->argument(0));
    64     if (!jsModule)
    65         return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("first argument to WebAssembly.Instance must be a WebAssembly.Module"), defaultSourceAppender, runtimeTypeForValue(exec->argument(0)))));
     65    JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, exec->argument(0));
     66    if (!module)
     67        return JSValue::encode(throwException(exec, scope, createTypeError(exec, ASCIILiteral("first argument to WebAssembly.Instance must be a WebAssembly.Module"), defaultSourceAppender, runtimeTypeForValue(exec->argument(0)))));
    6668
    6769    // If the importObject parameter is not undefined and Type(importObject) is not Object, a TypeError is thrown.
     
    6971    JSObject* importObject = importArgument.getObject();
    7072    if (!importArgument.isUndefined() && !importObject)
    71         return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("second argument to WebAssembly.Instance must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument))));
     73        return JSValue::encode(throwException(exec, scope, createTypeError(exec, ASCIILiteral("second argument to WebAssembly.Instance must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument))));
    7274   
    7375    Structure* instanceStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
    74     RETURN_IF_EXCEPTION(throwScope, { });
     76    RETURN_IF_EXCEPTION(scope, { });
    7577
    76     throwScope.release();
    77     return JSValue::encode(WebAssemblyInstanceConstructor::createInstance(exec, jsModule, importObject, instanceStructure));
    78 }
     78    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, instanceStructure);
     79    RETURN_IF_EXCEPTION(scope, { });
    7980
    80 JSWebAssemblyInstance* WebAssemblyInstanceConstructor::createInstance(ExecState* exec, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure)
    81 {
    82     auto& vm = exec->vm();
    83     auto throwScope = DECLARE_THROW_SCOPE(vm);
    84     auto* globalObject = exec->lexicalGlobalObject();
     81    // There are three possible cases:
     82    // 1) The instance already has an initialized CodeBlock (runnable), so we just need to finalizeCreation.
     83    // 2) The instance has no CodeBlock, so we need to make one and compile the code for it.
     84    // 3) The instance already has an uninitialized CodeBlock, so we need to wait for the compilation to finish.
    8585
    86     const Wasm::ModuleInformation& moduleInformation = jsModule->moduleInformation();
     86    if (!instance->initialized()) {
     87        if (instance->codeBlock())
     88            Wasm::ensureWorklist().completePlanSynchronously(instance->codeBlock()->plan());
     89        else {
     90            Ref<Wasm::Plan> plan = adoptRef(*new Plan(vm, module->source(), Plan::FullCompile, Plan::dontFinalize));
     91            plan->setModeAndPromise(instance->memoryMode(), nullptr);
     92            instance->addUnitializedCodeBlock(vm, plan.copyRef());
    8793
    88     auto exception = [&] (JSObject* error) {
    89         throwException(exec, throwScope, error);
    90         return nullptr;
    91     };
    92 
    93     // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
    94     if (moduleInformation.imports.size() && !importObject)
    95         return exception(createTypeError(exec, ASCIILiteral("can't make WebAssembly.Instance because there is no imports Object and the WebAssembly.Module requires imports")));
    96 
    97     Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
    98     WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(exec, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, moduleInformation);
    99     RETURN_IF_EXCEPTION(throwScope, nullptr);
    100 
    101 
    102     JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, instanceStructure, jsModule, moduleRecord->getModuleNamespace(exec));
    103     RETURN_IF_EXCEPTION(throwScope, nullptr);
    104 
    105     // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
    106     // Let imports be an initially-empty list of external values.
    107     unsigned numImportFunctions = 0;
    108     unsigned numImportGlobals = 0;
    109 
    110     bool hasMemoryImport = false;
    111     bool hasTableImport = false;
    112     // For each import i in module.imports:
    113     for (auto& import : moduleInformation.imports) {
    114         // 1. Let o be the resultant value of performing Get(importObject, i.module_name).
    115         JSValue importModuleValue = importObject->get(exec, import.module);
    116         RETURN_IF_EXCEPTION(throwScope, nullptr);
    117         // 2. If Type(o) is not Object, throw a TypeError.
    118         if (!importModuleValue.isObject())
    119             return exception(createTypeError(exec, ASCIILiteral("import must be an object"), defaultSourceAppender, runtimeTypeForValue(importModuleValue)));
    120 
    121         // 3. Let v be the value of performing Get(o, i.item_name)
    122         JSObject* object = jsCast<JSObject*>(importModuleValue);
    123         JSValue value = object->get(exec, import.field);
    124         RETURN_IF_EXCEPTION(throwScope, nullptr);
    125 
    126         switch (import.kind) {
    127         case Wasm::ExternalKind::Function: {
    128             // 4. If i is a function import:
    129             // i. If IsCallable(v) is false, throw a WebAssembly.LinkError.
    130             if (!value.isFunction())
    131                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("import function must be callable")));
    132 
    133             JSObject* function = jsCast<JSObject*>(value);
    134             // ii. If v is an Exported Function Exotic Object:
    135             WebAssemblyFunction* wasmFunction;
    136             WebAssemblyWrapperFunction* wasmWrapperFunction;
    137             if (isWebAssemblyHostFunction(vm, function, wasmFunction, wasmWrapperFunction)) {
    138                 // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError.
    139                 Wasm::SignatureIndex importedSignatureIndex;
    140                 if (wasmFunction)
    141                     importedSignatureIndex = wasmFunction->signatureIndex();
    142                 else {
    143                     importedSignatureIndex = wasmWrapperFunction->signatureIndex();
    144                     // b. Let closure be v.[[Closure]].
    145                     function = wasmWrapperFunction->function();
    146                 }
    147                 Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex];
    148                 if (importedSignatureIndex != expectedSignatureIndex)
    149                     return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported function's signature doesn't match the provided WebAssembly function's signature")));
    150             }
    151             // iii. Otherwise:
    152             // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue.
    153             // Note: done as part of Plan compilation.
    154             // iv. Append v to funcs.
    155             // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction).
    156 
    157             ASSERT(numImportFunctions == import.kindIndex);
    158             instance->setImportFunction(vm, function, numImportFunctions++);
    159             // v. Append closure to imports.
    160             break;
    161         }
    162         case Wasm::ExternalKind::Table: {
    163             RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
    164             // 7. Otherwise (i is a table import):
    165             hasTableImport = true;
    166             JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
    167             // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
    168             if (!table)
    169                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import is not an instance of WebAssembly.Table")));
    170 
    171             uint32_t declaredInitial = moduleInformation.tableInformation.initial();
    172             uint32_t importedInitial = table->size();
    173             if (importedInitial < declaredInitial)
    174                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import provided an 'initial' that is too small")));
    175 
    176             if (std::optional<uint32_t> declaredMaximum = moduleInformation.tableInformation.maximum()) {
    177                 std::optional<uint32_t> importedMaximum = table->maximum();
    178                 if (!importedMaximum)
    179                     return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does")));
    180                 if (*importedMaximum > *declaredMaximum)
    181                     return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'")));
    182             }
    183 
    184             // ii. Append v to tables.
    185             // iii. Append v.[[Table]] to imports.
    186             instance->setTable(vm, table);
    187             break;
    188         }
    189         case Wasm::ExternalKind::Memory: {
    190             // 6. If i is a memory import:
    191             RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
    192             RELEASE_ASSERT(moduleInformation.memory);
    193             hasMemoryImport = true;
    194             JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value);
    195             // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError.
    196             if (!memory)
    197                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import is not an instance of WebAssembly.Memory")));
    198 
    199             Wasm::PageCount declaredInitial = moduleInformation.memory.initial();
    200             Wasm::PageCount importedInitial = memory->memory().initial();
    201             if (importedInitial < declaredInitial)
    202                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size")));
    203 
    204             if (Wasm::PageCount declaredMaximum = moduleInformation.memory.maximum()) {
    205                 Wasm::PageCount importedMaximum = memory->memory().maximum();
    206                 if (!importedMaximum)
    207                     return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import did not have a 'maximum' but the module requires that it does")));
    208 
    209                 if (importedMaximum > declaredMaximum)
    210                     return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided a 'maximum' that is larger than the module's declared 'maximum' import memory size")));
    211             }
    212 
    213             // ii. Append v to memories.
    214             // iii. Append v.[[Memory]] to imports.
    215             instance->setMemory(vm, exec, memory);
    216             RETURN_IF_EXCEPTION(throwScope, nullptr);
    217             break;
    218         }
    219         case Wasm::ExternalKind::Global: {
    220             // 5. If i is a global import:
    221             // i. If i is not an immutable global, throw a TypeError.
    222             ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
    223             // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
    224             if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
    225                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global cannot be an i64")));
    226             if (!value.isNumber())
    227                 return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global must be a number")));
    228             // iii. Append ToWebAssemblyValue(v) to imports.
    229             ASSERT(numImportGlobals == import.kindIndex);
    230             switch (moduleInformation.globals[import.kindIndex].type) {
    231             case Wasm::I32:
    232                 instance->setGlobal(numImportGlobals++, value.toInt32(exec));
    233                 break;
    234             case Wasm::F32:
    235                 instance->setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec)));
    236                 break;
    237             case Wasm::F64:
    238                 instance->setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber()));
    239                 break;
    240             default:
    241                 RELEASE_ASSERT_NOT_REACHED();
    242             }
    243             ASSERT(!throwScope.exception());
    244             break;
    245         }
     94            auto& worklist = Wasm::ensureWorklist();
     95            worklist.enqueue(plan.copyRef());
     96            worklist.completePlanSynchronously(plan.get());
    24697        }
    24798    }
    24899
    249     {
    250         if (!!moduleInformation.memory && moduleInformation.memory.isImport()) {
    251             // We should either have a Memory import or we should have thrown an exception.
    252             RELEASE_ASSERT(hasMemoryImport);
    253         }
    254 
    255         if (moduleInformation.memory && !hasMemoryImport) {
    256             RELEASE_ASSERT(!moduleInformation.memory.isImport());
    257             // We create a memory when it's a memory definition.
    258             RefPtr<Wasm::Memory> memory;
    259             if (moduleInformation.memory.hasReservedMemory())
    260                 memory = jsModule->takeReservedMemory();
    261             else {
    262                 memory = Wasm::Memory::create(vm, moduleInformation.memory.initial(), moduleInformation.memory.maximum());
    263                 if (!memory)
    264                     return exception(createOutOfMemoryError(exec));
    265             }
    266             instance->setMemory(vm, exec,
    267                 JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), memory.releaseNonNull()));
    268             RETURN_IF_EXCEPTION(throwScope, nullptr);
    269         }
    270     }
    271 
    272     {
    273         if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
    274             // We should either have a Table import or we should have thrown an exception.
    275             RELEASE_ASSERT(hasTableImport);
    276         }
    277 
    278         if (!!moduleInformation.tableInformation && !hasTableImport) {
    279             RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
    280             // We create a Table when it's a Table definition.
    281             JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(),
    282                 moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
    283             // We should always be able to allocate a JSWebAssemblyTable we've defined.
    284             // If it's defined to be too large, we should have thrown a validation error.
    285             ASSERT(!throwScope.exception());
    286             ASSERT(table);
    287             instance->setTable(vm, table);
    288         }
    289     }
    290 
    291     if (!instance->memory()) {
    292         // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
    293         instance->setMemory(vm, exec, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*(new Wasm::Memory()))));
    294     }
    295 
    296     // Globals
    297     {
    298         ASSERT(numImportGlobals == moduleInformation.firstInternalGlobal);
    299         for (size_t globalIndex = numImportGlobals; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
    300             const auto& global = moduleInformation.globals[globalIndex];
    301             ASSERT(global.initializationType != Wasm::Global::IsImport);
    302             if (global.initializationType == Wasm::Global::FromGlobalImport) {
    303                 ASSERT(global.initialBitsOrImportNumber < numImportGlobals);
    304                 instance->setGlobal(globalIndex, instance->loadI64Global(global.initialBitsOrImportNumber));
    305             } else
    306                 instance->setGlobal(globalIndex, global.initialBitsOrImportNumber);
    307         }
    308     }
    309 
    310     moduleRecord->link(exec, instance);
    311     RETURN_IF_EXCEPTION(throwScope, nullptr);
    312 
    313     if (verbose)
    314         moduleRecord->dump();
    315     JSValue startResult = moduleRecord->evaluate(exec);
    316     UNUSED_PARAM(startResult);
    317     RETURN_IF_EXCEPTION(throwScope, nullptr);
    318 
    319     return instance;
     100    instance->finalizeCreation(vm, exec);
     101    RETURN_IF_EXCEPTION(scope, { });
     102    return JSValue::encode(instance);
    320103}
    321104
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

    r214261 r214504  
    7676    auto scope = DECLARE_THROW_SCOPE(vm);
    7777
    78     size_t byteOffset;
    79     size_t byteSize;
    80     uint8_t* base = getWasmBufferFromValue(exec, buffer, byteOffset, byteSize);
     78    RefPtr<ArrayBuffer> source = createSourceBufferFromValue(vm, exec, buffer);
    8179    RETURN_IF_EXCEPTION(scope, { });
    8280
    83     scope.release();
    84     return JSWebAssemblyModule::create(vm, exec, structure, base + byteOffset, byteSize);
     81    RefPtr<Wasm::Plan> plan = adoptRef(new Wasm::Plan(vm, *source, Wasm::Plan::Validation, Wasm::Plan::dontFinalize));
     82    if (!plan->parseAndValidateModule())
     83        return throwException(exec, scope, JSWebAssemblyCompileError::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyCompileErrorStructure(), plan->errorMessage()));
     84    return JSWebAssemblyModule::createStub(vm, exec, structure, WTFMove(source), WTFMove(plan));
    8585}
    8686
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModulePrototype.cpp

    r214484 r214504  
    111111            JSObject* obj = constructEmptyObject(exec);
    112112            RETURN_IF_EXCEPTION(throwScope, { });
    113             obj->putDirect(vm, module, jsString(exec, imp.module.string()));
    114             obj->putDirect(vm, name, jsString(exec, imp.field.string()));
     113            obj->putDirect(vm, module, jsString(exec, imp.module));
     114            obj->putDirect(vm, name, jsString(exec, imp.field));
    115115            obj->putDirect(vm, kind, jsString(exec, String(makeString(imp.kind))));
    116116            result->push(exec, obj);
     
    142142            JSObject* obj = constructEmptyObject(exec);
    143143            RETURN_IF_EXCEPTION(throwScope, { });
    144             obj->putDirect(vm, name, jsString(exec, exp.field.string()));
     144            obj->putDirect(vm, name, jsString(exec, exp.field));
    145145            obj->putDirect(vm, kind, jsString(exec, String(makeString(exp.kind))));
    146146            result->push(exec, obj);
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r214261 r214504  
    7474    Base::finishCreation(exec, vm);
    7575    ASSERT(inherits(vm, info()));
    76     for (const auto& exp : moduleInformation.exports)
    77         addExportEntry(ExportEntry::createLocal(exp.field, exp.field));
     76    for (const auto& exp : moduleInformation.exports) {
     77        Identifier field = Identifier::fromString(&vm, exp.field);
     78        addExportEntry(ExportEntry::createLocal(field, field));
     79    }
    7880}
    7981
     
    8688}
    8789
    88 void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyInstance* instance)
     90void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module, JSWebAssemblyInstance* instance)
    8991{
    9092    VM& vm = exec->vm();
     
    9395    auto* globalObject = exec->lexicalGlobalObject();
    9496
    95     JSWebAssemblyModule* module = instance->module();
    9697    JSWebAssemblyCodeBlock* codeBlock = instance->codeBlock();
    9798    const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
     
    113114            if (exp.kindIndex < functionImportCount) {
    114115                unsigned functionIndex = exp.kindIndex;
    115                 JSObject* functionImport = instance->importFunction(functionIndex)->get();
     116                JSObject* functionImport = instance->importFunction(functionIndex);
    116117                if (isWebAssemblyHostFunction(vm, functionImport))
    117118                    exportedValue = functionImport;
     
    129130                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
    130131                const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
    131                 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
     132                WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), exp.field, instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
    132133                exportedValue = function;
    133134            }
     
    180181        bool ignoreReadOnlyErrors = true;
    181182        bool putResult = false;
    182         symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, exp.field, exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
     183        symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromString(&vm, exp.field), exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
    183184        RELEASE_ASSERT(putResult);
    184185    }
     
    193194        ASSERT(signature->returnType() == Wasm::Void);
    194195        if (startFunctionIndexSpace < codeBlock->functionImportCount()) {
    195             JSObject* startFunction = instance->importFunction(startFunctionIndexSpace)->get();
     196            JSObject* startFunction = instance->importFunction(startFunctionIndexSpace);
    196197            m_startFunction.set(vm, this, startFunction);
    197198        } else {
     
    252253                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
    253254                if (functionIndex < codeBlock->functionImportCount()) {
    254                     JSObject* functionImport = jsCast<JSObject*>(m_instance->importFunction(functionIndex)->get());
     255                    JSObject* functionImport = jsCast<JSObject*>(m_instance->importFunction(functionIndex));
    255256                    if (isWebAssemblyHostFunction(vm, functionImport)) {
    256257                        WebAssemblyFunction* wasmFunction = jsDynamicCast<WebAssemblyFunction*>(vm, functionImport);
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.h

    r213745 r214504  
    3434
    3535class JSWebAssemblyInstance;
     36class JSWebAssemblyModule;
    3637class WebAssemblyFunction;
    3738
     
    4849    static WebAssemblyModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const Wasm::ModuleInformation&);
    4950
    50     void link(ExecState*, JSWebAssemblyInstance*);
     51    void link(ExecState*, JSWebAssemblyModule*, JSWebAssemblyInstance*);
    5152    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
    5253
Note: See TracChangeset for help on using the changeset viewer.