already_AddRefed<Promise> PushManager::PerformSubscriptionActionFromWorker( SubscriptionAction aAction, ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope(); RefPtr<Promise> p = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p); if (!proxy) { p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR); return p.forget(); } RefPtr<GetSubscriptionRunnable> r = new GetSubscriptionRunnable(proxy, mScope, aAction); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return p.forget(); }
already_AddRefed<Promise> WorkerDataStore::GetLength(JSContext* aCx, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); RefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv); if (aRv.Failed()) { return nullptr; } RefPtr<DataStoreGetLengthRunnable> runnable = new DataStoreGetLengthRunnable(workerPrivate, mBackingStore, promise); runnable->Dispatch(aRv); if (aRv.Failed()) { return nullptr; } if (runnable->Failed()) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } return promise.forget(); }
static JSObject* GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, uint32_t aData, void* aClosure) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); if (aTag != WORKER_DATA_STORES_TAG) { MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!"); return nullptr; } NS_ASSERTION(!aData, "aData should be empty"); // Read the holder from the buffer, which points to the data store. nsMainThreadPtrHolder<DataStore>* dataStoreholder; if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) { MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!"); return nullptr; } // Protect workerStoreObj from moving GC during ~nsRefPtr. JS::Rooted<JSObject*> workerStoreObj(aCx, nullptr); { nsRefPtr<WorkerDataStore> workerStore = new WorkerDataStore(workerPrivate->GlobalScope()); nsMainThreadPtrHandle<DataStore> backingStore(dataStoreholder); // When we're on the worker thread, prepare a DataStoreChangeEventProxy. nsRefPtr<DataStoreChangeEventProxy> eventProxy = new DataStoreChangeEventProxy(workerPrivate, workerStore); // Add the DataStoreChangeEventProxy as an event listener on the main thread. nsRefPtr<DataStoreAddEventListenerRunnable> runnable = new DataStoreAddEventListenerRunnable(workerPrivate, backingStore, eventProxy); runnable->Dispatch(aCx); // Point WorkerDataStore to DataStore. workerStore->SetBackingDataStore(backingStore); JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); if (!global) { MOZ_ASSERT(false, "cannot get global!"); } else { workerStoreObj = workerStore->WrapObject(aCx); if (!JS_WrapObject(aCx, &workerStoreObj)) { MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!"); workerStoreObj = nullptr; } } } return workerStoreObj; }
already_AddRefed<Promise> WorkerDataStore::Remove(JSContext* aCx, const StringOrUnsignedLong& aId, const nsAString& aRevisionId, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); RefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv); if (aRv.Failed()) { return nullptr; } RefPtr<DataStoreRemoveRunnable> runnable = new DataStoreRemoveRunnable(workerPrivate, mBackingStore, promise, aId, aRevisionId); runnable->Dispatch(aRv); if (aRv.Failed()) { return nullptr; } if (runnable->Failed()) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } return promise.forget(); }
// This method sets the request's referrerURL, as specified by the "determine // request's referrer" steps from Referrer Policy [1]. // The actual referrer policy and stripping is dealt with by HttpBaseChannel, // this always sets the full API referrer URL of the relevant global if it is // not already a url or no-referrer. // [1]: https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer nsresult UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest) { nsAutoString originalReferrer; aRequest->GetReferrer(originalReferrer); // If it is no-referrer ("") or a URL, don't modify. if (!originalReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) { return NS_OK; } nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal); if (window) { nsCOMPtr<nsIDocument> doc = window->GetExtantDoc(); if (doc) { nsAutoString referrer; doc->GetReferrer(referrer); aRequest->SetReferrer(referrer); } } else { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); WorkerPrivate::LocationInfo& info = worker->GetLocationInfo(); aRequest->SetReferrer(NS_ConvertUTF8toUTF16(info.mHref)); } return NS_OK; }
already_AddRefed<Promise> ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); MOZ_ASSERT(global); RefPtr<Promise> promise = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } if (workerPrivate->GlobalScope()->WindowInteractionAllowed()) { RefPtr<PromiseWorkerProxy> promiseProxy = PromiseWorkerProxy::Create(workerPrivate, promise); if (promiseProxy) { RefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId, promiseProxy); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); } else { promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); } } else { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); } return promise.forget(); }
already_AddRefed<Promise> PushManager::PermissionState(ErrorResult& aRv) { if (mImpl) { MOZ_ASSERT(NS_IsMainThread()); return mImpl->PermissionState(aRv); } WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope(); RefPtr<Promise> p = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p); if (!proxy) { p->MaybeReject(worker->GetJSContext(), JS::UndefinedHandleValue); return p.forget(); } RefPtr<PermissionStateRunnable> r = new PermissionStateRunnable(proxy); NS_DispatchToMainThread(r); return p.forget(); }
already_AddRefed<Promise> WorkerDataStore::Add(JSContext* aCx, JS::Handle<JS::Value> aObj, const Optional<StringOrUnsignedLong>& aId, const nsAString& aRevisionId, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsRefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr<DataStoreAddRunnable> runnable = new DataStoreAddRunnable(workerPrivate, mBackingStore, promise, aCx, aObj, aId, aRevisionId, aRv); runnable->Dispatch(aCx); return promise.forget(); }
already_AddRefed<Promise> ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); MOZ_ASSERT(global); nsRefPtr<Promise> promise = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsRefPtr<PromiseWorkerProxy> promiseProxy = PromiseWorkerProxy::Create(workerPrivate, promise); if (!promiseProxy->GetWorkerPromise()) { // Don't dispatch if adding the worker feature failed. return promise.forget(); } nsRefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId, promiseProxy); aRv = NS_DispatchToMainThread(r); if (NS_WARN_IF(aRv.Failed())) { promise->MaybeReject(aRv); } return promise.forget(); }
already_AddRefed<WorkerDataStoreCursor> WorkerDataStore::Sync(JSContext* aCx, const nsAString& aRevisionId, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); // Create a WorkerDataStoreCursor on the worker. Note that we need to pass // this WorkerDataStore into the WorkerDataStoreCursor, so that it can keep // track of which WorkerDataStore owns the WorkerDataStoreCursor. RefPtr<WorkerDataStoreCursor> workerCursor = new WorkerDataStoreCursor(this); // DataStoreSyncStoreRunnable will point the WorkerDataStoreCursor to the // DataStoreCursor created on the main thread. RefPtr<DataStoreSyncStoreRunnable> runnable = new DataStoreSyncStoreRunnable(workerPrivate, mBackingStore, workerCursor, aRevisionId); runnable->Dispatch(aRv); if (aRv.Failed()) { return nullptr; } if (runnable->Failed()) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } return workerCursor.forget(); }
// static already_AddRefed<IDBOpenDBRequest> IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory, JS::Handle<JSObject*> aScriptOwner) { MOZ_ASSERT(aFactory); aFactory->AssertIsOnOwningThread(); MOZ_ASSERT(aScriptOwner); nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, nullptr); CaptureCaller(request->mFilename, &request->mLineNo); request->SetScriptOwner(aScriptOwner); if (!NS_IsMainThread()) { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); JSContext* cx = workerPrivate->GetJSContext(); MOZ_ASSERT(cx); nsAutoPtr<WorkerFeature> feature(new WorkerFeature(workerPrivate)); if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) { return nullptr; } request->mWorkerFeature = Move(feature); } return request.forget(); }
already_AddRefed<Promise> PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope(); RefPtr<Promise> p = Promise::Create(global, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p); if (!proxy) { p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE); return p.forget(); } RefPtr<UnsubscribeRunnable> r = new UnsubscribeRunnable(proxy, mScope); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return p.forget(); }
~WorkerFeature() { mWorkerPrivate->AssertIsOnWorkerThread(); MOZ_COUNT_DTOR(IDBOpenDBRequest::WorkerFeature); mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this); }
bool ServiceWorkerGlobalScope::OpenWindowEnabled(JSContext* aCx, JSObject* aObj) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); return worker->OpenWindowEnabled(); }
// static already_AddRefed<WorkerPushSubscription> WorkerPushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); nsRefPtr<WorkerPushSubscription> sub = new WorkerPushSubscription(aEndpoint, aScope); return sub.forget(); }
PushManager::PushManager(const nsAString& aScope) : mScope(aScope) { #ifdef DEBUG // There's only one global on a worker, so we don't need to pass a global // object to the constructor. WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); #endif }
Promise* PromiseWorkerProxy::WorkerPromise() const { #ifdef DEBUG WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); #endif MOZ_ASSERT(mWorkerPromise); return mWorkerPromise; }
already_AddRefed<WorkerDataStore> WorkerDataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv) { JSContext* cx = aGlobal.GetContext(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsRefPtr<WorkerDataStore> store = new WorkerDataStore(workerPrivate->GlobalScope()); return store.forget(); }
bool WorkerDataStore::GetReadOnly(JSContext* aCx, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsRefPtr<DataStoreGetReadOnlyRunnable> runnable = new DataStoreGetReadOnlyRunnable(workerPrivate, mBackingStore, aRv); runnable->Dispatch(aCx); return runnable->mReadOnly; }
already_AddRefed<URL> ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput, ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref); RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aInput, baseURL, aRv); if (NS_WARN_IF(aRv.Failed())) { aRv.ThrowTypeError<MSG_INVALID_URL>(aInput); } return url.forget(); }
void WorkerDataStore::GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); RefPtr<DataStoreGetStringRunnable> runnable = new DataStoreGetStringRunnable(workerPrivate, mBackingStore, &DataStore::GetOwner, aOwner); runnable->Dispatch(aRv); }
bool Dispatch(JSContext* aCx) { mWorkerPrivate->AssertIsOnWorkerThread(); mSyncQueueKey = mWorkerPrivate->CreateNewSyncLoop(); if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { JS_ReportError(aCx, "Failed to dispatch to main thread!"); mWorkerPrivate->StopSyncLoop(mSyncQueueKey, false); return false; } return mWorkerPrivate->RunSyncLoop(aCx, mSyncQueueKey); }
bool WorkerDataStore::GetReadOnly(JSContext* aCx, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); RefPtr<DataStoreGetReadOnlyRunnable> runnable = new DataStoreGetReadOnlyRunnable(workerPrivate, mBackingStore); runnable->Dispatch(aRv); if (aRv.Failed()) { return true; // To be safe, I guess. } return runnable->mReadOnly; }
void PromiseWorkerProxy::CleanProperties() { #ifdef DEBUG WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); #endif // Ok to do this unprotected from Create(). // CleanUp() holds the lock before calling this. mCleanedUp = true; mWorkerPromise = nullptr; mWorkerPrivate = nullptr; // Clear the StructuredCloneHolderBase class. Clear(); }
/* static */ bool BroadcastChannel::IsEnabled(JSContext* aCx, JSObject* aGlobal) { if (NS_IsMainThread()) { return Preferences::GetBool("dom.broadcastChannel.enabled", false); } WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsRefPtr<PrefEnabledRunnable> runnable = new PrefEnabledRunnable(workerPrivate); runnable->Dispatch(workerPrivate->GetJSContext()); return runnable->IsEnabled(); }
void ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, const Optional<Sequence<JS::Value>>& aTransferable, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence<JS::Value>& realTransferable = aTransferable.Value(); JS::HandleValueArray elements = JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), realTransferable.Elements()); JSObject* array = JS_NewArrayObject(aCx, elements); if (!array) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } transferable.setObject(*array); } const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false); WorkerStructuredCloneClosure closure; JSAutoStructuredCloneBuffer buffer; if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable = new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), closure); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_FAILURE); } }
already_AddRefed<Promise> WorkerNavigator::GetDataStores(JSContext* aCx, const nsAString& aName, const nsAString& aOwner, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsRefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr<NavigatorGetDataStoresRunnable> runnable = new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aOwner, aRv); runnable->Dispatch(aCx); return promise.forget(); }
already_AddRefed<Promise> ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); nsString scope; mWorkerScope->GetScope(scope); if (aOptions.mIncludeUncontrolled || aOptions.mType != ClientType::Window) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } nsRefPtr<Promise> promise = Promise::Create(mWorkerScope, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsRefPtr<PromiseWorkerProxy> promiseProxy = PromiseWorkerProxy::Create(workerPrivate, promise); if (!promiseProxy->GetWorkerPromise()) { // Don't dispatch if adding the worker feature failed. return promise.forget(); } nsRefPtr<MatchAllRunnable> r = new MatchAllRunnable(workerPrivate, promiseProxy, NS_ConvertUTF16toUTF8(scope)); nsresult rv = NS_DispatchToMainThread(r); if (NS_WARN_IF(NS_FAILED(rv))) { promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); } return promise.forget(); }
void ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, const Optional<Sequence<JS::Value>>& aTransferable, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence<JS::Value>& realTransferable = aTransferable.Value(); JS::HandleValueArray elements = JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), realTransferable.Elements()); JSObject* array = JS_NewArrayObject(aCx, elements); if (!array) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } transferable.setObject(*array); } RefPtr<ServiceWorkerClientPostMessageRunnable> runnable = new ServiceWorkerClientPostMessageRunnable(mWindowId); runnable->Write(aCx, aMessage, transferable, aRv); if (NS_WARN_IF(aRv.Failed())) { return; } aRv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(aRv.Failed())) { return; } }
already_AddRefed<Promise> WorkerDataStore::Put(JSContext* aCx, JS::Handle<JS::Value> aObj, const StringOrUnsignedLong& aId, const nsAString& aRevisionId, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); RefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv); if (aRv.Failed()) { return nullptr; } RefPtr<DataStorePutRunnable> runnable = new DataStorePutRunnable(workerPrivate, mBackingStore, promise, aId, aRevisionId); runnable->Write(aCx, aObj, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } runnable->Dispatch(aRv); if (aRv.Failed()) { return nullptr; } if (NS_FAILED(runnable->ErrorCode())) { aRv.Throw(runnable->ErrorCode()); return nullptr; } return promise.forget(); }