Avoid using strong reference in JSDOMPromise’s DeferredWrapper
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Aug 2016 18:36:46 +0000 (18:36 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Aug 2016 18:36:46 +0000 (18:36 +0000)
commit870a3f23dcfe0aa1a81de1ffbd71fd9a99207e54
tree50aad3004439e1e5f82232d859f8dfe60f98f404
parent146d5df09fc4055bcba6e15bc3e5fa75069baa4e
Avoid using strong reference in JSDOMPromise’s DeferredWrapper
https://bugs.webkit.org/show_bug.cgi?id=161426
<rdar://problem/28091123>

Reviewed by Geoffrey Garen.

Replace JSC::Strong in DeferredWrapper by JSC::Weak, and make the global object own JSPromiseDeferred.

DeferredWrapper adds itself to JSDOMGlobalObject's newly added HashSet when it's created and clears itself
from the HashSet inside its destructor as well as when the promise is resolved or rejected.
This is so that JSDOMGlobalObject's visitChildren can visit every live DeferredWrapper.

Because this operation is rather expense, this patch turns DeferredWrapper into a RefCounted object to avoid
HashMap churns. Most of code changes in this patch is due to this type change, and the fact lambda cannot
capture Ref<DeferredWrapper> since its copy constructor doesn't exist.

We also create a write barrier from the global object to JSPromiseDeferred so that they won't be collected
during an eden collection when it happens before JSDOMGlobalObject's visitChildren is invoked.

Note that it's possible for the entire DOM wrapper world of the promise to go away before the promise is
resolved or rejected by a ref-counted C++ object. In this case, m_deferred and m_globalObject become dead.
Various member resolve* and reject functions of DeferredWrapper have been modified to check this condition.

Because JSDOMGlobalObject can be finalized before DeferredWrapper is finalized. DeferredWrapper's destructor,
which calls DeferredWrapper::clear, should only remove itself from m_globalObject when m_globalObject is alive.

Finally, this patch makes DeferredWrapper inherit from ActiveDOMCallback so that it won't try to execute scripts
when the active DOM objects have been suspended; e.g. after a page navigation.

No new tests since there should be no author/user visible behavioral change.

* Modules/applepay/ApplePaySession.cpp:
(WebCore::ApplePaySession::canMakePaymentsWithActiveCard):
* Modules/applepay/ApplePaySession.h:
* Modules/fetch/DOMWindowFetch.cpp:
(WebCore::DOMWindowFetch::fetch):
* Modules/fetch/DOMWindowFetch.h:
* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::arrayBuffer):
(WebCore::FetchBody::blob):
(WebCore::FetchBody::json):
(WebCore::FetchBody::text):
(WebCore::FetchBody::consume):
(WebCore::FetchBody::consumeArrayBuffer):
(WebCore::FetchBody::consumeArrayBufferView):
(WebCore::FetchBody::consumeText):
(WebCore::FetchBody::consumeBlob):
(WebCore::FetchBody::loadingFailed):
(WebCore::FetchBody::loadingSucceeded):
* Modules/fetch/FetchBody.h:
(WebCore::FetchBody::formData):
(WebCore::FetchBody::cleanConsumePromise):
(WebCore::FetchBody): Use RefPtr<DeferredWrapper> instead of Optional<DeferredWrapper> now that DeferredWrapper
is ref counted. Perhaps we could use Optional<Ref<DeferredWrapper>> here but that seemed rather verbose.
* Modules/fetch/FetchBodyConsumer.cpp:
(WebCore::FetchBodyConsumer::resolveWithData):
(WebCore::FetchBodyConsumer::resolve):
* Modules/fetch/FetchBodyConsumer.h:
* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::arrayBuffer):
(WebCore::FetchBodyOwner::blob):
(WebCore::FetchBodyOwner::formData):
(WebCore::FetchBodyOwner::json):
(WebCore::FetchBodyOwner::text):
* Modules/fetch/FetchBodyOwner.h:
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::consume):
(WebCore::FetchResponse::finishConsumingStream):
* Modules/fetch/FetchResponse.h:
* Modules/fetch/WorkerGlobalScopeFetch.cpp:
(WebCore::WorkerGlobalScopeFetch::fetch):
* Modules/fetch/WorkerGlobalScopeFetch.h:
* Modules/mediastream/UserMediaPermissionCheck.h:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMGlobalObject.cpp:
(WebCore::JSDOMGlobalObject::~JSDOMGlobalObject): Added.
(WebCore::JSDOMGlobalObject::visitChildren): Added visits to each JSPromiseDeferred owned by this global object.
* bindings/js/JSDOMGlobalObject.h:
(WebCore::JSDOMGlobalObject::deferredWrappers): Added. This map is only used by JSDOMGlobalObject's visitChildren.
* bindings/js/JSDOMPromise.cpp:
(WebCore::DeferredWrapper::DeferredWrapper):
(WebCore::DeferredWrapper::~DeferredWrapper): Calls clear. When the global object has already been finalized,
m_globalObject is dead. In that case, there is no need to remove itself from the global object. When m_deferred
has been cleared, either clear() has already been called (1) or the callback is dead (2). Since (2) happens only
when the global object itself is dead (as its visitChildren would have visited m_deferred otherwise), again, there
is no need to remove itself from global object.
(WebCore::DeferredWrapper::clear): Added. Clears m_deferred and removes itself from JSDOMGlobalObject.
(WebCore::DeferredWrapper::contextDestroyed): ScriptExecutionContext has been destroyed. We must call clear().
(WebCore::DeferredWrapper::callFunction): Check canInvokeCallback in ActiveDOMCallback.
(WebCore::DeferredWrapper::reject): Exit early when isSuspended() is true. See below.
(WebCore::rejectPromiseWithExceptionIfAny):
(WebCore::fulfillPromiseWithJSON):
(WebCore::fulfillPromiseWithArrayBuffer):
* bindings/js/JSDOMPromise.h:
(WebCore::DeferredWrapper::create): Added.
(WebCore::DeferredWrapper::isSuspended): Added. Returns true iff the DOM wrapper world has gone away or active DOM
objects have been suspended.
(WebCore::DeferredWrapper::globalObject): Made this inline.
(WebCore::DeferredWrapper::visitAggregate): Added. Called by JSDOMGlobalObject::visitChildren.
(WebCore::DOMPromise::resolve):
(WebCore::DOMPromise::reject):
(WebCore::DeferredWrapper::resolveWithValue): Exit early when isSuspended() is true.
(WebCore::DeferredWrapper::resolveWithNewlyCreated): Ditto.
(WebCore::DeferredWrapper::rejectWithValue): Ditto.
(WebCore::DeferredWrapper::resolve): Ditto.
(WebCore::DeferredWrapper::reject): Ditto.
* bindings/js/JSFontFaceCustom.cpp:
(WebCore::JSFontFace::loaded):
* bindings/js/JSFontFaceSetCustom.cpp:
(WebCore::JSFontFaceSet::ready):
* bindings/js/JSMediaDevicesCustom.cpp:
(WebCore::JSMediaDevices::getUserMedia):
* bindings/js/JSReadableStreamSourceCustom.cpp:
(WebCore::JSReadableStreamSource::start):
* bindings/js/JSWebKitSubtleCryptoCustom.cpp:
(WebCore::JSWebKitSubtleCrypto::encrypt):
(WebCore::JSWebKitSubtleCrypto::decrypt):
(WebCore::JSWebKitSubtleCrypto::sign):
(WebCore::JSWebKitSubtleCrypto::verify):
(WebCore::JSWebKitSubtleCrypto::digest):
(WebCore::JSWebKitSubtleCrypto::generateKey):
(WebCore::JSWebKitSubtleCrypto::importKey):
(WebCore::JSWebKitSubtleCrypto::exportKey):
(WebCore::JSWebKitSubtleCrypto::wrapKey):
(WebCore::JSWebKitSubtleCrypto::unwrapKey):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateReturnParameters):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@205257 268f45cc-cd09-0410-ab3c-d52691b4dbfc
28 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/applepay/ApplePaySession.cpp
Source/WebCore/Modules/applepay/ApplePaySession.h
Source/WebCore/Modules/fetch/DOMWindowFetch.cpp
Source/WebCore/Modules/fetch/DOMWindowFetch.h
Source/WebCore/Modules/fetch/FetchBody.cpp
Source/WebCore/Modules/fetch/FetchBody.h
Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp
Source/WebCore/Modules/fetch/FetchBodyConsumer.h
Source/WebCore/Modules/fetch/FetchBodyOwner.cpp
Source/WebCore/Modules/fetch/FetchBodyOwner.h
Source/WebCore/Modules/fetch/FetchResponse.cpp
Source/WebCore/Modules/fetch/FetchResponse.h
Source/WebCore/Modules/fetch/WorkerGlobalScopeFetch.cpp
Source/WebCore/Modules/fetch/WorkerGlobalScopeFetch.h
Source/WebCore/Modules/mediastream/UserMediaPermissionCheck.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSDOMGlobalObject.cpp
Source/WebCore/bindings/js/JSDOMGlobalObject.h
Source/WebCore/bindings/js/JSDOMPromise.cpp
Source/WebCore/bindings/js/JSDOMPromise.h
Source/WebCore/bindings/js/JSFontFaceCustom.cpp
Source/WebCore/bindings/js/JSFontFaceSetCustom.cpp
Source/WebCore/bindings/js/JSMediaDevicesCustom.cpp
Source/WebCore/bindings/js/JSReadableStreamSourceCustom.cpp
Source/WebCore/bindings/js/JSWebKitSubtleCryptoCustom.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebKit2/CMakeLists.txt