Bug 1612570 - Add promise support to worklet, r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D61406

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2020-02-06 13:54:19 +00:00
Родитель f41dda9dcc
Коммит c0a0edd822
6 изменённых файлов: 108 добавлений и 3 удалений

Просмотреть файл

@ -368,7 +368,9 @@ bool ExecutionRunnable::ParseAndLinkModule(
}
void ExecutionRunnable::RunOnWorkletThread() {
WorkletThread::EnsureCycleCollectedJSContext(mParentRuntime);
WorkletThread* workletThread =
static_cast<WorkletThread*>(NS_GetCurrentThread());
workletThread->EnsureCycleCollectedJSContext(mParentRuntime);
WorkletGlobalScope* globalScope = mWorkletImpl->GetGlobalScope();
MOZ_ASSERT(globalScope);

Просмотреть файл

@ -305,7 +305,33 @@ WorkletThread::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t aFlags) {
return NS_ERROR_NOT_IMPLEMENTED;
}
/* static */
static bool DispatchToEventLoop(void* aClosure,
JS::Dispatchable* aDispatchable) {
// This callback may execute either on the worklet thread or a random
// JS-internal helper thread.
// See comment at JS::InitDispatchToEventLoop() below for how we know the
// WorkletThread is alive.
WorkletThread* workletThread = reinterpret_cast<WorkletThread*>(aClosure);
nsresult rv = workletThread->DispatchRunnable(NS_NewRunnableFunction(
"WorkletThread::DispatchToEventLoop", [aDispatchable]() {
CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
if (!ccjscx) {
return;
}
WorkletJSContext* wjc = ccjscx->GetAsWorkletJSContext();
if (!wjc) {
return;
}
aDispatchable->run(wjc->Context(), JS::Dispatchable::NotShuttingDown);
}));
return NS_SUCCEEDED(rv);
}
void WorkletThread::EnsureCycleCollectedJSContext(JSRuntime* aParentRuntime) {
CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
if (ccjscx) {
@ -328,6 +354,11 @@ void WorkletThread::EnsureCycleCollectedJSContext(JSRuntime* aParentRuntime) {
// FIXME: JS::SetCTypesActivityCallback
// FIXME: JS_SetGCZeal
// A WorkletThread lives strictly longer than its JSRuntime so we can safely
// store a raw pointer as the callback's closure argument on the JSRuntime.
JS::InitDispatchToEventLoop(context->Context(), DispatchToEventLoop,
(void*)this);
JS_SetNativeStackQuota(context->Context(),
WORKLET_CONTEXT_NATIVE_STACK_LIMIT);

Просмотреть файл

@ -29,7 +29,7 @@ class WorkletThread final : public nsThread, public nsIObserver {
// Threads that call EnsureCycleCollectedJSContext must call
// DeleteCycleCollectedJSContext::Get() before terminating. Clients of
// Create() do not need to do this as Terminate() will ensure this happens.
static void EnsureCycleCollectedJSContext(JSRuntime* aParentRuntime);
void EnsureCycleCollectedJSContext(JSRuntime* aParentRuntime);
static void DeleteCycleCollectedJSContext();
static bool IsOnWorkletThread();

Просмотреть файл

@ -25,3 +25,5 @@ scheme = http
support-files=worklet_paintWorklet.js
[test_audioWorklet_WASM.html]
support-files=worklet_audioWorklet_WASM.js
[test_promise.html]
support-files=worklet_promise.js

Просмотреть файл

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for promise in worklet</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="common.js"></script>
</head>
<body>
<script type="application/javascript">
function configureTest() {
return SpecialPowers.pushPrefEnv(
{"set": [["dom.audioworklet.enabled", true],
["dom.worklet.enabled", true]]});
}
function runTestInIframe() {
if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) {
SimpleTest.finish();
return;
}
ok(window.isSecureContext, "Test should run in secure context");
var audioContext = new AudioContext();
ok(audioContext.audioWorklet instanceof AudioWorklet,
"AudioContext.audioWorklet should be an instance of AudioWorklet");
audioContext.audioWorklet.addModule("worklet_promise.js")
.then(() => {
const node = new AudioWorkletNode(audioContext, 'promise');
node.port.onmessage = e => {
ok(e.data instanceof WebAssembly.Module, "The WasmModule has been compiled into the worklet.");
SimpleTest.finish();
}
const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary);
const fooModuleCode = wasmTextToBinary(`(module
(func $foo (result i32) (i32.const 42))
(export "foo" $foo)
)`);
node.port.postMessage(fooModuleCode);
});
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,22 @@
class WasmProcessWorkletProcessor extends AudioWorkletProcessor {
constructor(...args) {
super(...args);
this.port.onmessage = e => {
WebAssembly.compile(e.data).then(
m => {
this.port.postMessage(m);
},
() => {
this.port.postMessage("error");
}
);
};
}
process(inputs, outputs, parameters) {
// Do nothing, output silence
return true;
}
}
registerProcessor("promise", WasmProcessWorkletProcessor);