Bug 1247972 - specialize NS_ProxyRelease for nsISupports to be out-of-line; r=erahm

NS_ProxyRelease's current implementation requires a lot of code.  We can
reduce the impact of this by providing an out-of-line implementation for
classes based on nsISupports.  This change reduces codesize by ~60K on
a Linux x86-64 build.
This commit is contained in:
Aidin Gharibnavaz 2016-06-29 18:56:41 -04:00
parent 2ca762b096
commit 523608513b
7 changed files with 130 additions and 27 deletions

View File

@ -458,4 +458,13 @@ RasterImage::GetAnimationMode(uint16_t* aAnimationMode) {
} // namespace image
} // namespace mozilla
/**
* Casting RasterImage to nsISupports is ambiguous. This method handles that.
*/
inline nsISupports*
ToSupports(mozilla::image::RasterImage* p)
{
return NS_ISUPPORTS_CAST(mozilla::image::ImageResource*, p);
}
#endif /* mozilla_image_RasterImage_h */

View File

@ -111,4 +111,14 @@ private:
} // net namespace
} // mozilla namespace
/**
* Casting WebSocketEventService to nsISupports is ambiguous.
* This method handles that.
*/
inline nsISupports*
ToSupports(mozilla::net::WebSocketEventService* p)
{
return NS_ISUPPORTS_CAST(nsIWebSocketEventService*, p);
}
#endif // mozilla_net_WebSocketEventService_h

View File

@ -110,4 +110,14 @@ protected:
nsCOMPtr<nsISupports> mSecurityInfo;
};
/**
* Casting nsWyciwygChannel to nsISupports is ambiguous.
* This method handles that.
*/
inline nsISupports*
ToSupports(nsWyciwygChannel* p)
{
return NS_ISUPPORTS_CAST(nsIStreamListener*, p);
}
#endif /* nsWyciwygChannel_h___ */

View File

@ -413,4 +413,14 @@ private:
} // namespace storage
} // namespace mozilla
/**
* Casting Connection to nsISupports is ambiguous.
* This method handles that.
*/
inline nsISupports*
ToSupports(mozilla::storage::Connection* p)
{
return NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, p);
}
#endif // mozilla_storage_Connection_h

View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
namespace detail {
/* static */ void
ProxyReleaseChooser<true>::ProxyReleaseISupports(nsIEventTarget* aTarget,
nsISupports* aDoomed,
bool aAlwaysProxy)
{
::detail::ProxyRelease<nsISupports>(aTarget, dont_AddRef(aDoomed),
aAlwaysProxy);
}
} // namespace detail

View File

@ -15,17 +15,19 @@
#include "nsThreadUtils.h"
#include "mozilla/Likely.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#ifdef XPCOM_GLUE_AVOID_NSPR
#error NS_ProxyRelease implementation depends on NSPR.
#endif
namespace detail {
template<class T>
class nsProxyReleaseEvent : public mozilla::Runnable
template<typename T>
class ProxyReleaseEvent : public mozilla::Runnable
{
public:
explicit nsProxyReleaseEvent(already_AddRefed<T> aDoomed)
explicit ProxyReleaseEvent(already_AddRefed<T> aDoomed)
: mDoomed(aDoomed.take()) {}
NS_IMETHOD Run()
@ -38,6 +40,68 @@ private:
T* MOZ_OWNING_REF mDoomed;
};
template<typename T>
void
ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed, bool aAlwaysProxy)
{
// Auto-managing release of the pointer.
RefPtr<T> doomed = aDoomed;
nsresult rv;
if (!doomed || !aTarget) {
return;
}
if (!aAlwaysProxy) {
bool onCurrentThread = false;
rv = aTarget->IsOnCurrentThread(&onCurrentThread);
if (NS_SUCCEEDED(rv) && onCurrentThread) {
return;
}
}
nsCOMPtr<nsIRunnable> ev = new ProxyReleaseEvent<T>(doomed.forget());
rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("failed to post proxy release event, leaking!");
// It is better to leak the aDoomed object than risk crashing as
// a result of deleting it on the wrong thread.
}
}
template<bool nsISupportsBased>
struct ProxyReleaseChooser
{
template<typename T>
static void ProxyRelease(nsIEventTarget* aTarget,
already_AddRefed<T> aDoomed,
bool aAlwaysProxy)
{
::detail::ProxyRelease(aTarget, mozilla::Move(aDoomed), aAlwaysProxy);
}
};
template<>
struct ProxyReleaseChooser<true>
{
// We need an intermediate step for handling classes with ambiguous
// inheritance to nsISupports.
template<typename T>
static void ProxyRelease(nsIEventTarget* aTarget,
already_AddRefed<T> aDoomed,
bool aAlwaysProxy)
{
ProxyReleaseISupports(aTarget, ToSupports(aDoomed.take()), aAlwaysProxy);
}
static void ProxyReleaseISupports(nsIEventTarget* aTarget,
nsISupports* aDoomed,
bool aAlwaysProxy);
};
} // namespace detail
/**
* Ensures that the delete of a smart pointer occurs on the target thread.
*
@ -56,30 +120,8 @@ inline NS_HIDDEN_(void)
NS_ProxyRelease(nsIEventTarget* aTarget, already_AddRefed<T> aDoomed,
bool aAlwaysProxy = false)
{
// Auto-managing release of the pointer.
RefPtr<T> doomed = aDoomed;
nsresult rv;
if (!doomed || !aTarget) {
return;
}
if (!aAlwaysProxy) {
bool onCurrentThread = false;
rv = aTarget->IsOnCurrentThread(&onCurrentThread);
if (NS_SUCCEEDED(rv) && onCurrentThread) {
return;
}
}
nsCOMPtr<nsIRunnable> ev = new nsProxyReleaseEvent<T>(doomed.forget());
rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("failed to post proxy release event, leaking!");
// It is better to leak the aDoomed object than risk crashing as
// a result of deleting it on the wrong thread.
}
::detail::ProxyReleaseChooser<mozilla::IsBaseOf<nsISupports, T>::value>
::ProxyRelease(aTarget, mozilla::Move(aDoomed), aAlwaysProxy);
}
/**

View File

@ -39,6 +39,7 @@ xpcom_glue_src_cppsrcs = [
xpcom_gluens_src_lcppsrcs = [
'BlockingResourceBase.cpp',
'GenericFactory.cpp',
'nsProxyRelease.cpp',
'nsTextFormatter.cpp',
]