gecko-dev/xpcom/base/nsCOMPtr.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1487 строки
46 KiB
C
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 15:12:37 +04:00
/* 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/. */
1998-12-17 22:12:45 +03:00
#ifndef nsCOMPtr_h___
#define nsCOMPtr_h___
/*
* Having problems?
*
* See the User Manual at:
* http://www.mozilla.org/projects/xpcom/nsCOMPtr.html
*
*
* nsCOMPtr
* better than a raw pointer
* for owning objects
* -- scc
*/
1998-12-17 22:12:45 +03:00
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
1998-12-17 22:12:45 +03:00
#include "nsDebug.h" // for |NS_ASSERTION|
#include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
#include "mozilla/RefPtr.h"
1998-12-17 22:12:45 +03:00
#include "nsCycleCollectionNoteChild.h"
/*
* WARNING: This file defines several macros for internal use only. These
* macros begin with the prefix |NSCAP_|. Do not use these macros in your own
* code. They are for internal use only for cross-platform compatibility, and
* are subject to change without notice.
*/
#ifdef _MSC_VER
// Under VC++, we win by inlining StartAssignment.
# define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
// Also under VC++, at the highest warning level, we are overwhelmed with
// warnings about (unused) inline functions being removed. This is to be
// expected with templates, so we disable the warning.
# pragma warning(disable : 4514)
1998-12-17 22:12:45 +03:00
#endif
#define NSCAP_FEATURE_USE_BASE
#ifdef DEBUG
1999-08-23 14:07:16 +04:00
# define NSCAP_FEATURE_TEST_DONTQUERY_CASES
# undef NSCAP_FEATURE_USE_BASE
#endif
#ifdef __GNUC__
// Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
// rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
// don't reorder instructions based on aliasing assumptions for
// this variable. Fortunately, gcc versions < 3.3 do not do any
// optimizations that break nsCOMPtr.
# define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
#else
# define NS_MAY_ALIAS_PTR(t) t*
#endif
#if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
# define NSCAP_FEATURE_USE_BASE
#endif
/*
* The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
* NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
* other interesting debug facilities. In fact, if you want |nsCOMPtr| to
* participate in the standard logging facility, you provide
* (e.g., in "nsISupportsImpl.h") suitable definitions
*
* #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
* #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
*/
#ifndef NSCAP_ADDREF
# define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
#endif
#ifndef NSCAP_RELEASE
# define NSCAP_RELEASE(this, ptr) (ptr)->Release()
#endif
// Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
#ifdef NSCAP_LOG_ASSIGNMENT
// Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
// know to instantiate |~nsGetterAddRefs| in turn to note the external
// assignment into the |nsCOMPtr|.
# define NSCAP_LOG_EXTERNAL_ASSIGNMENT
#else
// ...otherwise, just strip it out of the code
2003-02-25 18:53:36 +03:00
# define NSCAP_LOG_ASSIGNMENT(this, ptr)
#endif
#ifndef NSCAP_LOG_RELEASE
# define NSCAP_LOG_RELEASE(this, ptr)
#endif
namespace mozilla {
template <class T>
class OwningNonNull;
} // namespace mozilla
template <class T>
inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
return already_AddRefed<T>(aRawPtr);
}
template <class T>
inline already_AddRefed<T>&& dont_AddRef(
already_AddRefed<T>&& aAlreadyAddRefedPtr) {
return std::move(aAlreadyAddRefedPtr);
}
/*
* An nsCOMPtr_helper transforms commonly called getters into typesafe forms
* that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
* Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
*
* Here are the rules for a helper:
* - it implements |operator()| to produce an interface pointer
* - (except for its name) |operator()| is a valid [XP]COM `getter'
* - the interface pointer that it returns is already |AddRef()|ed (as from
* any good getter)
* - it matches the type requested with the supplied |nsIID| argument
* - its constructor provides an optional |nsresult*| that |operator()| can
* fill in with an error when it is executed
*
* See |class nsGetInterface| for an example.
*/
class MOZ_STACK_CLASS nsCOMPtr_helper {
public:
virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const = 0;
};
/*
* nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
* adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
* often enough that the codesize savings are big enough to warrant the
* specialcasing.
*/
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
class MOZ_STACK_CLASS nsQueryInterfaceISupports {
public:
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
private:
nsISupports* MOZ_OWNING_REF mRawPtr;
};
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
#ifndef NSCAP_FEATURE_USE_BASE
template <typename T>
class MOZ_STACK_CLASS nsQueryInterface final
: public nsQueryInterfaceISupports {
public:
explicit nsQueryInterface(T* aRawPtr)
: nsQueryInterfaceISupports(ToSupports(aRawPtr)) {}
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
return nsQueryInterfaceISupports::operator()(aIID, aAnswer);
}
};
#endif // #ifndef NSCAP_FEATURE_USE_BASE
class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError {
public:
nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
: mRawPtr(aRawPtr), mErrorPtr(aError) {}
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
private:
nsISupports* MOZ_OWNING_REF mRawPtr;
nsresult* mErrorPtr;
};
1999-02-17 04:58:25 +03:00
#ifndef NSCAP_FEATURE_USE_BASE
template <typename T>
class MOZ_STACK_CLASS nsQueryInterfaceWithError final
: public nsQueryInterfaceISupportsWithError {
public:
explicit nsQueryInterfaceWithError(T* aRawPtr, nsresult* aError)
: nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr), aError) {}
nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
return nsQueryInterfaceISupportsWithError::operator()(aIID, aAnswer);
}
};
#endif // #ifndef NSCAP_FEATURE_USE_BASE
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
namespace mozilla {
// PointedToType<> is needed so that do_QueryInterface() will work with a
// variety of smart pointer types in addition to raw pointers. These types
// include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
template <class T>
using PointedToType =
typename mozilla::RemovePointer<decltype(&*mozilla::DeclVal<T>())>::Type;
} // namespace mozilla
#ifdef NSCAP_FEATURE_USE_BASE
template <class T>
inline nsQueryInterfaceISupports do_QueryInterface(T aPtr) {
return nsQueryInterfaceISupports(
ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)));
}
template <class T>
inline nsQueryInterfaceISupportsWithError do_QueryInterface(T aPtr,
nsresult* aError) {
return nsQueryInterfaceISupportsWithError(
ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)), aError);
}
#else
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
template <class T>
inline nsQueryInterface<mozilla::PointedToType<T> > do_QueryInterface(T aPtr) {
return nsQueryInterface<mozilla::PointedToType<T> >(aPtr);
}
template <class T>
inline nsQueryInterfaceWithError<mozilla::PointedToType<T> > do_QueryInterface(
T aRawPtr, nsresult* aError) {
return nsQueryInterfaceWithError<mozilla::PointedToType<T> >(aRawPtr, aError);
}
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
template <class T>
inline void do_QueryInterface(already_AddRefed<T>&) {
// This signature exists solely to _stop_ you from doing the bad thing.
// Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
// someone else is an automatic leak. See bug 8221.
}
template <class T>
inline void do_QueryInterface(already_AddRefed<T>&, nsresult*) {
// This signature exists solely to _stop_ you from doing the bad thing.
// Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
// someone else is an automatic leak. See bug 8221.
}
////////////////////////////////////////////////////////////////////////////
// Using servicemanager with COMPtrs
class nsGetServiceByCID final {
public:
explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
private:
const nsCID& mCID;
};
class nsGetServiceByCIDWithError final {
public:
nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
: mCID(aCID), mErrorPtr(aErrorPtr) {}
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
private:
const nsCID& mCID;
nsresult* mErrorPtr;
};
class nsGetServiceByContractID final {
public:
explicit nsGetServiceByContractID(const char* aContractID)
: mContractID(aContractID) {}
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
private:
const char* mContractID;
};
class nsGetServiceByContractIDWithError final {
public:
nsGetServiceByContractIDWithError(const char* aContractID,
nsresult* aErrorPtr)
: mContractID(aContractID), mErrorPtr(aErrorPtr) {}
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
private:
const char* mContractID;
nsresult* mErrorPtr;
};
class nsIWeakReference;
// Weak references
class MOZ_STACK_CLASS nsQueryReferent final {
public:
nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
: mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
private:
nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
nsresult* mErrorPtr;
};
/**
* Factors implementation for all template versions of nsCOMPtr.
*
* Here's the way people normally do things like this:
*
* template<class T> class Foo { ... };
* template<> class Foo<void*> { ... };
* template<class T> class Foo<T*> : private Foo<void*> { ... };
*/
class nsCOMPtr_base {
public:
explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base() {
NSCAP_LOG_RELEASE(this, mRawPtr);
if (mRawPtr) {
NSCAP_RELEASE(this, mRawPtr);
}
}
void NS_FASTCALL assign_with_AddRef(nsISupports*);
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
void NS_FASTCALL assign_from_qi(const nsQueryInterfaceISupports,
const nsIID&);
void NS_FASTCALL assign_from_qi_with_error(
const nsQueryInterfaceISupportsWithError&, const nsIID&);
void NS_FASTCALL assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
void NS_FASTCALL assign_from_gs_cid_with_error(
const nsGetServiceByCIDWithError&, const nsIID&);
void NS_FASTCALL assign_from_gs_contractid(const nsGetServiceByContractID,
const nsIID&);
void NS_FASTCALL assign_from_gs_contractid_with_error(
const nsGetServiceByContractIDWithError&, const nsIID&);
void NS_FASTCALL assign_from_query_referent(const nsQueryReferent&,
const nsIID&);
void NS_FASTCALL assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
void** NS_FASTCALL begin_assignment();
protected:
NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
void assign_assuming_AddRef(nsISupports* aNewPtr) {
// |AddRef()|ing the new value (before entering this function) before
// |Release()|ing the old lets us safely ignore the self-assignment case.
// We must, however, be careful only to |Release()| _after_ doing the
// assignment, in case the |Release()| leads to our _own_ destruction,
// which would, in turn, cause an incorrect second |Release()| of our old
// pointer. Thank <waterson@netscape.com> for discovering this.
nsISupports* oldPtr = mRawPtr;
mRawPtr = aNewPtr;
NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
NSCAP_LOG_RELEASE(this, oldPtr);
if (oldPtr) {
NSCAP_RELEASE(this, oldPtr);
}
}
};
// template<class T> class nsGetterAddRefs;
// Helper for assert_validity method
template <class T>
char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
template <class T>
char TestForIID(...);
template <class T>
class MOZ_IS_REFPTR nsCOMPtr final
#ifdef NSCAP_FEATURE_USE_BASE
: private nsCOMPtr_base
#endif
{
private:
#ifdef NSCAP_FEATURE_USE_BASE
# define NSCAP_CTOR_BASE(x) nsCOMPtr_base(ToSupports(x))
void assign_assuming_AddRef(T* aNewPtr) {
nsCOMPtr_base::assign_assuming_AddRef(ToSupports(aNewPtr));
}
#else
# define NSCAP_CTOR_BASE(x) mRawPtr(x)
void assign_with_AddRef(nsISupports*);
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
template <typename U>
void assign_from_qi(const nsQueryInterface<U>, const nsIID&);
template <typename U>
void assign_from_qi_with_error(const nsQueryInterfaceWithError<U>&,
const nsIID&);
void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
const nsIID&);
void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
void assign_from_gs_contractid_with_error(
const nsGetServiceByContractIDWithError&, const nsIID&);
void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
void** begin_assignment();
void assign_assuming_AddRef(T* aNewPtr) {
T* oldPtr = mRawPtr;
mRawPtr = aNewPtr;
NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
NSCAP_LOG_RELEASE(this, oldPtr);
if (oldPtr) {
NSCAP_RELEASE(this, oldPtr);
}
}
private:
T* MOZ_OWNING_REF mRawPtr;
#endif
void assert_validity() {
static_assert(1 < sizeof(TestForIID<T>(nullptr)),
"nsCOMPtr only works "
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
"for types with IIDs. Either use RefPtr; add an IID to "
"your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
"NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
"to a base class with an IID.");
}
public:
typedef T element_type;
#ifndef NSCAP_FEATURE_USE_BASE
~nsCOMPtr() {
NSCAP_LOG_RELEASE(this, mRawPtr);
if (mRawPtr) {
NSCAP_RELEASE(this, mRawPtr);
}
}
1999-05-11 00:48:43 +04:00
#endif
#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
void Assert_NoQueryNeeded() {
if (mRawPtr) {
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
// This can't be defined in terms of do_QueryInterface because
// that bans casts from a class to itself.
void* out = nullptr;
mRawPtr->QueryInterface(NS_GET_TEMPLATE_IID(T), &out);
T* query_result = static_cast<T*>(out);
MOZ_ASSERT(query_result == mRawPtr, "QueryInterface needed");
NS_RELEASE(query_result);
}
}
1999-08-23 14:07:16 +04:00
# define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
#else
# define NSCAP_ASSERT_NO_QUERY_NEEDED()
#endif
// Constructors
nsCOMPtr() : NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
}
MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
}
nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
assert_validity();
if (mRawPtr) {
NSCAP_ADDREF(this, mRawPtr);
}
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
}
template <class U>
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
: NSCAP_CTOR_BASE(aSmartPtr.get()) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value,
"U should be a subclass of T");
assert_validity();
if (mRawPtr) {
NSCAP_ADDREF(this, mRawPtr);
}
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get());
}
nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
assert_validity();
aSmartPtr.mRawPtr = nullptr;
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
}
template <class U>
MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
: NSCAP_CTOR_BASE(aSmartPtr.forget().template downcast<T>().take()) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value,
"U should be a subclass of T");
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : NSCAP_CTOR_BASE(aRawPtr) {
assert_validity();
if (mRawPtr) {
NSCAP_ADDREF(this, mRawPtr);
}
NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
: NSCAP_CTOR_BASE(aSmartPtr.take()) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
1998-12-17 22:12:45 +03:00
// Construct from |otherComPtr.forget()|.
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
: NSCAP_CTOR_BASE(aSmartPtr.take()) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
// Construct from |already_AddRefed|.
template <typename U>
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
: NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
assert_validity();
// But make sure that U actually inherits from T.
static_assert(mozilla::IsBaseOf<T, U>::value, "U is not a subclass of T");
NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
// Construct from |otherComPtr.forget()|.
template <typename U>
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
: NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
assert_validity();
// But make sure that U actually inherits from T.
static_assert(mozilla::IsBaseOf<T, U>::value, "U is not a subclass of T");
NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
NSCAP_ASSERT_NO_QUERY_NEEDED();
1999-08-23 14:07:16 +04:00
}
// Construct from |do_QueryInterface(expr)|.
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
#ifdef NSCAP_FEATURE_USE_BASE
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
#else
template <typename U>
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI)
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_QueryInterface(expr, &rv)|.
#ifdef NSCAP_FEATURE_USE_BASE
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
#else
template <typename U>
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_GetService(cid_expr)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_GetService(cid_expr, &rv)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_GetService(contractid_expr)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_GetService(contractid_expr, &rv)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
}
// Construct from |do_QueryReferent(ptr)|
MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
}
// And finally, anything else we might need to construct from can exploit the
// nsCOMPtr_helper facility.
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
: NSCAP_CTOR_BASE(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
// Defined in OwningNonNull.h
template <class U>
MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
// Assignment operators
nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
assign_with_AddRef(ToSupports(aRhs.mRawPtr));
return *this;
}
template <class U>
nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value,
"U should be a subclass of T");
assign_with_AddRef(ToSupports(static_cast<T*>(aRhs.get())));
return *this;
}
nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
assign_assuming_AddRef(aRhs.forget().take());
return *this;
}
template <class U>
nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value,
"U should be a subclass of T");
assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this;
}
nsCOMPtr<T>& operator=(T* aRhs) {
assign_with_AddRef(ToSupports(aRhs));
NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this;
}
nsCOMPtr<T>& operator=(decltype(nullptr)) {
assign_assuming_AddRef(nullptr);
return *this;
}
// Assign from |already_AddRefed|.
template <typename U>
nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value, "U is not a subclass of T");
assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this;
}
1998-12-17 22:12:45 +03:00
// Assign from |otherComPtr.forget()|.
template <typename U>
nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
// Make sure that U actually inherits from T
static_assert(mozilla::IsBaseOf<T, U>::value, "U is not a subclass of T");
assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this;
}
// Assign from |do_QueryInterface(expr)|.
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
#ifdef NSCAP_FEATURE_USE_BASE
nsCOMPtr<T>& operator=(const nsQueryInterfaceISupports aRhs)
#else
template <typename U>
nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs)
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
{
assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
// Assign from |do_QueryInterface(expr, &rv)|.
#ifdef NSCAP_FEATURE_USE_BASE
nsCOMPtr<T>& operator=(const nsQueryInterfaceISupportsWithError& aRhs)
#else
template <typename U>
nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs)
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
{
assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
1998-12-17 22:12:45 +03:00
// Assign from |do_GetService(cid_expr)|.
nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
1998-12-17 22:12:45 +03:00
// Assign from |do_GetService(cid_expr, &rv)|.
nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
1998-12-17 22:12:45 +03:00
// Assign from |do_GetService(contractid_expr)|.
nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
// Assign from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
// Assign from |do_QueryReferent(ptr)|.
nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
return *this;
}
// And finally, anything else we might need to assign from can exploit the
// nsCOMPtr_helper facility.
nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
NSCAP_ASSERT_NO_QUERY_NEEDED();
return *this;
}
1998-12-17 22:12:45 +03:00
// Defined in OwningNonNull.h
template <class U>
nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
void swap(nsCOMPtr<T>& aRhs) {
#ifdef NSCAP_FEATURE_USE_BASE
nsISupports* temp = aRhs.mRawPtr;
#else
T* temp = aRhs.mRawPtr;
#endif
NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
NSCAP_LOG_ASSIGNMENT(this, temp);
NSCAP_LOG_RELEASE(this, mRawPtr);
NSCAP_LOG_RELEASE(&aRhs, temp);
aRhs.mRawPtr = mRawPtr;
mRawPtr = temp;
// |aRhs| maintains the same invariants, so we don't need to
// |NSCAP_ASSERT_NO_QUERY_NEEDED|
}
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
void swap(T*& aRhs) {
#ifdef NSCAP_FEATURE_USE_BASE
nsISupports* temp = ToSupports(aRhs);
#else
T* temp = aRhs;
#endif
NSCAP_LOG_ASSIGNMENT(this, temp);
NSCAP_LOG_RELEASE(this, mRawPtr);
aRhs = reinterpret_cast<T*>(mRawPtr);
mRawPtr = temp;
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
// Other pointer operators
1998-12-17 22:12:45 +03:00
// Return the value of mRawPtr and null out mRawPtr. Useful for
// already_AddRefed return values.
already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
T* temp = nullptr;
swap(temp);
return already_AddRefed<T>(temp);
}
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
// Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
// where aRhs bay be a T** or an I** where I is a base class of T.
template <typename I>
void forget(I** aRhs) {
NS_ASSERTION(aRhs, "Null pointer passed to forget!");
NSCAP_LOG_RELEASE(this, mRawPtr);
*aRhs = get();
mRawPtr = nullptr;
}
// Prefer the implicit conversion provided automatically by
// |operator T*() const|. Use |get()| to resolve ambiguity or to get a
// castable pointer.
T* get() const { return reinterpret_cast<T*>(mRawPtr); }
// Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
// used in a context where a raw pointer is expected. It is this operator
// that makes an nsCOMPtr substitutable for a raw pointer.
//
// Prefer the implicit use of this operator to calling |get()|, except where
// necessary to resolve ambiguity.
operator T*() const& { return get(); }
// Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
// because the refcount might be one and the pointer will immediately become
// invalid.
operator T*() const&& = delete;
// Needed to avoid the deleted operator above
explicit operator bool() const { return !!mRawPtr; }
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL nsCOMPtr with operator->().");
return get();
}
// These are not intended to be used by clients. See |address_of| below.
nsCOMPtr<T>* get_address() { return this; }
const nsCOMPtr<T>* get_address() const { return this; }
public:
T& operator*() const {
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL nsCOMPtr with operator*().");
return *get();
}
T** StartAssignment() {
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return reinterpret_cast<T**>(begin_assignment());
#else
assign_assuming_AddRef(nullptr);
return reinterpret_cast<T**>(&mRawPtr);
#endif
}
};
/*
* Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
* the same way people use nsISupports* and void*, i.e., as a `catch-all'
* pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
* would only be able to point to the single [XP]COM-correct nsISupports
* instance within an object; extra querying ensues. Clients need to be able to
* pass around arbitrary interface pointers, without hassles, through
* intermediary code that doesn't know the exact type.
*/
template <>
class MOZ_IS_REFPTR nsCOMPtr<nsISupports> : private nsCOMPtr_base {
public:
typedef nsISupports element_type;
1998-12-17 22:12:45 +03:00
// Constructors
nsCOMPtr() : nsCOMPtr_base(nullptr) { NSCAP_LOG_ASSIGNMENT(this, nullptr); }
1998-12-17 22:12:45 +03:00
MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
}
nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
: nsCOMPtr_base(aSmartPtr.mRawPtr) {
if (mRawPtr) {
NSCAP_ADDREF(this, mRawPtr);
}
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
}
1998-12-17 22:12:45 +03:00
MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr) : nsCOMPtr_base(aRawPtr) {
if (mRawPtr) {
NSCAP_ADDREF(this, mRawPtr);
}
NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
}
// Construct from |already_AddRefed|.
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
: nsCOMPtr_base(aSmartPtr.take()) {
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
}
// Construct from |otherComPtr.forget()|.
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
: nsCOMPtr_base(aSmartPtr.take()) {
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
}
// Construct from |do_QueryInterface(expr)|.
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_qi(aQI, NS_GET_IID(nsISupports));
}
// Construct from |do_QueryInterface(expr, &rv)|.
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
}
// Construct from |do_GetService(cid_expr)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
}
// Construct from |do_GetService(cid_expr, &rv)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
}
// Construct from |do_GetService(contractid_expr)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
}
// Construct from |do_GetService(contractid_expr, &rv)|.
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
}
// Construct from |do_QueryReferent(ptr)|
MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_query_referent(aQueryReferent,
NS_GET_TEMPLATE_IID(nsISupports));
}
// And finally, anything else we might need to construct from can exploit
// the |nsCOMPtr_helper| facility
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
: nsCOMPtr_base(nullptr) {
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_helper(aHelper, NS_GET_IID(nsISupports));
}
// Assignment operators
nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs) {
assign_with_AddRef(aRhs.mRawPtr);
return *this;
}
nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs) {
assign_with_AddRef(aRhs);
return *this;
}
nsCOMPtr<nsISupports>& operator=(decltype(nullptr)) {
assign_assuming_AddRef(nullptr);
return *this;
}
// Assign from |already_AddRefed|.
nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs) {
assign_assuming_AddRef(aRhs.take());
return *this;
}
// Assign from |otherComPtr.forget()|.
nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs) {
assign_assuming_AddRef(aRhs.take());
return *this;
}
// Assign from |do_QueryInterface(expr)|.
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceISupports aRhs) {
assign_from_qi(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_QueryInterface(expr, &rv)|.
nsCOMPtr<nsISupports>& operator=(
const nsQueryInterfaceISupportsWithError& aRhs) {
assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_GetService(cid_expr)|.
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs) {
assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_GetService(cid_expr, &rv)|.
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs) {
assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_GetService(contractid_expr)|.
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs) {
assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr<nsISupports>& operator=(
const nsGetServiceByContractIDWithError& aRhs) {
assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Assign from |do_QueryReferent(ptr)|.
nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs) {
assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
return *this;
}
// And finally, anything else we might need to assign from can exploit the
// nsCOMPtr_helper facility
nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs) {
assign_from_helper(aRhs, NS_GET_IID(nsISupports));
return *this;
}
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
void swap(nsCOMPtr<nsISupports>& aRhs) {
nsISupports* temp = aRhs.mRawPtr;
NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
NSCAP_LOG_ASSIGNMENT(this, temp);
NSCAP_LOG_RELEASE(this, mRawPtr);
NSCAP_LOG_RELEASE(&aRhs, temp);
aRhs.mRawPtr = mRawPtr;
mRawPtr = temp;
}
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
void swap(nsISupports*& aRhs) {
nsISupports* temp = aRhs;
NSCAP_LOG_ASSIGNMENT(this, temp);
NSCAP_LOG_RELEASE(this, mRawPtr);
aRhs = mRawPtr;
mRawPtr = temp;
}
// Return the value of mRawPtr and null out mRawPtr. Useful for
// already_AddRefed return values.
already_AddRefed<nsISupports> forget() {
nsISupports* temp = nullptr;
swap(temp);
return already_AddRefed<nsISupports>(temp);
}
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
// Useful to avoid unnecessary AddRef/Release pairs with "out"
// parameters.
void forget(nsISupports** aRhs) {
NS_ASSERTION(aRhs, "Null pointer passed to forget!");
*aRhs = nullptr;
swap(*aRhs);
}
// Other pointer operators
// Prefer the implicit conversion provided automatically by
// |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
// get a castable pointer.
nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
// Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
// used in a context where a raw pointer is expected. It is this operator
// that makes an nsCOMPtr substitutable for a raw pointer.
//
// Prefer the implicit use of this operator to calling |get()|, except where
// necessary to resolve ambiguity/
operator nsISupports*() const { return get(); }
nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL nsCOMPtr with operator->().");
return get();
}
// These are not intended to be used by clients. See |address_of| below.
nsCOMPtr<nsISupports>* get_address() { return this; }
const nsCOMPtr<nsISupports>* get_address() const { return this; }
public:
nsISupports& operator*() const {
MOZ_ASSERT(mRawPtr != nullptr,
"You can't dereference a NULL nsCOMPtr with operator*().");
return *get();
}
nsISupports** StartAssignment() {
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
return reinterpret_cast<nsISupports**>(begin_assignment());
#else
assign_assuming_AddRef(nullptr);
return reinterpret_cast<nsISupports**>(&mRawPtr);
#endif
}
};
template <typename T>
inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
aField = nullptr;
}
template <typename T>
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
const char* aName, uint32_t aFlags = 0) {
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
}
#ifndef NSCAP_FEATURE_USE_BASE
template <class T>
void nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr) {
if (aRawPtr) {
NSCAP_ADDREF(this, aRawPtr);
}
assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
}
template <class T>
Bug 1493226, part 1 - Statically prevent trivial calls to do_QueryInterface r=froydnj This patch adds a static assert to enforce that do_QueryInterface is not used to go from a class to a base class, because that can be done more efficiently via a static_cast. This is done by putting the type of the source into the nsQueryInterface type. Once that is done, it is easy to check the source and destination type. This has to be done carefully so that in non-DEBUG builds, where NSCAP_FEATURE_USE_BASE is defined, we don't generate any additional code. The first step is to rename nsQueryInterface to nsQueryInterfaceISupports. In DEBUG builds, I then add a new subtype nsQueryInterface<T>, where T is the type of the object we are going to QI. This class is a thin wrapper around nsQueryInterfaceISupports that only forwards operations to the base class. The main bit of trickery here is PointedToType<T>, which is needed to get the type parameter for nsQueryInterface. This dereferences the type, gets the address of it, then does RemovePointer. This is needed because a wide variety of pointer types are passed in to do_QueryInterface, including RefPtr<>, nsCOMPtr<>, raw pointers, and OwningNonNull<>. PointedToType<RefPtr<T>> is equal to T, PointedToType<T*> is equal to T, and so on. In NSCAP_FEATURE_USE_BASE builds (opt), we only use nsQueryInterfaceISupports, but in debug builds we use nsQueryInterface<> where possible. The latter is also used for the nsCOMPtr<nsISupports> overload, because we can always QI to nsISupports, because that is sometimes used for canonicalization. Another gross bit is that Assert_NoQueryNeeded can no longer use nsCOMPtr<>, because it works by QIing T to T, which is banned by the static analysis. Instead I had to reimplement it by hand. Depends on D7527 Differential Revision: https://phabricator.services.mozilla.com/D7553 --HG-- extra : moz-landing-system : lando
2018-10-04 22:16:28 +03:00
template <typename U>
void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
const nsIID& aIID) {
static_assert(
!(mozilla::IsSame<T, U>::value || mozilla::IsBaseOf<T, U>::value),
"don't use do_QueryInterface for compile-time-determinable casts");
void* newRawPtr;
if (NS_FAILED(aQI(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
template <typename U>
void nsCOMPtr<T>::assign_from_qi_with_error(
const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
static_assert(
!(mozilla::IsSame<T, U>::value || mozilla::IsBaseOf<T, U>::value),
"don't use do_QueryInterface for compile-time-determinable casts");
void* newRawPtr;
if (NS_FAILED(aQI(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_gs_cid_with_error(
const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_query_referent(
const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
const nsIID& aIID) {
void* newRawPtr;
if (NS_FAILED(helper(aIID, &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
}
template <class T>
void** nsCOMPtr<T>::begin_assignment() {
assign_assuming_AddRef(nullptr);
union {
T** mT;
void** mVoid;
} result;
result.mT = &mRawPtr;
return result.mVoid;
}
#endif
template <class T>
inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
return aPtr.get_address();
}
template <class T>
inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
return aPtr.get_address();
}
/**
* This class is designed to be used for anonymous temporary objects in the
* argument list of calls that return COM interface pointers, e.g.,
*
* nsCOMPtr<IFoo> fooP;
* ...->QueryInterface(iid, getter_AddRefs(fooP))
*
* DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
*
* When initialized with a |nsCOMPtr|, as in the example above, it returns
* a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
* (|QueryInterface| in this case) can fill in.
*
* This type should be a nested class inside |nsCOMPtr<T>|.
*/
template <class T>
class nsGetterAddRefs {
public:
explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
: mTargetSmartPtr(aSmartPtr) {}
#if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
~nsGetterAddRefs() {
# ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
mTargetSmartPtr.get());
# endif
# ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
mTargetSmartPtr.Assert_NoQueryNeeded();
# endif
}
#endif
operator void**() {
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
}
operator T**() { return mTargetSmartPtr.StartAssignment(); }
T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
private:
nsCOMPtr<T>& mTargetSmartPtr;
};
template <>
class nsGetterAddRefs<nsISupports> {
public:
explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
: mTargetSmartPtr(aSmartPtr) {}
#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
~nsGetterAddRefs() {
NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
mTargetSmartPtr.get());
}
#endif
operator void**() {
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
}
operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
private:
nsCOMPtr<nsISupports>& mTargetSmartPtr;
};
template <class T>
inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
return nsGetterAddRefs<T>(aSmartPtr);
}
template <class T, class DestinationType>
inline nsresult CallQueryInterface(
T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
return CallQueryInterface(aSource,
static_cast<DestinationType**>(aDestination));
}
// Comparing two |nsCOMPtr|s
template <class T, class U>
inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
}
template <class T, class U>
inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
}
// Comparing an |nsCOMPtr| to a raw pointer
template <class T, class U>
inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
return static_cast<const T*>(aLhs.get()) == aRhs;
}
template <class T, class U>
inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
return aLhs == static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
return static_cast<const T*>(aLhs.get()) != aRhs;
}
template <class T, class U>
inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
return aLhs != static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
}
template <class T, class U>
inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
}
template <class T, class U>
inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
}
// Comparing an |nsCOMPtr| to |nullptr|
template <class T>
inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
return aLhs.get() == nullptr;
}
template <class T>
inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
return nullptr == aRhs.get();
}
template <class T>
inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
return aLhs.get() != nullptr;
}
template <class T>
inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
return nullptr != aRhs.get();
}
// Comparing any two [XP]COM objects for identity
inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
}
template <class SourceType, class DestinationType>
inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
DestinationType** aDestPtr) {
return CallQueryInterface(aSourcePtr.get(), aDestPtr);
}
template <class T>
RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
void* newRawPtr;
if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
newRawPtr = nullptr;
}
mRawPtr = static_cast<T*>(newRawPtr);
}
template <class T>
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
void* newRawPtr;
if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
newRawPtr = nullptr;
}
mRawPtr = static_cast<T*>(newRawPtr);
}
template <class T>
RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
void* newRawPtr;
if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
return *this;
}
template <class T>
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
void* newRawPtr;
if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
newRawPtr = nullptr;
}
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
return *this;
}
template <class T>
inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
nsCOMPtr<T> ref(aObj);
return ref.forget();
}
// MOZ_DBG support
template <class T>
std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
return mozilla::DebugValue(aOut, aObj.get());
}
1998-12-17 22:12:45 +03:00
#endif // !defined(nsCOMPtr_h___)