diff options
Diffstat (limited to 'xpcom')
44 files changed, 2443 insertions, 731 deletions
diff --git a/xpcom/base/AppShutdown.cpp b/xpcom/base/AppShutdown.cpp index c68dedef31..53ae4e3ba9 100644 --- a/xpcom/base/AppShutdown.cpp +++ b/xpcom/base/AppShutdown.cpp @@ -309,32 +309,32 @@ bool AppShutdown::IsRestarting() { void AppShutdown::AnnotateShutdownReason(AppShutdownReason aReason) { auto key = CrashReporter::Annotation::ShutdownReason; - nsCString reasonStr; + const char* reasonStr; switch (aReason) { case AppShutdownReason::AppClose: - reasonStr = "AppClose"_ns; + reasonStr = "AppClose"; break; case AppShutdownReason::AppRestart: - reasonStr = "AppRestart"_ns; + reasonStr = "AppRestart"; break; case AppShutdownReason::OSForceClose: - reasonStr = "OSForceClose"_ns; + reasonStr = "OSForceClose"; break; case AppShutdownReason::OSSessionEnd: - reasonStr = "OSSessionEnd"_ns; + reasonStr = "OSSessionEnd"; break; case AppShutdownReason::OSShutdown: - reasonStr = "OSShutdown"_ns; + reasonStr = "OSShutdown"; break; case AppShutdownReason::WinUnexpectedMozQuit: - reasonStr = "WinUnexpectedMozQuit"_ns; + reasonStr = "WinUnexpectedMozQuit"; break; default: MOZ_ASSERT_UNREACHABLE("We should know the given reason for shutdown."); - reasonStr = "Unknown"_ns; + reasonStr = "Unknown"; break; } - CrashReporter::AnnotateCrashReport(key, reasonStr); + CrashReporter::RecordAnnotationCString(key, reasonStr); } #ifdef DEBUG diff --git a/xpcom/base/AvailableMemoryWatcherLinux.cpp b/xpcom/base/AvailableMemoryWatcherLinux.cpp index 04927b7d46..de8a1d79fc 100644 --- a/xpcom/base/AvailableMemoryWatcherLinux.cpp +++ b/xpcom/base/AvailableMemoryWatcherLinux.cpp @@ -206,7 +206,7 @@ void nsAvailableMemoryWatcher::HandleLowMemory() { void nsAvailableMemoryWatcher::UpdateCrashAnnotation(const MutexAutoLock&) MOZ_REQUIRES(mMutex) { - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationBool( CrashReporter::Annotation::LinuxUnderMemoryPressure, mUnderMemoryPressure); } diff --git a/xpcom/base/AvailableMemoryWatcherMac.cpp b/xpcom/base/AvailableMemoryWatcherMac.cpp index d6f2d16b30..de6901f8d5 100644 --- a/xpcom/base/AvailableMemoryWatcherMac.cpp +++ b/xpcom/base/AvailableMemoryWatcherMac.cpp @@ -95,11 +95,11 @@ class nsAvailableMemoryWatcher final : public nsITimerCallback, void AddParentAnnotation(CrashReporter::Annotation aAnnotation, nsAutoCString aString) { - CrashReporter::AnnotateCrashReport(aAnnotation, aString); + CrashReporter::RecordAnnotationNSCString(aAnnotation, aString); } void AddParentAnnotation(CrashReporter::Annotation aAnnotation, uint32_t aData) { - CrashReporter::AnnotateCrashReport(aAnnotation, aData); + CrashReporter::RecordAnnotationU32(aAnnotation, aData); } void LowMemoryResponse(); @@ -251,18 +251,18 @@ nsresult nsAvailableMemoryWatcher::Init() { // Set the initial state of all annotations for parent crash reports. // Content process crash reports are set when a crash occurs and // AddChildAnnotations() is called. - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressure, mLevelStr); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureNormalTime, mNormalTimeStr); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureWarningTime, mWarningTimeStr); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureCriticalTime, mCriticalTimeStr); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationU32( CrashReporter::Annotation::MacMemoryPressureSysctl, mLevelSysctl); - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationU32( CrashReporter::Annotation::MacAvailableMemorySysctl, mAvailMemSysctl); // To support running experiments, handle pref @@ -441,18 +441,18 @@ void nsAvailableMemoryWatcher::OnMemoryPressureChangedInternal( // Add all annotations to the provided crash reporter instance. void nsAvailableMemoryWatcher::AddChildAnnotations( const UniquePtr<ipc::CrashReporterHost>& aCrashReporter) { - aCrashReporter->AddAnnotation(CrashReporter::Annotation::MacMemoryPressure, - mLevelStr); - aCrashReporter->AddAnnotation( + aCrashReporter->AddAnnotationNSCString( + CrashReporter::Annotation::MacMemoryPressure, mLevelStr); + aCrashReporter->AddAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureNormalTime, mNormalTimeStr); - aCrashReporter->AddAnnotation( + aCrashReporter->AddAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureWarningTime, mWarningTimeStr); - aCrashReporter->AddAnnotation( + aCrashReporter->AddAnnotationNSCString( CrashReporter::Annotation::MacMemoryPressureCriticalTime, mCriticalTimeStr); - aCrashReporter->AddAnnotation( + aCrashReporter->AddAnnotationU32( CrashReporter::Annotation::MacMemoryPressureSysctl, mLevelSysctl); - aCrashReporter->AddAnnotation( + aCrashReporter->AddAnnotationU32( CrashReporter::Annotation::MacAvailableMemorySysctl, mAvailMemSysctl); } diff --git a/xpcom/base/AvailableMemoryWatcherWin.cpp b/xpcom/base/AvailableMemoryWatcherWin.cpp index cd027366de..1effbe3226 100644 --- a/xpcom/base/AvailableMemoryWatcherWin.cpp +++ b/xpcom/base/AvailableMemoryWatcherWin.cpp @@ -121,6 +121,12 @@ nsresult nsAvailableMemoryWatcher::Init() { return NS_ERROR_FAILURE; } + static_assert(sizeof(sNumLowPhysicalMemEvents) == sizeof(uint32_t)); + + CrashReporter::RegisterAnnotationU32( + CrashReporter::Annotation::LowPhysicalMemoryEvents, + reinterpret_cast<uint32_t*>(&sNumLowPhysicalMemEvents)); + return NS_OK; } @@ -172,9 +178,6 @@ VOID CALLBACK nsAvailableMemoryWatcher::LowMemoryCallback(PVOID aContext, // static void nsAvailableMemoryWatcher::RecordLowMemoryEvent() { sNumLowPhysicalMemEvents++; - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::LowPhysicalMemoryEvents, - sNumLowPhysicalMemEvents); } bool nsAvailableMemoryWatcher::RegisterMemoryResourceHandler( diff --git a/xpcom/base/CFTypeRefPtr.h b/xpcom/base/CFTypeRefPtr.h new file mode 100644 index 0000000000..185355777e --- /dev/null +++ b/xpcom/base/CFTypeRefPtr.h @@ -0,0 +1,194 @@ +/* -*- 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/. */ + +#ifndef CFTypeRefPtr_h +#define CFTypeRefPtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/DbgMacro.h" +#include "mozilla/HashFunctions.h" + +// A smart pointer for CoreFoundation classes which does reference counting. +// +// Manual reference counting: +// +// UInt32 someNumber = 10; +// CFNumberRef numberObject = +// CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber); +// // do something with numberObject +// CFRelease(numberObject); +// +// Automatic reference counting using CFTypeRefPtr: +// +// UInt32 someNumber = 10; +// auto numberObject = +// CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule( +// CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &someNumber)); +// // do something with numberObject +// // no CFRelease + +template <class PtrT> +class CFTypeRefPtr { + private: + void assign_with_CFRetain(PtrT aRawPtr) { + CFRetain(aRawPtr); + assign_assuming_CFRetain(aRawPtr); + } + + void assign_assuming_CFRetain(PtrT aNewPtr) { + PtrT oldPtr = mRawPtr; + mRawPtr = aNewPtr; + if (oldPtr) { + CFRelease(oldPtr); + } + } + + private: + PtrT mRawPtr; + + public: + ~CFTypeRefPtr() { + if (mRawPtr) { + CFRelease(mRawPtr); + } + } + + // Constructors + + CFTypeRefPtr() : mRawPtr(nullptr) {} + + CFTypeRefPtr(const CFTypeRefPtr<PtrT>& aSmartPtr) + : mRawPtr(aSmartPtr.mRawPtr) { + if (mRawPtr) { + CFRetain(mRawPtr); + } + } + + CFTypeRefPtr(CFTypeRefPtr<PtrT>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) { + aRefPtr.mRawPtr = nullptr; + } + + MOZ_IMPLICIT CFTypeRefPtr(decltype(nullptr)) : mRawPtr(nullptr) {} + + // There is no constructor from a raw pointer value. + // Use one of the static WrapUnder*Rule methods below instead. + + static CFTypeRefPtr<PtrT> WrapUnderCreateRule(PtrT aRawPtr) { + CFTypeRefPtr<PtrT> ptr; + ptr.AssignUnderCreateRule(aRawPtr); + return ptr; + } + + static CFTypeRefPtr<PtrT> WrapUnderGetRule(PtrT aRawPtr) { + CFTypeRefPtr<PtrT> ptr; + ptr.AssignUnderGetRule(aRawPtr); + return ptr; + } + + // Assignment operators + + CFTypeRefPtr<PtrT>& operator=(decltype(nullptr)) { + assign_assuming_CFRetain(nullptr); + return *this; + } + + CFTypeRefPtr<PtrT>& operator=(const CFTypeRefPtr<PtrT>& aRhs) { + assign_with_CFRetain(aRhs.mRawPtr); + return *this; + } + + CFTypeRefPtr<PtrT>& operator=(CFTypeRefPtr<PtrT>&& aRefPtr) { + assign_assuming_CFRetain(aRefPtr.mRawPtr); + aRefPtr.mRawPtr = nullptr; + return *this; + } + + // There is no operator= for a raw pointer value. + // Use one of the AssignUnder*Rule methods below instead. + + CFTypeRefPtr<PtrT>& AssignUnderCreateRule(PtrT aRawPtr) { + // Freshly-created objects come with a retain count of 1. + assign_assuming_CFRetain(aRawPtr); + return *this; + } + + CFTypeRefPtr<PtrT>& AssignUnderGetRule(PtrT aRawPtr) { + assign_with_CFRetain(aRawPtr); + return *this; + } + + // Other pointer operators + + // This is the only way to get the raw pointer out of the smart pointer. + // There is no implicit conversion to a raw pointer. + PtrT get() const { return mRawPtr; } + + // Don't allow implicit conversion of temporary CFTypeRefPtr to raw pointer, + // because the refcount might be one and the pointer will immediately become + // invalid. + operator PtrT() const&& = delete; + // Also don't allow implicit conversion of non-temporary CFTypeRefPtr. + operator PtrT() const& = delete; + + // These let you null-check a pointer without calling get(). + explicit operator bool() const { return !!mRawPtr; } +}; + +template <class PtrT> +inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs, + const CFTypeRefPtr<PtrT>& aRhs) { + return aLhs.get() == aRhs.get(); +} + +template <class PtrT> +inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs, + const CFTypeRefPtr<PtrT>& aRhs) { + return !(aLhs == aRhs); +} + +// Comparing an |CFTypeRefPtr| to |nullptr| + +template <class PtrT> +inline bool operator==(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) { + return aLhs.get() == nullptr; +} + +template <class PtrT> +inline bool operator==(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) { + return nullptr == aRhs.get(); +} + +template <class PtrT> +inline bool operator!=(const CFTypeRefPtr<PtrT>& aLhs, decltype(nullptr)) { + return aLhs.get() != nullptr; +} + +template <class PtrT> +inline bool operator!=(decltype(nullptr), const CFTypeRefPtr<PtrT>& aRhs) { + return nullptr != aRhs.get(); +} + +// MOZ_DBG support + +template <class PtrT> +std::ostream& operator<<(std::ostream& aOut, const CFTypeRefPtr<PtrT>& aObj) { + return mozilla::DebugValue(aOut, aObj.get()); +} + +// std::hash support (e.g. for unordered_map) +namespace std { +template <class PtrT> +struct hash<CFTypeRefPtr<PtrT>> { + typedef CFTypeRefPtr<PtrT> argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& aPtr) const { + return mozilla::HashGeneric(reinterpret_cast<uintptr_t>(aPtr.get())); + } +}; +} // namespace std + +#endif /* CFTypeRefPtr_h */ diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 03af9e3074..c3f9d56857 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1046,7 +1046,7 @@ struct GCMajorMarker : public BaseMarkerType<GCMajorMarker> { using MS = MarkerSchema; static constexpr MS::PayloadField PayloadFields[] = { - {"timings", MS::InputType::String, "GC timings"}}; + {"timings", MS::InputType::CString, "GC timings"}}; static constexpr MS::Location Locations[] = {MS::Location::MarkerChart, MS::Location::MarkerTable, @@ -1793,8 +1793,8 @@ void CycleCollectedJSRuntime::AnnotateAndSetOutOfMemory(OOMState* aStatePtr, ? CrashReporter::Annotation::JSOutOfMemory : CrashReporter::Annotation::JSLargeAllocationFailure; - CrashReporter::AnnotateCrashReport( - annotation, nsDependentCString(OOMStateToString(aNewState))); + CrashReporter::RecordAnnotationCString(annotation, + OOMStateToString(aNewState)); } void CycleCollectedJSRuntime::OnGC(JSContext* aContext, JSGCStatus aStatus, diff --git a/xpcom/base/EnumeratedArrayCycleCollection.h b/xpcom/base/EnumeratedArrayCycleCollection.h index 465d4cf38a..863b990de7 100644 --- a/xpcom/base/EnumeratedArrayCycleCollection.h +++ b/xpcom/base/EnumeratedArrayCycleCollection.h @@ -10,21 +10,21 @@ #include "mozilla/EnumeratedArray.h" #include "nsCycleCollectionTraversalCallback.h" -template <typename IndexType, IndexType SizeAsEnumValue, typename ValueType> +template <typename IndexType, typename ValueType, size_t Size> inline void ImplCycleCollectionUnlink( - mozilla::EnumeratedArray<IndexType, SizeAsEnumValue, ValueType>& aField) { - for (size_t i = 0; i < size_t(SizeAsEnumValue); ++i) { + mozilla::EnumeratedArray<IndexType, ValueType, Size>& aField) { + for (size_t i = 0; i < Size; ++i) { aField[IndexType(i)] = nullptr; } } -template <typename IndexType, IndexType SizeAsEnumValue, typename ValueType> +template <typename IndexType, typename ValueType, size_t Size> inline void ImplCycleCollectionTraverse( nsCycleCollectionTraversalCallback& aCallback, - mozilla::EnumeratedArray<IndexType, SizeAsEnumValue, ValueType>& aField, + mozilla::EnumeratedArray<IndexType, ValueType, Size>& aField, const char* aName, uint32_t aFlags = 0) { aFlags |= CycleCollectionEdgeNameArrayFlag; - for (size_t i = 0; i < size_t(SizeAsEnumValue); ++i) { + for (size_t i = 0; i < Size; ++i) { ImplCycleCollectionTraverse(aCallback, aField[IndexType(i)], aName, aFlags); } } diff --git a/xpcom/base/MacHelpers.mm b/xpcom/base/MacHelpers.mm index 26c04c49dd..9d53fd5b56 100644 --- a/xpcom/base/MacHelpers.mm +++ b/xpcom/base/MacHelpers.mm @@ -24,8 +24,7 @@ nsresult GetSelectedCityInfo(nsAString& aCountryCode) { return NS_ERROR_FAILURE; } - return mozilla::CopyCocoaStringToXPCOMString((NSString*)countryCode, - aCountryCode); + mozilla::CopyNSStringToXPCOMString((NSString*)countryCode, aCountryCode); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); } diff --git a/xpcom/base/MacStringHelpers.h b/xpcom/base/MacStringHelpers.h index c2f9ee82dc..f43046cfb6 100644 --- a/xpcom/base/MacStringHelpers.h +++ b/xpcom/base/MacStringHelpers.h @@ -13,7 +13,11 @@ namespace mozilla { -nsresult CopyCocoaStringToXPCOMString(NSString* aFrom, nsAString& aTo); +void CopyNSStringToXPCOMString(const NSString* aFrom, nsAString& aTo); + +NSString* XPCOMStringToNSString(const nsAString& aFrom); + +NSString* XPCOMStringToNSString(const nsACString& aFrom); } // namespace mozilla diff --git a/xpcom/base/MacStringHelpers.mm b/xpcom/base/MacStringHelpers.mm index cf0b03665d..30b447548a 100644 --- a/xpcom/base/MacStringHelpers.mm +++ b/xpcom/base/MacStringHelpers.mm @@ -12,24 +12,42 @@ namespace mozilla { -nsresult CopyCocoaStringToXPCOMString(NSString* aFrom, nsAString& aTo) { - NS_OBJC_BEGIN_TRY_BLOCK_RETURN; +void CopyNSStringToXPCOMString(const NSString* aFrom, nsAString& aTo) { + NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; - NSUInteger len = [aFrom length]; - if (len > std::numeric_limits<nsAString::size_type>::max()) { - return NS_ERROR_OUT_OF_MEMORY; + if (!aFrom) { + aTo.Truncate(); + return; } - if (!aTo.SetLength(len, mozilla::fallible)) { - return NS_ERROR_OUT_OF_MEMORY; + NSUInteger len = [aFrom length]; + if (len > std::numeric_limits<nsAString::size_type>::max()) { + aTo.AllocFailed(std::numeric_limits<nsAString::size_type>::max()); } + aTo.SetLength(len); [aFrom getCharacters:reinterpret_cast<unichar*>(aTo.BeginWriting()) range:NSMakeRange(0, len)]; - return NS_OK; + NS_OBJC_END_TRY_IGNORE_BLOCK; +} - NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); +NSString* XPCOMStringToNSString(const nsAString& aFrom) { + if (aFrom.IsEmpty()) { + return [NSString string]; + } + return [NSString stringWithCharacters:reinterpret_cast<const unichar*>( + aFrom.BeginReading()) + length:aFrom.Length()]; +} + +NSString* XPCOMStringToNSString(const nsACString& aFrom) { + if (aFrom.IsEmpty()) { + return [NSString string]; + } + return [[[NSString alloc] initWithBytes:aFrom.BeginReading() + length:aFrom.Length() + encoding:NSUTF8StringEncoding] autorelease]; } } // namespace mozilla diff --git a/xpcom/base/moz.build b/xpcom/base/moz.build index 1ac409ed04..16870a9dbc 100644 --- a/xpcom/base/moz.build +++ b/xpcom/base/moz.build @@ -27,18 +27,24 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": XPIDL_SOURCES += [ "nsIMacPreferencesReader.idl", ] + EXPORTS.mozilla += [ + "MacHelpers.h", + "nsMacPreferencesReader.h", + ] + UNIFIED_SOURCES += [ + "MacHelpers.mm", + "nsMacPreferencesReader.mm", + ] +if CONFIG["OS_ARCH"] == "Darwin": EXPORTS += [ + "CFTypeRefPtr.h", "nsObjCExceptions.h", ] EXPORTS.mozilla += [ - "MacHelpers.h", "MacStringHelpers.h", - "nsMacPreferencesReader.h", ] UNIFIED_SOURCES += [ - "MacHelpers.mm", "MacStringHelpers.mm", - "nsMacPreferencesReader.mm", "nsObjCExceptions.mm", ] diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 9c885b6ef1..9c39dee475 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -628,8 +628,8 @@ void PtrInfo::AnnotatedReleaseAssert(bool aCondition, const char* aMessage) { } nsPrintfCString msg("%s, for class %s", aMessage, piName); NS_WARNING(msg.get()); - CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::CycleCollector, - msg); + CrashReporter::RecordAnnotationNSCString( + CrashReporter::Annotation::CycleCollector, msg); MOZ_CRASH(); } diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index 4023efd0ec..81305ccdb9 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -452,13 +452,12 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, if (XRE_IsParentProcess()) { // Don't include the PID in the crash report annotation to // allow faceting on crash-stats.mozilla.org. - nsCString note("xpcom_runtime_abort("); + nsAutoCString note("xpcom_runtime_abort("); note += nonPIDBuf.buffer; note += ")"; CrashReporter::AppendAppNotesToCrashReport(note); - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::AbortMessage, - nsDependentCString(nonPIDBuf.buffer)); + CrashReporter::RecordAnnotationNSCString( + CrashReporter::Annotation::AbortMessage, note); } #if defined(DEBUG) && defined(_WIN32) diff --git a/xpcom/base/nsISupportsImpl.cpp b/xpcom/base/nsISupportsImpl.cpp index c282ec14db..5ae4b3914b 100644 --- a/xpcom/base/nsISupportsImpl.cpp +++ b/xpcom/base/nsISupportsImpl.cpp @@ -50,13 +50,25 @@ bool nsAutoOwningThread::IsCurrentThread() const { nsAutoOwningEventTarget::nsAutoOwningEventTarget() : mTarget(GetCurrentSerialEventTarget()) { - mTarget->AddRef(); + NS_ADDREF(mTarget); } -nsAutoOwningEventTarget::~nsAutoOwningEventTarget() { - nsCOMPtr<nsISerialEventTarget> target = dont_AddRef(mTarget); +nsAutoOwningEventTarget::nsAutoOwningEventTarget( + const nsAutoOwningEventTarget& aOther) + : mTarget(aOther.mTarget) { + NS_ADDREF(mTarget); } +nsAutoOwningEventTarget& nsAutoOwningEventTarget::operator=( + const nsAutoOwningEventTarget& aRhs) { + nsISerialEventTarget* previous = std::exchange(mTarget, aRhs.mTarget); + NS_ADDREF(mTarget); + NS_RELEASE(previous); + return *this; +} + +nsAutoOwningEventTarget::~nsAutoOwningEventTarget() { NS_RELEASE(mTarget); } + void nsAutoOwningEventTarget ::AssertCurrentThreadOwnsMe( const char* msg) const { if (MOZ_UNLIKELY(!IsCurrentThread())) { diff --git a/xpcom/base/nsISupportsImpl.h b/xpcom/base/nsISupportsImpl.h index 27ff85b385..0485a98812 100644 --- a/xpcom/base/nsISupportsImpl.h +++ b/xpcom/base/nsISupportsImpl.h @@ -71,6 +71,20 @@ class nsISerialEventTarget; class nsAutoOwningEventTarget { public: nsAutoOwningEventTarget(); + + nsAutoOwningEventTarget(const nsAutoOwningEventTarget& aOther); + + // Per https://en.cppreference.com/w/cpp/language/move_constructor + // there's no implicitly-declared move constructor if there are user-declared + // copy constructors, and we have one, immediately above. + + nsAutoOwningEventTarget& operator=(const nsAutoOwningEventTarget& aRhs); + + // Per https://en.cppreference.com/w/cpp/language/move_assignment + // there's no implicitly-declared move assignment operator if there are + // user-declared copy assignment operators, and we have one, immediately + // above. + ~nsAutoOwningEventTarget(); // We move the actual assertion checks out-of-line to minimize code bloat, @@ -88,6 +102,7 @@ class nsAutoOwningEventTarget { private: void AssertCurrentThreadOwnsMe(const char* aMsg) const; + // A raw pointer to avoid nsCOMPtr.h dependency. nsISerialEventTarget* mTarget; }; diff --git a/xpcom/base/nsrootidl.idl b/xpcom/base/nsrootidl.idl index 28e643e312..292ea54890 100644 --- a/xpcom/base/nsrootidl.idl +++ b/xpcom/base/nsrootidl.idl @@ -35,18 +35,21 @@ class Promise; #if 0 %} -typedef boolean bool ; -typedef octet uint8_t ; -typedef unsigned short uint16_t ; -typedef unsigned short char16_t; -typedef unsigned long uint32_t ; -typedef unsigned long long uint64_t ; -typedef long long PRTime ; -typedef short int16_t ; -typedef long int32_t ; -typedef long long int64_t ; - -typedef unsigned long nsresult ; +// [substitute] typedefs emit the underlying builtin type directly, and +// avoid polluting bindings for other languages with C++ stdint types. + +[substitute] typedef boolean bool ; +[substitute] typedef octet uint8_t ; +[substitute] typedef unsigned short uint16_t ; +[substitute] typedef unsigned long uint32_t ; +[substitute] typedef unsigned long long uint64_t ; +[substitute] typedef short int16_t ; +[substitute] typedef long int32_t ; +[substitute] typedef long long int64_t ; + + typedef unsigned short char16_t ; + typedef unsigned long nsresult ; + typedef long long PRTime ; // If we ever want to use `size_t` in scriptable interfaces, this will need to // be built into the xpidl compiler, as the size varies based on platform. diff --git a/xpcom/components/StaticComponents.cpp.in b/xpcom/components/StaticComponents.cpp.in index 7f3fee6859..d717b9f64a 100644 --- a/xpcom/components/StaticComponents.cpp.in +++ b/xpcom/components/StaticComponents.cpp.in @@ -83,9 +83,14 @@ const nsXPTInterface gInterfaces[] = { //# @interfaces@ }; +//# @define_has_component_jsms@ + +#ifdef HAS_COMPONENT_JSMS +// TODO: Remove this once m-c and c-c migrations finish (bug 1881887). const StringOffset gComponentJSMs[] = { //# @component_jsms@ }; +#endif const StringOffset gComponentESModules[] = { //# @component_esmodules@ @@ -148,9 +153,9 @@ static nsresult ConstructJSMOrESMComponent(const nsACString& aURI, (void**)aResult); } -static nsresult ConstructJSMComponent(const nsACString& aURI, - const char* aConstructor, - nsISupports** aResult) { +[[maybe_unused]] static nsresult ConstructJSMComponent(const nsACString& aURI, + const char* aConstructor, + nsISupports** aResult) { return ConstructJSMOrESMComponent<ComponentType::JSM>( aURI, aConstructor, aResult); } @@ -351,11 +356,15 @@ const StaticProtocolHandler* StaticProtocolHandler::Lookup(const nsACString& aSc /* static */ already_AddRefed<nsIUTF8StringEnumerator> StaticComponents::GetComponentJSMs() { +#ifdef HAS_COMPONENT_JSMS auto jsms = MakeUnique<nsTArray<nsCString>>(MOZ_ARRAY_LENGTH(gComponentJSMs)); for (const auto& entry : gComponentJSMs) { jsms->AppendElement(GetString(entry)); } +#else + auto jsms = MakeUnique<nsTArray<nsCString>>(0); +#endif nsCOMPtr<nsIUTF8StringEnumerator> result; MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result), diff --git a/xpcom/components/gen_static_components.py b/xpcom/components/gen_static_components.py index f759dc3132..122b7b21ca 100644 --- a/xpcom/components/gen_static_components.py +++ b/xpcom/components/gen_static_components.py @@ -920,14 +920,18 @@ def gen_substs(manifests): cid_phf = PerfectHash(modules, PHF_SIZE, key=lambda module: module.cid.bytes) - contract_phf = PerfectHash(contracts, PHF_SIZE, key=lambda entry: entry.contract) + contract_phf = PerfectHash( + contracts, PHF_SIZE, key=lambda entry: entry.contract.encode() + ) js_services_phf = PerfectHash( - list(js_services.values()), PHF_SIZE, key=lambda entry: entry.js_name + list(js_services.values()), PHF_SIZE, key=lambda entry: entry.js_name.encode() ) protocol_handlers_phf = PerfectHash( - list(protocol_handlers.values()), TINY_PHF_SIZE, key=lambda entry: entry.scheme + list(protocol_handlers.values()), + TINY_PHF_SIZE, + key=lambda entry: entry.scheme.encode(), ) js_services_json = {} @@ -945,7 +949,7 @@ def gen_substs(manifests): substs["contract_count"] = len(contracts) substs["protocol_handler_count"] = len(protocol_handlers) - substs["default_protocol_handler_idx"] = protocol_handlers_phf.get_index("default") + substs["default_protocol_handler_idx"] = protocol_handlers_phf.get_index(b"default") gen_module_funcs(substs, module_funcs) @@ -954,6 +958,9 @@ def gen_substs(manifests): substs["component_jsms"] = ( "\n".join(" %s," % strings.entry_to_cxx(jsm) for jsm in sorted(jsms)) + "\n" ) + substs["define_has_component_jsms"] = ( + "#define HAS_COMPONENT_JSMS" if len(jsms) > 0 else "" + ) substs["component_esmodules"] = ( "\n".join( " %s," % strings.entry_to_cxx(esModule) for esModule in sorted(esModules) @@ -1021,7 +1028,9 @@ def gen_substs(manifests): key_length="aKey.Length()", ) - substs["js_services_json"] = json.dumps(js_services_json, sort_keys=True, indent=4) + substs["js_services_json"] = ( + json.dumps(js_services_json, sort_keys=True, indent=2) + "\n" + ) # Do this only after everything else has been emitted so we're sure the # string table is complete. diff --git a/xpcom/components/nsIComponentManager.idl b/xpcom/components/nsIComponentManager.idl index 9abde9960c..6b921be004 100644 --- a/xpcom/components/nsIComponentManager.idl +++ b/xpcom/components/nsIComponentManager.idl @@ -99,6 +99,8 @@ interface nsIComponentManager : nsISupports /** * Returns a list of JSM URLs which are used to create components. This * should only be used in automation. + * + * TODO: Remove this once m-c and c-c migrations finish (bug 1881887). */ nsIUTF8StringEnumerator getComponentJSMs(); diff --git a/xpcom/components/nsIServiceManager.idl b/xpcom/components/nsIServiceManager.idl index dd613070e9..e327b49d79 100644 --- a/xpcom/components/nsIServiceManager.idl +++ b/xpcom/components/nsIServiceManager.idl @@ -59,9 +59,6 @@ interface nsIServiceManager : nsISupports %{C++ -// Observing xpcom autoregistration. Topics will be 'start' and 'stop'. -#define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration" - #ifdef MOZILLA_INTERNAL_API #include "nsXPCOM.h" #include "nsComponentManagerUtils.h" diff --git a/xpcom/docs/stringguide.rst b/xpcom/docs/stringguide.rst index a3266d9604..ceba003245 100644 --- a/xpcom/docs/stringguide.rst +++ b/xpcom/docs/stringguide.rst @@ -342,11 +342,11 @@ bucket could accommodate the new logical length. Helper Classes and Functions ---------------------------- -Converting Cocoa strings -~~~~~~~~~~~~~~~~~~~~~~~~ +Converting NSString strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use ``mozilla::CopyCocoaStringToXPCOMString()`` in -``mozilla/MacStringHelpers.h`` to convert Cocoa strings to XPCOM strings. +Use ``mozilla::CopyNSStringToXPCOMString()`` in +``mozilla/MacStringHelpers.h`` to convert NSString strings to XPCOM strings. Searching strings - looking for substrings, characters, etc. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/xpcom/ds/HTMLAtoms.py b/xpcom/ds/HTMLAtoms.py index ddaf52ae9f..927be525e3 100644 --- a/xpcom/ds/HTMLAtoms.py +++ b/xpcom/ds/HTMLAtoms.py @@ -41,6 +41,8 @@ HTML_PARSER_ATOMS = [ # ATOM GENERATED BY HTML PARSER TRANSLATOR (WILL BE AUTOMATICALLY OVERWRITTEN): Atom("shadowrootmode", "shadowrootmode"), # ATOM GENERATED BY HTML PARSER TRANSLATOR (WILL BE AUTOMATICALLY OVERWRITTEN): + Atom("shadowrootclonable", "shadowrootclonable"), + # ATOM GENERATED BY HTML PARSER TRANSLATOR (WILL BE AUTOMATICALLY OVERWRITTEN): Atom("stddeviation", "stddeviation"), # ATOM GENERATED BY HTML PARSER TRANSLATOR (WILL BE AUTOMATICALLY OVERWRITTEN): Atom("shadowrootdelegatesfocus", "shadowrootdelegatesfocus"), diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index ca4ac97813..2a0a25431e 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -121,6 +121,8 @@ STATIC_ATOMS = [ Atom("aria_activedescendant", "aria-activedescendant"), Atom("aria_atomic", "aria-atomic"), Atom("aria_autocomplete", "aria-autocomplete"), + Atom("aria_braillelabel", "aria-braillelabel"), + Atom("aria_brailleroledescription", "aria-brailleroledescription"), Atom("aria_busy", "aria-busy"), Atom("aria_checked", "aria-checked"), Atom("aria_controls", "aria-controls"), @@ -206,7 +208,6 @@ STATIC_ATOMS = [ Atom("box", "box"), Atom("br", "br"), Atom("browser", "browser"), - Atom("mozbrowser", "mozbrowser"), Atom("button", "button"), Atom("callTemplate", "call-template"), Atom("canvas", "canvas"), @@ -340,7 +341,6 @@ STATIC_ATOMS = [ Atom("difference", "difference"), Atom("digit", "digit"), Atom("dir", "dir"), - Atom("dirAutoSetBy", "dirAutoSetBy"), Atom("directory", "directory"), Atom("dirname", "dirname"), Atom("disableOutputEscaping", "disable-output-escaping"), @@ -453,7 +453,6 @@ STATIC_ATOMS = [ Atom("flags", "flags"), Atom("flex", "flex"), Atom("flip", "flip"), - Atom("floating", "floating"), Atom("floor", "floor"), Atom("flowlength", "flowlength"), Atom("focus", "focus"), @@ -731,6 +730,7 @@ STATIC_ATOMS = [ Atom("noembed", "noembed"), Atom("noframes", "noframes"), Atom("nohref", "nohref"), + Atom("noinitialselection", "noinitialselection"), Atom("nomodule", "nomodule"), Atom("nonce", "nonce"), Atom("none", "none"), @@ -832,6 +832,7 @@ STATIC_ATOMS = [ Atom("onfocusout", "onfocusout"), Atom("onfullscreenchange", "onfullscreenchange"), Atom("onfullscreenerror", "onfullscreenerror"), + Atom("ongatheringstatechange", "ongatheringstatechange"), Atom("onget", "onget"), Atom("onhashchange", "onhashchange"), Atom("oninput", "oninput"), @@ -1062,6 +1063,7 @@ STATIC_ATOMS = [ Atom("rem", "rem"), Atom("remote", "remote"), Atom("removeelement", "removeelement"), + Atom("render", "render"), Atom("renderingobserverset", "renderingobserverset"), Atom("repeat", "repeat"), Atom("replace", "replace"), @@ -1234,7 +1236,6 @@ STATIC_ATOMS = [ Atom("textarea", "textarea"), Atom("textbox", "textbox"), Atom("textLink", "text-link"), - Atom("textNodeDirectionalityMap", "textNodeDirectionalityMap"), Atom("textOverlay", "text-overlay"), Atom("tfoot", "tfoot"), Atom("th", "th"), @@ -1242,7 +1243,6 @@ STATIC_ATOMS = [ Atom("thumb", "thumb"), Atom("time", "time"), Atom("title", "title"), - Atom("titlebar", "titlebar"), Atom("titletip", "titletip"), Atom("toggle", "toggle"), Atom("token", "token"), @@ -2262,6 +2262,7 @@ STATIC_ATOMS = [ Atom("_moz_swipe_animation_enabled", "-moz-swipe-animation-enabled"), Atom("_moz_gtk_csd_available", "-moz-gtk-csd-available"), Atom("_moz_gtk_csd_titlebar_radius", "-moz-gtk-csd-titlebar-radius"), + Atom("_moz_gtk_csd_titlebar_button_spacing", "-moz-gtk-csd-titlebar-button-spacing"), Atom("_moz_gtk_csd_minimize_button", "-moz-gtk-csd-minimize-button"), Atom("_moz_gtk_csd_minimize_button_position", "-moz-gtk-csd-minimize-button-position"), Atom("_moz_gtk_csd_maximize_button", "-moz-gtk-csd-maximize-button"), @@ -2409,6 +2410,8 @@ STATIC_ATOMS = [ Atom("mathml_legacy_mathvariant_attribute_disabled", "mathml.legacy_mathvariant_attribute.disabled"), Atom("layout_css_always_underline_links", "layout.css.always_underline_links"), Atom("layout_css_cached_scrollbar_styles_enabled", "layout.css.cached-scrollbar-styles.enabled"), + Atom("layout_css_h1_in_section_ua_styles_enabled", "layout.css.h1-in-section-ua-styles.enabled"), + Atom("dom_forms_number_hide_spin_buttons_when_no_hover_or_focus", "dom.forms.number.hide_spin_buttons_when_no_hover_or_focus"), # Contextual Identity / Containers Atom("usercontextid", "usercontextid"), Atom("geckoViewSessionContextId", "geckoViewSessionContextId"), @@ -2525,7 +2528,6 @@ STATIC_ATOMS = [ InheritingAnonBoxAtom("AnonBox_cellContent", ":-moz-cell-content"), InheritingAnonBoxAtom("AnonBox_dropDownList", ":-moz-dropdown-list"), InheritingAnonBoxAtom("AnonBox_fieldsetContent", ":-moz-fieldset-content"), - InheritingAnonBoxAtom("AnonBox_mozDisplayComboboxControlFrame", ":-moz-display-comboboxcontrol-frame"), InheritingAnonBoxAtom("AnonBox_htmlCanvasContent", ":-moz-html-canvas-content"), InheritingAnonBoxAtom("AnonBox_inlineTable", ":-moz-inline-table"), InheritingAnonBoxAtom("AnonBox_table", ":-moz-table"), diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index e0fd430cd4..882d867474 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -180,13 +180,14 @@ nsresult nsObserverService::EnsureValidCall() const { } nsresult nsObserverService::FilterHttpOnTopics(const char* aTopic) { - // Specifically allow http-on-opening-request and http-on-stop-request in the - // child process; see bug 1269765. + // Specifically allow some http-on-* observer notifications in the child + // process. if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8) && + strcmp(aTopic, "http-on-before-stop-request") && strcmp(aTopic, "http-on-failed-opening-request") && + strcmp(aTopic, "http-on-image-cache-response") && strcmp(aTopic, "http-on-opening-request") && - strcmp(aTopic, "http-on-stop-request") && - strcmp(aTopic, "http-on-image-cache-response")) { + strcmp(aTopic, "http-on-stop-request")) { nsCOMPtr<nsIConsoleService> console( do_GetService(NS_CONSOLESERVICE_CONTRACTID)); nsCOMPtr<nsIScriptError> error( diff --git a/xpcom/ds/tools/perfecthash.py b/xpcom/ds/tools/perfecthash.py index 929b643a30..2a5778e86d 100644 --- a/xpcom/ds/tools/perfecthash.py +++ b/xpcom/ds/tools/perfecthash.py @@ -24,18 +24,6 @@ small dataset it was designed for. In the future we may want to optimize further import textwrap from collections import namedtuple -import six -from mozbuild.util import ensure_bytes - - -# Iteration over bytestrings works differently in Python 2 and 3; this function -# captures the two possibilities. Returns an 'int' given the output of iterating -# through a bytestring regardless of the input. -def _ord(c): - if six.PY3: - return c - return ord(c) - class PerfectHash(object): """PerfectHash objects represent a computed perfect hash function, which @@ -88,7 +76,7 @@ class PerfectHash(object): for bucket in buckets: # Once we've reached an empty bucket, we're done. - if len(bucket.entries) == 0: + if not bucket.entries: break # Try values for the basis until we find one with no conflicts. @@ -103,7 +91,7 @@ class PerfectHash(object): # There was a conflict, try the next basis. basis += 1 idx = 0 - del slots[:] + slots.clear() assert basis < self.U32_MAX, "table too small" else: slots.append(slot) @@ -127,15 +115,16 @@ class PerfectHash(object): 32-bit FNV is used for indexing into the first table, and the value stored in that table is used as the offset basis for indexing into the values table.""" - for byte in memoryview(ensure_bytes(key)): - obyte = _ord(byte) + FNV_PRIME = cls.FNV_PRIME + U32_MAX = cls.U32_MAX + for obyte in memoryview(key): basis ^= obyte # xor-in the byte - basis *= cls.FNV_PRIME # Multiply by the FNV prime - basis &= cls.U32_MAX # clamp to 32-bits + basis *= FNV_PRIME # Multiply by the FNV prime + basis &= U32_MAX # clamp to 32-bits return basis def key(self, entry): - return memoryview(ensure_bytes(self._key(entry))) + return memoryview(self._key(entry)) def get_raw_index(self, key): """Determine the index in self.entries without validating""" @@ -145,7 +134,7 @@ class PerfectHash(object): def get_index(self, key): """Given a key, determine the index in self.entries""" idx = self.get_raw_index(key) - if memoryview(ensure_bytes(key)) != self.key(self.entries[idx]): + if memoryview(key) != self.key(self.entries[idx]): return None return idx @@ -334,7 +323,7 @@ class CGHelper(object): not in the table.""" assert all( - _ord(b) <= 0x7F for e in self.phf.entries for b in self.phf.key(e) + b <= 0x7F for e in self.phf.entries for b in self.phf.key(e) ), "non-ASCII key" if return_type is None: diff --git a/xpcom/idl-parser/xpidl/fixtures/xpctest.d.json b/xpcom/idl-parser/xpidl/fixtures/xpctest.d.json new file mode 100644 index 0000000000..fb3cb7e6b7 --- /dev/null +++ b/xpcom/idl-parser/xpidl/fixtures/xpctest.d.json @@ -0,0 +1,1402 @@ +[ + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestObjectReadOnly", + "members": [ + { + "name": "strReadOnly", + "readonly": true, + "type": "string" + }, + { + "name": "boolReadOnly", + "readonly": true, + "type": "boolean" + }, + { + "name": "shortReadOnly", + "readonly": true, + "type": "i16" + }, + { + "name": "longReadOnly", + "readonly": true, + "type": "i32" + }, + { + "name": "floatReadOnly", + "readonly": true, + "type": "float" + }, + { + "name": "charReadOnly", + "readonly": true, + "type": "string" + }, + { + "name": "timeReadOnly", + "readonly": true, + "type": "PRTime" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestObjectReadWrite", + "members": [ + { + "name": "stringProperty", + "readonly": false, + "type": "string" + }, + { + "name": "booleanProperty", + "readonly": false, + "type": "boolean" + }, + { + "name": "shortProperty", + "readonly": false, + "type": "i16" + }, + { + "name": "longProperty", + "readonly": false, + "type": "i32" + }, + { + "name": "floatProperty", + "readonly": false, + "type": "float" + }, + { + "name": "charProperty", + "readonly": false, + "type": "string" + }, + { + "name": "timeProperty", + "readonly": false, + "type": "PRTime" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_attributes.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestBug809674", + "members": [ + { + "args": [ + { + "name": "x", + "optional": false, + "type": "u32" + }, + { + "name": "y", + "optional": false, + "type": "u32" + } + ], + "iid_is": null, + "name": "addArgs", + "type": "u32" + }, + { + "args": [ + { + "name": "x", + "optional": false, + "type": "u32" + }, + { + "name": "y", + "optional": false, + "type": "u32" + }, + { + "name": "subOut", + "optional": false, + "type": "OutParam<u32>" + }, + { + "name": "mulOut", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "addSubMulArgs", + "type": "u32" + }, + { + "args": [ + { + "name": "x", + "optional": false, + "type": "any" + }, + { + "name": "y", + "optional": false, + "type": "any" + } + ], + "iid_is": null, + "name": "addVals", + "type": "any" + }, + { + "args": [], + "iid_is": null, + "name": "methodNoArgs", + "type": "u32" + }, + { + "args": [], + "iid_is": null, + "name": "methodNoArgsNoRetVal", + "type": "void" + }, + { + "args": [ + { + "name": "x1", + "optional": false, + "type": "u32" + }, + { + "name": "x2", + "optional": false, + "type": "u32" + }, + { + "name": "x3", + "optional": false, + "type": "u32" + }, + { + "name": "x4", + "optional": false, + "type": "u32" + }, + { + "name": "x5", + "optional": false, + "type": "u32" + }, + { + "name": "x6", + "optional": false, + "type": "u32" + }, + { + "name": "x7", + "optional": false, + "type": "u32" + }, + { + "name": "x8", + "optional": false, + "type": "u32" + } + ], + "iid_is": null, + "name": "addMany", + "type": "u32" + }, + { + "name": "valProperty", + "readonly": false, + "type": "any" + }, + { + "name": "uintProperty", + "readonly": false, + "type": "u32" + }, + { + "args": [], + "iid_is": null, + "name": "methodWithOptionalArgc", + "type": "void" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_bug809674.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [ + { + "name": "testConst", + "value": 1 + } + ], + "enums": [ + { + "id": "testFlagsExplicit", + "variants": [ + { + "name": "shouldBe1Explicit", + "value": 1 + }, + { + "name": "shouldBe2Explicit", + "value": 2 + }, + { + "name": "shouldBe4Explicit", + "value": 4 + }, + { + "name": "shouldBe8Explicit", + "value": 8 + }, + { + "name": "shouldBe12Explicit", + "value": 12 + } + ] + }, + { + "id": "testFlagsImplicit", + "variants": [ + { + "name": "shouldBe0Implicit", + "value": 0 + }, + { + "name": "shouldBe1Implicit", + "value": 1 + }, + { + "name": "shouldBe2Implicit", + "value": 2 + }, + { + "name": "shouldBe3Implicit", + "value": 3 + }, + { + "name": "shouldBe5Implicit", + "value": 5 + }, + { + "name": "shouldBe6Implicit", + "value": 6 + }, + { + "name": "shouldBe2AgainImplicit", + "value": 2 + }, + { + "name": "shouldBe3AgainImplicit", + "value": 3 + } + ] + } + ], + "id": "nsIXPCTestCEnums", + "members": [ + { + "args": [ + { + "name": "abc", + "optional": false, + "type": "nsIXPCTestCEnums.testFlagsExplicit" + } + ], + "iid_is": null, + "name": "testCEnumInput", + "type": "void" + }, + { + "args": [], + "iid_is": null, + "name": "testCEnumOutput", + "type": "nsIXPCTestCEnums.testFlagsExplicit" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_cenums.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestInterfaceA", + "members": [ + { + "name": "name", + "readonly": false, + "type": "string" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestInterfaceB", + "members": [ + { + "name": "name", + "readonly": false, + "type": "string" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestInterfaceC", + "members": [ + { + "name": "someInteger", + "readonly": false, + "type": "i32" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_interfaces.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestParams", + "members": [ + { + "args": [ + { + "name": "a", + "optional": false, + "type": "boolean" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<boolean>" + } + ], + "iid_is": null, + "name": "testBoolean", + "type": "boolean" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "u8" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<u8>" + } + ], + "iid_is": null, + "name": "testOctet", + "type": "u8" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "i16" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i16>" + } + ], + "iid_is": null, + "name": "testShort", + "type": "i16" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "i32" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i32>" + } + ], + "iid_is": null, + "name": "testLong", + "type": "i32" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "i64" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i64>" + } + ], + "iid_is": null, + "name": "testLongLong", + "type": "i64" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "u16" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<u16>" + } + ], + "iid_is": null, + "name": "testUnsignedShort", + "type": "u16" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "u32" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<u32>" + } + ], + "iid_is": null, + "name": "testUnsignedLong", + "type": "u32" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "u64" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<u64>" + } + ], + "iid_is": null, + "name": "testUnsignedLongLong", + "type": "u64" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "float" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<float>" + } + ], + "iid_is": null, + "name": "testFloat", + "type": "float" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "double" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<float>" + } + ], + "iid_is": null, + "name": "testDouble", + "type": "double" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testChar", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testString", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testWchar", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testWstring", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testAString", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testAUTF8String", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + } + ], + "iid_is": null, + "name": "testACString", + "type": "string" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "any" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<any>" + } + ], + "iid_is": null, + "name": "testJsval", + "type": "any" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "i16[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i16[]>" + } + ], + "iid_is": null, + "name": "testShortSequence", + "type": "i16[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "double[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<double[]>" + } + ], + "iid_is": null, + "name": "testDoubleSequence", + "type": "double[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "nsIXPCTestInterfaceA[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<nsIXPCTestInterfaceA[]>" + } + ], + "iid_is": null, + "name": "testInterfaceSequence", + "type": "nsIXPCTestInterfaceA[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string[]>" + } + ], + "iid_is": null, + "name": "testAStringSequence", + "type": "string[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string[]>" + } + ], + "iid_is": null, + "name": "testACStringSequence", + "type": "string[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "any[]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<any[]>" + } + ], + "iid_is": null, + "name": "testJsvalSequence", + "type": "any[]" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "i16[][]" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i16[][]>" + } + ], + "iid_is": null, + "name": "testSequenceSequence", + "type": "i16[][]" + }, + { + "args": [ + { + "name": "arr", + "optional": true, + "type": "u8[]" + } + ], + "iid_is": null, + "name": "testOptionalSequence", + "type": "u8[]" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "i16[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<i16[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testShortArray", + "type": "OutParam<i16[]>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "double[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<double[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testDoubleArray", + "type": "OutParam<double[]>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "string[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testStringArray", + "type": "OutParam<string[]>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "string[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testWstringArray", + "type": "OutParam<string[]>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "nsIXPCTestInterfaceA[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<nsIXPCTestInterfaceA[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testInterfaceArray", + "type": "OutParam<nsIXPCTestInterfaceA[]>" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "u8[]" + }, + { + "name": "aLength", + "optional": true, + "type": "u32" + } + ], + "iid_is": null, + "name": "testByteArrayOptionalLength", + "type": "u32" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testSizedString", + "type": "OutParam<string>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "string" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<string>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testSizedWstring", + "type": "OutParam<string>" + }, + { + "args": [ + { + "name": "aLength", + "optional": false, + "type": "u32" + }, + { + "name": "a", + "optional": false, + "type": "any[]" + }, + { + "name": "bLength", + "optional": false, + "type": "InOutParam<u32>" + }, + { + "name": "b", + "optional": false, + "type": "InOutParam<any[]>" + }, + { + "name": "rvLength", + "optional": false, + "type": "OutParam<u32>" + } + ], + "iid_is": null, + "name": "testJsvalArray", + "type": "OutParam<any[]>" + }, + { + "args": [ + { + "name": "o", + "optional": false, + "type": "OutParam<string>" + } + ], + "iid_is": null, + "name": "testOutAString", + "type": "void" + }, + { + "args": [ + { + "name": "a", + "optional": false, + "type": "string[]" + }, + { + "name": "aLength", + "optional": true, + "type": "u32" + } + ], + "iid_is": null, + "name": "testStringArrayOptionalSize", + "type": "string" + }, + { + "args": [ + { + "name": "aJSObj", + "optional": false, + "type": "nsIXPCTestParams" + }, + { + "name": "aOut", + "optional": true, + "type": "OutParam<nsIURI>" + } + ], + "iid_is": null, + "name": "testOmittedOptionalOut", + "type": "void" + }, + { + "name": "testNaN", + "readonly": true, + "type": "double" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_params.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestReturnCodeParent", + "members": [ + { + "args": [ + { + "name": "childBehavior", + "optional": false, + "type": "i32" + } + ], + "iid_is": null, + "name": "callChild", + "type": "nsresult" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [ + { + "name": "CHILD_SHOULD_THROW", + "value": 0 + }, + { + "name": "CHILD_SHOULD_RETURN_SUCCESS", + "value": 1 + }, + { + "name": "CHILD_SHOULD_RETURN_RESULTCODE", + "value": 2 + }, + { + "name": "CHILD_SHOULD_NEST_RESULTCODES", + "value": 3 + } + ], + "enums": [], + "id": "nsIXPCTestReturnCodeChild", + "members": [ + { + "args": [ + { + "name": "behavior", + "optional": false, + "type": "i32" + } + ], + "iid_is": null, + "name": "doIt", + "type": "void" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_returncode.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + }, + { + "interfaces": [ + { + "base": "nsISupports", + "callable": true, + "consts": [], + "enums": [], + "id": "nsIXPCTestFunctionInterface", + "members": [ + { + "args": [ + { + "name": "arg", + "optional": false, + "type": "string" + } + ], + "iid_is": null, + "name": "echo", + "type": "string" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestUtils", + "members": [ + { + "args": [ + { + "name": "f", + "optional": false, + "type": "nsIXPCTestFunctionInterface" + } + ], + "iid_is": null, + "name": "doubleWrapFunction", + "type": "nsIXPCTestFunctionInterface" + } + ] + }, + { + "base": "nsISupports", + "callable": false, + "consts": [], + "enums": [], + "id": "nsIXPCTestNoScriptMembers", + "members": [ + { + "name": "exposedProp", + "readonly": false, + "type": "i32" + }, + { + "args": [ + { + "name": "arg", + "optional": false, + "type": "i32" + } + ], + "iid_is": null, + "name": "exposedMethod", + "type": "void" + } + ] + } + ], + "path": "js/xpconnect/tests/idl/xpctest_utils.idl", + "typedefs": [ + [ + "PRTime", + "i64" + ], + [ + "char16_t", + "u16" + ], + [ + "nsresult", + "u32" + ] + ] + } +]
\ No newline at end of file diff --git a/xpcom/idl-parser/xpidl/header.py b/xpcom/idl-parser/xpidl/header.py index ed179b1bad..7f6c65dfc0 100644 --- a/xpcom/idl-parser/xpidl/header.py +++ b/xpcom/idl-parser/xpidl/header.py @@ -339,6 +339,8 @@ def print_header(idl, fd, filename, relpath): write_interface(p, fd) continue if p.kind == "typedef": + if p.substitute: + continue printComments(fd, p.doccomments, "") fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType("in"), p.name)) diff --git a/xpcom/idl-parser/xpidl/runtests.py b/xpcom/idl-parser/xpidl/runtests.py index 2dd269dfd9..b889d40010 100755 --- a/xpcom/idl-parser/xpidl/runtests.py +++ b/xpcom/idl-parser/xpidl/runtests.py @@ -5,6 +5,8 @@ # # Unit tests for xpidl.py +import json +import os import sys # Hack: the first entry in sys.path is the directory containing the script. @@ -16,7 +18,7 @@ import unittest import mozunit -from xpidl import header, xpidl +from xpidl import header, typescript, xpidl class TestParser(unittest.TestCase): @@ -253,5 +255,42 @@ attribute long bar; self.assertEqual(e.args[0], ("cannot find symbol 'Y'")) +class TestTypescript(unittest.TestCase): + """A few basic smoke tests for typescript generation.""" + + dir = os.path.dirname(__file__) + src = os.path.join(dir, "..", "..", "..") + + # We use the xpctest.xpt *.idl files from: + tests_dir = os.path.join(src, "js/xpconnect/tests/idl") + files = [ + "xpctest_attributes.idl", + "xpctest_bug809674.idl", + "xpctest_cenums.idl", + "xpctest_interfaces.idl", + "xpctest_params.idl", + "xpctest_returncode.idl", + "xpctest_utils.idl", + ] + + fixtures = os.path.join(dir, "fixtures") + inc_dirs = [os.path.join(src, "xpcom/base")] + + def setUp(self): + self.parser = xpidl.IDLParser() + + def test_d_json(self): + mods = [] + for file in self.files: + path = os.path.join(self.tests_dir, file) + idl = self.parser.parse(open(path).read(), path) + idl.resolve(self.inc_dirs, self.parser, {}) + mods.append(typescript.ts_source(idl)) + + result = json.dumps(mods, indent=2, sort_keys=True) + expected = open(os.path.join(self.fixtures, "xpctest.d.json")).read() + self.assertEqual(result, expected, "types data json does not match") + + if __name__ == "__main__": mozunit.main(runwith="unittest") diff --git a/xpcom/idl-parser/xpidl/rust.py b/xpcom/idl-parser/xpidl/rust.py index b9fc6627fb..5d906d85ea 100644 --- a/xpcom/idl-parser/xpidl/rust.py +++ b/xpcom/idl-parser/xpidl/rust.py @@ -363,8 +363,8 @@ def print_rust_bindings(idl, fd, relpath): if p.kind == "typedef": try: - # We have to skip the typedef of bool to bool (it doesn't make any sense anyways) - if p.name == "bool": + # Skip bool and C++ stdint typedefs marked with [substitute]. + if p.substitute: continue if printdoccomments: diff --git a/xpcom/idl-parser/xpidl/typescript.py b/xpcom/idl-parser/xpidl/typescript.py new file mode 100644 index 0000000000..614a328edf --- /dev/null +++ b/xpcom/idl-parser/xpidl/typescript.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# typescript.py - Collect .d.json TypeScript info from xpidl. +# +# 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/. + +import json + +import mozpack.path as mozpath + +from xpidl import xpidl + + +def ts_enum(e): + variants = [{"name": v.name, "value": v.getValue()} for v in e.variants] + return {"id": e.basename, "variants": variants} + + +def ts_attribute(a): + return {"name": a.name, "type": a.realtype.tsType(), "readonly": a.readonly} + + +def ts_method(m): + args = [] + for p in m.params: + if p.iid_is and not p.retval: + raise xpidl.TSNoncompat(f"{m.name} has unsupported iid_is argument") + args.append({"name": p.name, "optional": p.optional, "type": p.tsType()}) + + iid_is = None + type = m.realtype.tsType() + if args and m.params[-1].retval: + type = args.pop()["type"] + iid_is = m.params[-1].iid_is + + return {"name": m.name, "type": type, "iid_is": iid_is, "args": args} + + +def ts_interface(iface): + enums = [] + consts = [] + members = [] + + for m in iface.members: + try: + if isinstance(m, xpidl.CEnum): + enums.append(ts_enum(m)) + elif isinstance(m, xpidl.ConstMember): + consts.append({"name": m.name, "value": m.getValue()}) + elif isinstance(m, xpidl.Attribute) and m.isScriptable(): + members.append(ts_attribute(m)) + elif isinstance(m, xpidl.Method) and m.isScriptable(): + members.append(ts_method(m)) + except xpidl.TSNoncompat: + # Omit member if any type is unsupported. + pass + + return { + "id": iface.name, + "base": iface.base, + "callable": iface.attributes.function, + "enums": enums, + "consts": consts, + "members": members, + } + + +def ts_typedefs(idl): + for p in idl.getNames(): + if isinstance(p, xpidl.Typedef) and not p.substitute: + try: + yield (p.name, p.realtype.tsType()) + except xpidl.TSNoncompat: + pass + + +def ts_source(idl): + """Collect typescript interface .d.json from a source idl file.""" + root = mozpath.join(mozpath.dirname(__file__), "../../..") + return { + "path": mozpath.relpath(idl.productions[0].location._file, root), + "interfaces": [ + ts_interface(p) + for p in idl.productions + if isinstance(p, xpidl.Interface) and p.attributes.scriptable + ], + "typedefs": sorted(ts_typedefs(idl)), + } + + +def write(d_json, fd): + """Write json type info into fd""" + json.dump(d_json, fd, indent=2, sort_keys=True) diff --git a/xpcom/idl-parser/xpidl/xpidl.py b/xpcom/idl-parser/xpidl/xpidl.py index b95fd14bc5..19d042d1b0 100755 --- a/xpcom/idl-parser/xpidl/xpidl.py +++ b/xpcom/idl-parser/xpidl/xpidl.py @@ -122,10 +122,13 @@ class Builtin(object): kind = "builtin" location = BuiltinLocation - def __init__(self, name, nativename, rustname, signed=False, maybeConst=False): + def __init__( + self, name, nativename, rustname, tsname, signed=False, maybeConst=False + ): self.name = name self.nativename = nativename self.rustname = rustname + self.tsname = tsname self.signed = signed self.maybeConst = maybeConst @@ -171,28 +174,37 @@ class Builtin(object): return "%s%s" % ("*mut " if "out" in calltype else "", rustname) + def tsType(self): + if self.tsname: + return self.tsname + + raise TSNoncompat(f"Builtin type {self.name} unsupported in TypeScript") + builtinNames = [ - Builtin("boolean", "bool", "bool"), - Builtin("void", "void", "libc::c_void"), - Builtin("octet", "uint8_t", "u8", False, True), - Builtin("short", "int16_t", "i16", True, True), - Builtin("long", "int32_t", "i32", True, True), - Builtin("long long", "int64_t", "i64", True, True), - Builtin("unsigned short", "uint16_t", "u16", False, True), - Builtin("unsigned long", "uint32_t", "u32", False, True), - Builtin("unsigned long long", "uint64_t", "u64", False, True), - Builtin("float", "float", "libc::c_float", True, False), - Builtin("double", "double", "libc::c_double", True, False), - Builtin("char", "char", "libc::c_char", True, False), - Builtin("string", "char *", "*const libc::c_char", False, False), - Builtin("wchar", "char16_t", "u16", False, False), - Builtin("wstring", "char16_t *", "*const u16", False, False), + Builtin("boolean", "bool", "bool", "boolean"), + Builtin("void", "void", "libc::c_void", "void"), + Builtin("octet", "uint8_t", "u8", "u8", False, True), + Builtin("short", "int16_t", "i16", "i16", True, True), + Builtin("long", "int32_t", "i32", "i32", True, True), + Builtin("long long", "int64_t", "i64", "i64", True, True), + Builtin("unsigned short", "uint16_t", "u16", "u16", False, True), + Builtin("unsigned long", "uint32_t", "u32", "u32", False, True), + Builtin("unsigned long long", "uint64_t", "u64", "u64", False, True), + Builtin("float", "float", "libc::c_float", "float"), + Builtin("double", "double", "libc::c_double", "double"), + Builtin("char", "char", "libc::c_char", "string"), + Builtin("string", "char *", "*const libc::c_char", "string"), + Builtin("wchar", "char16_t", "u16", "string"), + Builtin("wstring", "char16_t *", "*const u16", "string"), # As seen in mfbt/RefCountType.h, this type has special handling to # maintain binary compatibility with MSCOM's IUnknown that cannot be # expressed in XPIDL. Builtin( - "MozExternalRefCountType", "MozExternalRefCountType", "MozExternalRefCountType" + "MozExternalRefCountType", + "MozExternalRefCountType", + "MozExternalRefCountType", + None, ), ] @@ -308,6 +320,16 @@ class RustNoncompat(Exception): return self.reason +class TSNoncompat(Exception): + """Raised when a type cannot be exposed to TypeScript.""" + + def __init__(self, reason): + self.reason = reason + + def __str__(self): + return self.reason + + class IDLError(Exception): def __init__(self, message, location, warning=False, notes=None): self.message = message @@ -458,12 +480,20 @@ class CDATA(object): class Typedef(object): kind = "typedef" - def __init__(self, type, name, location, doccomments): + def __init__(self, type, name, attlist, location, doccomments): self.type = type self.name = name self.location = location self.doccomments = doccomments + # C++ stdint types and the bool typedef from nsrootidl.idl are marked + # with [substitute], and emit as the underlying builtin type directly. + self.substitute = False + for name, value, aloc in attlist: + if name != "substitute" or value is not None: + raise IDLError(f"Unexpected attribute {name}({value})", aloc) + self.substitute = True + def __eq__(self, other): return self.name == other.name and self.type == other.type @@ -475,14 +505,26 @@ class Typedef(object): raise IDLError("Unsupported typedef target type", self.location) def nativeType(self, calltype): + if self.substitute: + return self.realtype.nativeType(calltype) + return "%s %s" % (self.name, "*" if "out" in calltype else "") def rustType(self, calltype): + if self.substitute: + return self.realtype.rustType(calltype) + if self.name == "nsresult": return "%s::nserror::nsresult" % ("*mut " if "out" in calltype else "") return "%s%s" % ("*mut " if "out" in calltype else "", self.name) + def tsType(self): + if self.substitute: + return self.realtype.tsType() + + return self.name + def __str__(self): return "typedef %s %s\n" % (self.type, self.name) @@ -524,6 +566,9 @@ class Forward(object): return "Option<RefPtr<%s>>" % self.name return "%s*const %s" % ("*mut" if "out" in calltype else "", self.name) + def tsType(self): + return self.name + def __str__(self): return "forward-declared %s\n" % self.name @@ -701,6 +746,21 @@ class Native(object): raise RustNoncompat("native type %s unsupported" % self.nativename) + ts_special = { + "astring": "string", + "cstring": "string", + "jsval": "any", + "nsid": "nsID", + "promise": "Promise<any>", + "utf8string": "string", + } + + def tsType(self): + if type := self.ts_special.get(self.specialtype, None): + return type + + raise TSNoncompat(f"Native type {self.name} unsupported in TypeScript") + def __str__(self): return "native %s(%s)\n" % (self.name, self.nativename) @@ -749,6 +809,9 @@ class WebIDL(object): # Just expose the type as a void* - we can't do any better. return "%s*const libc::c_void" % ("*mut " if "out" in calltype else "") + def tsType(self): + return self.name + def __str__(self): return "webidl %s\n" % self.name @@ -923,6 +986,9 @@ class Interface(object): total += realbase.countEntries() return total + def tsType(self): + return self.name + class InterfaceAttributes(object): uuid = None @@ -1110,6 +1176,9 @@ class CEnum(object): def rustType(self, calltype): return "%s u%d" % ("*mut" if "out" in calltype else "", self.width) + def tsType(self): + return f"{self.iface.name}.{self.basename}" + def __str__(self): body = ", ".join("%s = %s" % v for v in self.variants) return "\tcenum %s : %d { %s };\n" % (self.name, self.width, body) @@ -1523,8 +1592,22 @@ class Param(object): self.name, ) + def tsType(self): + # A generic retval param type needs special handling. + if self.retval and self.iid_is: + return "nsQIResult" + + type = self.realtype.tsType() + if self.paramtype == "inout": + return f"InOutParam<{type}>" + if self.paramtype == "out": + return f"OutParam<{type}>" + return type + class LegacyArray(object): + kind = "legacyarray" + def __init__(self, basetype): self.type = basetype self.location = self.type.location @@ -1555,6 +1638,9 @@ class LegacyArray(object): self.type.rustType("legacyelement"), ) + def tsType(self): + return self.type.tsType() + "[]" + class Array(object): kind = "array" @@ -1594,6 +1680,9 @@ class Array(object): else: return base + def tsType(self): + return self.type.tsType() + "[]" + TypeId = namedtuple("TypeId", "name params") @@ -1751,12 +1840,13 @@ class IDLParser(object): p[0].insert(0, p[1]) def p_typedef(self, p): - """typedef : TYPEDEF type IDENTIFIER ';'""" + """typedef : attributes TYPEDEF type IDENTIFIER ';'""" p[0] = Typedef( - type=p[2], - name=p[3], - location=self.getLocation(p, 1), - doccomments=p.slice[1].doccomments, + type=p[3], + name=p[4], + attlist=p[1]["attlist"], + location=self.getLocation(p, 2), + doccomments=getattr(p[1], "doccomments", []) + p.slice[2].doccomments, ) def p_native(self, p): diff --git a/xpcom/io/CocoaFileUtils.mm b/xpcom/io/CocoaFileUtils.mm index 3710be864c..f45da3ec66 100644 --- a/xpcom/io/CocoaFileUtils.mm +++ b/xpcom/io/CocoaFileUtils.mm @@ -309,7 +309,7 @@ void CopyQuarantineReferrerUrl(const CFStringRef aFilePath, ::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey); if (referrerRef && ::CFGetTypeID(referrerRef) == ::CFURLGetTypeID()) { // URL string must be copied prior to releasing the dictionary. - mozilla::CopyCocoaStringToXPCOMString( + mozilla::CopyNSStringToXPCOMString( (NSString*)::CFURLGetString(static_cast<CFURLRef>(referrerRef)), aReferrer); } diff --git a/xpcom/io/nsLocalFileCommon.cpp b/xpcom/io/nsLocalFileCommon.cpp index f6eabf2d0f..7e9d7151c1 100644 --- a/xpcom/io/nsLocalFileCommon.cpp +++ b/xpcom/io/nsLocalFileCommon.cpp @@ -139,7 +139,8 @@ const char* const sExecutableExts[] = { ".wsc", ".wsf", ".wsh", - ".xll" // MS Excel dynamic link library + ".xll", // MS Excel dynamic link library + ".xrm-ms" // clang-format on }; diff --git a/xpcom/io/nsLocalFileCommon.h b/xpcom/io/nsLocalFileCommon.h index 3db0ac9e89..96b7e1f06a 100644 --- a/xpcom/io/nsLocalFileCommon.h +++ b/xpcom/io/nsLocalFileCommon.h @@ -8,9 +8,9 @@ #define _NS_LOCAL_FILE_COMMON_H_ #ifdef MOZ_ESR -extern const char* const sExecutableExts[107]; -#else extern const char* const sExecutableExts[108]; +#else +extern const char* const sExecutableExts[109]; #endif #endif diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp b/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp index 61bb7b2efd..e73dd023cb 100644 --- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp @@ -44,7 +44,9 @@ extern "C" void invoke_copy_to_stack(uint64_t* gpregs, double* fpregs, value = s->val.u16; break; case nsXPTType::T_U32: - value = s->val.u32; + // 32-bit values need to be sign-extended in 64-bit registers, + // so use the signed value here. + value = s->val.i32; break; case nsXPTType::T_U64: value = s->val.u64; diff --git a/xpcom/system/nsIDeviceSensors.idl b/xpcom/system/nsIDeviceSensors.idl index dcb67cb925..a173421ebf 100644 --- a/xpcom/system/nsIDeviceSensors.idl +++ b/xpcom/system/nsIDeviceSensors.idl @@ -51,10 +51,6 @@ interface nsIDeviceSensors : nsISupports %{C++ -#define NS_DEVICE_SENSORS_CID \ -{ 0xecba5203, 0x77da, 0x465a, \ -{ 0x86, 0x5e, 0x78, 0xb7, 0xaf, 0x10, 0xd8, 0xf7 } } - #define NS_DEVICE_SENSORS_CONTRACTID "@mozilla.org/devicesensors;1" %} diff --git a/xpcom/system/nsIXULRuntime.idl b/xpcom/system/nsIXULRuntime.idl index 8beadae9f1..9d187bcbba 100644 --- a/xpcom/system/nsIXULRuntime.idl +++ b/xpcom/system/nsIXULRuntime.idl @@ -30,6 +30,10 @@ bool FissionExperimentEnrolled(); // fission.disableSessionHistoryInParent is false. bool SessionHistoryInParent(); +// Returns true if SessionHistoryInParent() is true and +// browser.sessionstore.disable_platform_collection is false. +bool SessionStorePlatformCollection(); + // Returns true if SessionHistoryInParent() returns true and // fission.bfcacheInParent is true. bool BFCacheInParent(); @@ -169,6 +173,11 @@ interface nsIXULRuntime : nsISupports readonly attribute boolean sessionHistoryInParent; /** + * Whether Gecko code drives session store collection data. + */ + readonly attribute boolean sessionStorePlatformCollection; + + /** * Whether to write console errors to a log file. If a component * encounters startup errors that might prevent the app from showing * proper UI, it should set this flag to "true". diff --git a/xpcom/tests/gtest/TestAutoOwningEventTarget.cpp b/xpcom/tests/gtest/TestAutoOwningEventTarget.cpp new file mode 100644 index 0000000000..2bd34ecfee --- /dev/null +++ b/xpcom/tests/gtest/TestAutoOwningEventTarget.cpp @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:cindent:ts=4:et:sw=4: +/* 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 "nsCOMPtr.h" +#include "nsISupportsImpl.h" +#include "nsNetCID.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "gtest/gtest.h" +#include "mozilla/SyncRunnable.h" +#include "mozilla/TaskQueue.h" +#include "mozilla/gtest/MozAssertions.h" + +namespace TestAutoOwningEventTarget { + +using namespace mozilla; + +#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED + +namespace { + +static MozExternalRefCountType GetRefCount(nsISupports* aSupports) { + aSupports->AddRef(); + return aSupports->Release(); +} + +void CheckAutoOwningEventTarget( + nsISerialEventTarget* aSerialEventTarget, + const nsAutoOwningEventTarget& aAutoOwningEventTarget, + const bool aIsCurrent) { + ASSERT_TRUE(aSerialEventTarget); + + ASSERT_EQ(aAutoOwningEventTarget.IsCurrentThread(), aIsCurrent); + + { + const auto refCountBefore = GetRefCount(aSerialEventTarget); + + { + nsAutoOwningEventTarget copyConstructedEventTarget( + aAutoOwningEventTarget); + ASSERT_EQ(copyConstructedEventTarget.IsCurrentThread(), aIsCurrent); + } + + const auto refCountAfter = GetRefCount(aSerialEventTarget); + + ASSERT_GE(refCountAfter, refCountBefore); + ASSERT_EQ(refCountAfter - refCountBefore, 0u); + } + + { + const auto refCountBefore = GetRefCount(aSerialEventTarget); + + { + nsAutoOwningEventTarget copyAssignedEventTarget; + ASSERT_TRUE(copyAssignedEventTarget.IsCurrentThread()); + + copyAssignedEventTarget = aAutoOwningEventTarget; + ASSERT_EQ(copyAssignedEventTarget.IsCurrentThread(), aIsCurrent); + } + + const auto refCountAfter = GetRefCount(aSerialEventTarget); + + ASSERT_GE(refCountAfter, refCountBefore); + ASSERT_EQ(refCountAfter - refCountBefore, 0u); + } +} + +} // namespace + +TEST(TestAutoOwningEventTarget, Simple) +{ + { + nsAutoOwningEventTarget autoOwningEventTarget; + + ASSERT_NO_FATAL_FAILURE(CheckAutoOwningEventTarget( + GetCurrentSerialEventTarget(), autoOwningEventTarget, + /* aIsCurrent */ true)); + } +} + +TEST(TestAutoOwningEventTarget, TaskQueue) +{ + nsresult rv; + nsCOMPtr<nsIEventTarget> threadPool = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + auto taskQueue = TaskQueue::Create(threadPool.forget(), "TestTaskQueue", + /* aSupportsTailDispatch */ false); + + nsAutoOwningEventTarget autoOwningEventTarget; + + // XXX This call can't be wrapped with ASSERT_NS_SUCCEEDED directly because + // base-toolchains builds fail with: error: duplicate label + // 'gtest_label_testnofatal_111' + rv = SyncRunnable::DispatchToThread( + taskQueue, + NS_NewRunnableFunction( + "TestRunnable", [taskQueue, &autoOwningEventTarget] { + { + ASSERT_NO_FATAL_FAILURE(CheckAutoOwningEventTarget( + taskQueue, autoOwningEventTarget, /* aIsCurrent */ false)); + } + + { + nsAutoOwningEventTarget autoOwningEventTarget; + + ASSERT_NO_FATAL_FAILURE(CheckAutoOwningEventTarget( + taskQueue, autoOwningEventTarget, /* aIsCurrent */ true)); + } + })); + ASSERT_NS_SUCCEEDED(rv); +} + +#endif + +} // namespace TestAutoOwningEventTarget diff --git a/xpcom/tests/gtest/TestThreadUtils.cpp b/xpcom/tests/gtest/TestThreadUtils.cpp index 2b9ff97192..96b1342885 100644 --- a/xpcom/tests/gtest/TestThreadUtils.cpp +++ b/xpcom/tests/gtest/TestThreadUtils.cpp @@ -885,122 +885,88 @@ TEST(ThreadUtils, IdleTaskRunner) TEST(ThreadUtils, TypeTraits) { - static_assert(!mozilla::IsRefcountedSmartPointer<int>::value, - "IsRefcountedSmartPointer<int> should be false"); - static_assert(mozilla::IsRefcountedSmartPointer<RefPtr<int>>::value, - "IsRefcountedSmartPointer<RefPtr<...>> should be true"); - static_assert(mozilla::IsRefcountedSmartPointer<const RefPtr<int>>::value, - "IsRefcountedSmartPointer<const RefPtr<...>> should be true"); - static_assert( - mozilla::IsRefcountedSmartPointer<volatile RefPtr<int>>::value, - "IsRefcountedSmartPointer<volatile RefPtr<...>> should be true"); - static_assert( - mozilla::IsRefcountedSmartPointer<const volatile RefPtr<int>>::value, - "IsRefcountedSmartPointer<const volatile RefPtr<...>> should be true"); - static_assert(mozilla::IsRefcountedSmartPointer<nsCOMPtr<int>>::value, - "IsRefcountedSmartPointer<nsCOMPtr<...>> should be true"); - static_assert(mozilla::IsRefcountedSmartPointer<const nsCOMPtr<int>>::value, - "IsRefcountedSmartPointer<const nsCOMPtr<...>> should be true"); - static_assert( - mozilla::IsRefcountedSmartPointer<volatile nsCOMPtr<int>>::value, - "IsRefcountedSmartPointer<volatile nsCOMPtr<...>> should be true"); - static_assert( - mozilla::IsRefcountedSmartPointer<const volatile nsCOMPtr<int>>::value, - "IsRefcountedSmartPointer<const volatile nsCOMPtr<...>> should be true"); - - static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>::Type>, - "RemoveSmartPointer<int>::Type should be int"); - static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>::Type>, - "RemoveSmartPointer<int*>::Type should be int*"); - static_assert( - std::is_same_v<UniquePtr<int>, - mozilla::RemoveSmartPointer<UniquePtr<int>>::Type>, - "RemoveSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>"); - static_assert( - std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>::Type>, - "RemoveSmartPointer<RefPtr<int>>::Type should be int"); - static_assert( - std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>::Type>, - "RemoveSmartPointer<const RefPtr<int>>::Type should be int"); + static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>>, + "RemoveSmartPointer<int> should be int"); + static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>>, + "RemoveSmartPointer<int*> should be int*"); + static_assert(std::is_same_v<UniquePtr<int>, + mozilla::RemoveSmartPointer<UniquePtr<int>>>, + "RemoveSmartPointer<UniquePtr<int>> should be UniquePtr<int>"); + static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>>, + "RemoveSmartPointer<RefPtr<int>> should be int"); + static_assert( + std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>>, + "RemoveSmartPointer<const RefPtr<int>> should be int"); + static_assert( + std::is_same_v<int, mozilla::RemoveSmartPointer<volatile RefPtr<int>>>, + "RemoveSmartPointer<volatile RefPtr<int>> should be int"); static_assert( std::is_same_v<int, - mozilla::RemoveSmartPointer<volatile RefPtr<int>>::Type>, - "RemoveSmartPointer<volatile RefPtr<int>>::Type should be int"); - static_assert( - std::is_same_v< - int, mozilla::RemoveSmartPointer<const volatile RefPtr<int>>::Type>, - "RemoveSmartPointer<const volatile RefPtr<int>>::Type should be int"); + mozilla::RemoveSmartPointer<const volatile RefPtr<int>>>, + "RemoveSmartPointer<const volatile RefPtr<int>> should be int"); + static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>>, + "RemoveSmartPointer<nsCOMPtr<int>> should be int"); static_assert( - std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>::Type>, - "RemoveSmartPointer<nsCOMPtr<int>>::Type should be int"); + std::is_same_v<int, mozilla::RemoveSmartPointer<const nsCOMPtr<int>>>, + "RemoveSmartPointer<const nsCOMPtr<int>> should be int"); static_assert( - std::is_same_v<int, - mozilla::RemoveSmartPointer<const nsCOMPtr<int>>::Type>, - "RemoveSmartPointer<const nsCOMPtr<int>>::Type should be int"); + std::is_same_v<int, mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>>, + "RemoveSmartPointer<volatile nsCOMPtr<int>> should be int"); static_assert( std::is_same_v<int, - mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>::Type>, - "RemoveSmartPointer<volatile nsCOMPtr<int>>::Type should be int"); - static_assert( - std::is_same_v< - int, mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type>, - "RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type should be int"); + mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>>, + "RemoveSmartPointer<const volatile nsCOMPtr<int>> should be int"); - static_assert( - std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>::Type>, - "RemoveRawOrSmartPointer<int>::Type should be int"); + static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>>, + "RemoveRawOrSmartPointer<int> should be int"); static_assert( std::is_same_v<UniquePtr<int>, - mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>::Type>, - "RemoveRawOrSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>"); - static_assert( - std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>::Type>, - "RemoveRawOrSmartPointer<int*>::Type should be int"); + mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>>, + "RemoveRawOrSmartPointer<UniquePtr<int>> should be UniquePtr<int>"); + static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>>, + "RemoveRawOrSmartPointer<int*> should be int"); static_assert( - std::is_same_v<const int, - mozilla::RemoveRawOrSmartPointer<const int*>::Type>, - "RemoveRawOrSmartPointer<const int*>::Type should be const int"); + std::is_same_v<const int, mozilla::RemoveRawOrSmartPointer<const int*>>, + "RemoveRawOrSmartPointer<const int*> should be const int"); static_assert( std::is_same_v<volatile int, - mozilla::RemoveRawOrSmartPointer<volatile int*>::Type>, - "RemoveRawOrSmartPointer<volatile int*>::Type should be volatile int"); + mozilla::RemoveRawOrSmartPointer<volatile int*>>, + "RemoveRawOrSmartPointer<volatile int*> should be volatile int"); static_assert( - std::is_same_v<const volatile int, mozilla::RemoveRawOrSmartPointer< - const volatile int*>::Type>, - "RemoveRawOrSmartPointer<const volatile int*>::Type should be const " + std::is_same_v<const volatile int, + mozilla::RemoveRawOrSmartPointer<const volatile int*>>, + "RemoveRawOrSmartPointer<const volatile int*> should be const " "volatile int"); static_assert( - std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>::Type>, - "RemoveRawOrSmartPointer<RefPtr<int>>::Type should be int"); + std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>>, + "RemoveRawOrSmartPointer<RefPtr<int>> should be int"); + static_assert( + std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>>, + "RemoveRawOrSmartPointer<const RefPtr<int>> should be int"); static_assert( std::is_same_v<int, - mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>::Type>, - "RemoveRawOrSmartPointer<const RefPtr<int>>::Type should be int"); + mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>>, + "RemoveRawOrSmartPointer<volatile RefPtr<int>> should be int"); static_assert( std::is_same_v< - int, mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type>, - "RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type should be int"); - static_assert( - std::is_same_v<int, mozilla::RemoveRawOrSmartPointer< - const volatile RefPtr<int>>::Type>, - "RemoveRawOrSmartPointer<const volatile RefPtr<int>>::Type should be " + int, mozilla::RemoveRawOrSmartPointer<const volatile RefPtr<int>>>, + "RemoveRawOrSmartPointer<const volatile RefPtr<int>> should be " "int"); static_assert( + std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>>, + "RemoveRawOrSmartPointer<nsCOMPtr<int>> should be int"); + static_assert( std::is_same_v<int, - mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type>, - "RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type should be int"); + mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>>, + "RemoveRawOrSmartPointer<const nsCOMPtr<int>> should be int"); static_assert( - std::is_same_v< - int, mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type>, - "RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type should be int"); + std::is_same_v<int, + mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>>, + "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>> should be int"); static_assert( std::is_same_v< - int, mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type>, - "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type should be int"); - static_assert( - std::is_same_v<int, mozilla::RemoveRawOrSmartPointer< - const volatile nsCOMPtr<int>>::Type>, - "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>::Type should be " + int, mozilla::RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>>, + "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>> should be " "int"); } @@ -1289,15 +1255,9 @@ TEST(ThreadUtils, main) static_assert(!IsParameterStorageClass<int>::value, "'int' should not be recognized as Storage Class"); static_assert( - IsParameterStorageClass<StoreCopyPassByValue<int>>::value, - "StoreCopyPassByValue<int> should be recognized as Storage Class"); - static_assert( IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value, "StoreCopyPassByConstLRef<int> should be recognized as Storage Class"); static_assert( - IsParameterStorageClass<StoreCopyPassByLRef<int>>::value, - "StoreCopyPassByLRef<int> should be recognized as Storage Class"); - static_assert( IsParameterStorageClass<StoreCopyPassByRRef<int>>::value, "StoreCopyPassByRRef<int> should be recognized as Storage Class"); static_assert( @@ -1315,12 +1275,6 @@ TEST(ThreadUtils, main) static_assert( IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value, "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class"); - static_assert( - IsParameterStorageClass<StoreCopyPassByConstPtr<int>>::value, - "StoreCopyPassByConstPtr<int> should be recognized as Storage Class"); - static_assert( - IsParameterStorageClass<StoreCopyPassByPtr<int>>::value, - "StoreCopyPassByPtr<int> should be recognized as Storage Class"); RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject); int count = 0; @@ -1359,11 +1313,6 @@ TEST(ThreadUtils, main) StoreCopyPassByConstLRef<int>>, "detail::ParameterStorage<int>::Type should be " "StoreCopyPassByConstLRef<int>"); - static_assert(std::is_same_v< - ::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type, - StoreCopyPassByValue<int>>, - "detail::ParameterStorage<StoreCopyPassByValue<int>>::Type " - "should be StoreCopyPassByValue<int>"); r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt, &ThreadUtilsObject::Test1i, 12); @@ -1480,37 +1429,6 @@ TEST(ThreadUtils, main) EXPECT_EQ(i, rpt->mA0); } - // Raw pointer to copy. - static_assert(std::is_same_v<StoreCopyPassByPtr<int>::stored_type, int>, - "StoreCopyPassByPtr<int>::stored_type should be int"); - static_assert(std::is_same_v<StoreCopyPassByPtr<int>::passed_type, int*>, - "StoreCopyPassByPtr<int>::passed_type should be int*"); - { - int i = 1202; - r1 = NewRunnableMethod<StoreCopyPassByPtr<int>>( - "TestThreadUtils::ThreadUtilsObject::Test1pi", rpt, - &ThreadUtilsObject::Test1pi, i); - r1->Run(); - EXPECT_EQ(count += 2, rpt->mCount); - EXPECT_EQ(i, rpt->mA0); - } - - // Raw pointer to const copy. - static_assert(std::is_same_v<StoreCopyPassByConstPtr<int>::stored_type, int>, - "StoreCopyPassByConstPtr<int>::stored_type should be int"); - static_assert( - std::is_same_v<StoreCopyPassByConstPtr<int>::passed_type, const int*>, - "StoreCopyPassByConstPtr<int>::passed_type should be const int*"); - { - int i = 1203; - r1 = NewRunnableMethod<StoreCopyPassByConstPtr<int>>( - "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt, - &ThreadUtilsObject::Test1pci, i); - r1->Run(); - EXPECT_EQ(count += 2, rpt->mCount); - EXPECT_EQ(i, rpt->mA0); - } - // nsRefPtr to pointer. static_assert( std::is_same_v<::detail::ParameterStorage< @@ -1536,7 +1454,7 @@ TEST(ThreadUtils, main) // (more nsRefPtr tests below) // nsRefPtr for ref-countable classes that do not derive from ISupports. - static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>::value, + static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>, "ThreadUtilsRefCountedFinal has AddRef() and Release()"); static_assert( std::is_same_v< @@ -1544,7 +1462,7 @@ TEST(ThreadUtils, main) StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>, "ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be " "StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>"); - static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>::value, + static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>, "ThreadUtilsRefCountedBase has AddRef() and Release()"); static_assert( std::is_same_v< @@ -1552,9 +1470,8 @@ TEST(ThreadUtils, main) StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>, "ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be " "StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>"); - static_assert( - ::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>::value, - "ThreadUtilsRefCountedDerived has AddRef() and Release()"); + static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>, + "ThreadUtilsRefCountedDerived has AddRef() and Release()"); static_assert( std::is_same_v< ::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type, @@ -1562,7 +1479,7 @@ TEST(ThreadUtils, main) "ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be " "StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>"); - static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>::value, + static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>, "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()"); static_assert(!std::is_same_v< ::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type, @@ -1738,126 +1655,6 @@ TEST(ThreadUtils, main) Spy::ClearAll(); if (gDebug) { - printf("%d - Test: Store copy from lvalue, pass by value\n", __LINE__); - } - { // Block around nsCOMPtr lifetime. - nsCOMPtr<nsIRunnable> r2; - { // Block around Spy lifetime. - if (gDebug) { - printf("%d - Spy s(10)\n", __LINE__); - } - Spy s(10); - EXPECT_EQ(1, gConstructions); - EXPECT_EQ(1, gAlive); - if (gDebug) { - printf( - "%d - r2 = " - "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, s)\n", - __LINE__); - } - r2 = NewRunnableMethod<StoreCopyPassByValue<Spy>>( - "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt, - &ThreadUtilsObject::TestByValue, s); - EXPECT_EQ(2, gAlive); - EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction. - Spy::ClearActions(); - if (gDebug) { - printf("%d - End block with Spy s(10)\n", __LINE__); - } - } - EXPECT_EQ(1, gDestructions); - EXPECT_EQ(1, gAlive); - Spy::ClearActions(); - if (gDebug) { - printf("%d - Run()\n", __LINE__); - } - r2->Run(); - EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call. - EXPECT_EQ(10, rpt->mSpy.mID); - EXPECT_LE(1, gDestructions); - EXPECT_EQ(1, gAlive); - Spy::ClearActions(); - if (gDebug) { - printf("%d - End block with r\n", __LINE__); - } - } - if (gDebug) { - printf("%d - After end block with r\n", __LINE__); - } - EXPECT_EQ(1, gDestructions); - EXPECT_EQ(0, gAlive); - - Spy::ClearAll(); - if (gDebug) { - printf("%d - Test: Store copy from prvalue, pass by value\n", __LINE__); - } - { - if (gDebug) { - printf( - "%d - r3 = " - "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, " - "Spy(11))\n", - __LINE__); - } - nsCOMPtr<nsIRunnable> r3 = NewRunnableMethod<StoreCopyPassByValue<Spy>>( - "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt, - &ThreadUtilsObject::TestByValue, Spy(11)); - EXPECT_EQ(1, gAlive); - EXPECT_EQ(1, gConstructions); - EXPECT_LE(1, gMoveConstructions); - Spy::ClearActions(); - if (gDebug) { - printf("%d - Run()\n", __LINE__); - } - r3->Run(); - EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call. - EXPECT_EQ(11, rpt->mSpy.mID); - EXPECT_LE(1, gDestructions); - EXPECT_EQ(1, gAlive); - Spy::ClearActions(); - if (gDebug) { - printf("%d - End block with r\n", __LINE__); - } - } - if (gDebug) { - printf("%d - After end block with r\n", __LINE__); - } - EXPECT_EQ(1, gDestructions); - EXPECT_EQ(0, gAlive); - - Spy::ClearAll(); - { // Store copy from xvalue, pass by value. - nsCOMPtr<nsIRunnable> r4; - { - Spy s(12); - EXPECT_EQ(1, gConstructions); - EXPECT_EQ(1, gAlive); - Spy::ClearActions(); - r4 = NewRunnableMethod<StoreCopyPassByValue<Spy>>( - "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt, - &ThreadUtilsObject::TestByValue, std::move(s)); - EXPECT_LE(1, gMoveConstructions); - EXPECT_EQ(1, gAlive); - EXPECT_EQ(1, gZombies); - Spy::ClearActions(); - } - EXPECT_EQ(1, gDestructions); - EXPECT_EQ(1, gAlive); - EXPECT_EQ(0, gZombies); - Spy::ClearActions(); - r4->Run(); - EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call. - EXPECT_EQ(12, rpt->mSpy.mID); - EXPECT_LE(1, gDestructions); - EXPECT_EQ(1, gAlive); - Spy::ClearActions(); - } - EXPECT_EQ(1, gDestructions); - EXPECT_EQ(0, gAlive); - // Won't test xvalues anymore, prvalues are enough to verify all rvalues. - - Spy::ClearAll(); - if (gDebug) { printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n", __LINE__); } diff --git a/xpcom/tests/gtest/moz.build b/xpcom/tests/gtest/moz.build index 57ec43a371..6fd509d7b2 100644 --- a/xpcom/tests/gtest/moz.build +++ b/xpcom/tests/gtest/moz.build @@ -9,6 +9,7 @@ UNIFIED_SOURCES += [ "TestArenaAllocator.cpp", "TestArrayAlgorithm.cpp", "TestAtoms.cpp", + "TestAutoOwningEventTarget.cpp", "TestAutoRefCnt.cpp", "TestBase64.cpp", "TestCallTemplates.cpp", @@ -120,10 +121,14 @@ else: if CONFIG["OS_TARGET"] == "Darwin": UNIFIED_SOURCES += [ "TestAvailableMemoryWatcherMac.cpp", - "TestMacNSURLEscaping.mm", "TestThreads_mac.mm", ] +if CONFIG["TARGET_OS"] == "OSX": + UNIFIED_SOURCES += [ + "TestMacNSURLEscaping.mm", + ] + if CONFIG["OS_TARGET"] == "Linux": UNIFIED_SOURCES += [ "TestAvailableMemoryWatcherLinux.cpp", diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index f17e085c2f..af4ac657fd 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -82,24 +82,22 @@ struct MethodTrait : MethodTraitsHelper<std::remove_reference_t<T>> {}; } // namespace detail -template <typename MethodType> -using TakesArgument = - std::integral_constant<bool, detail::MethodTrait<MethodType>::ArgSize != 0>; +template <typename T> +using MethodReturnType = typename detail::MethodTrait<T>::ReturnType; -template <typename MethodType, typename TargetType> -using ReturnTypeIs = - std::is_convertible<typename detail::MethodTrait<MethodType>::ReturnType, - TargetType>; +template <typename MethodType> +constexpr bool TakesAnyArguments = + detail::MethodTrait<MethodType>::ArgSize != 0; template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> class MozPromise; -template <typename Return> -struct IsMozPromise : std::false_type {}; +template <typename T> +constexpr bool IsMozPromise = false; template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> -struct IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> - : std::true_type {}; +constexpr bool + IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> = true; /* * A promise manages an asynchronous request that may or may not be able to be @@ -176,8 +174,8 @@ class MozPromise : public MozPromiseBase { } public: - typedef ResolveValueT ResolveValueType; - typedef RejectValueT RejectValueType; + using ResolveValueType = ResolveValueT; + using RejectValueType = RejectValueT; class ResolveOrRejectValue { public: template <typename ResolveValueType_> @@ -288,12 +286,10 @@ class MozPromise : public MozPromiseBase { return p; } - typedef MozPromise<CopyableTArray<ResolveValueType>, RejectValueType, - IsExclusive> - AllPromiseType; - - typedef MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive> - AllSettledPromiseType; + using AllPromiseType = MozPromise<CopyableTArray<ResolveValueType>, + RejectValueType, IsExclusive>; + using AllSettledPromiseType = + MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>; private: class AllPromiseHolder : public MozPromiseRefcountable { @@ -350,17 +346,17 @@ class MozPromise : public MozPromiseBase { // Trying to pass ResolveOrRejectValue by value fails static analysis checks, // so we need to use either a const& or an rvalue reference, depending on // whether IsExclusive is true or not. - typedef std::conditional_t<IsExclusive, ResolveOrRejectValue&&, - const ResolveOrRejectValue&> - ResolveOrRejectValueParam; + using ResolveOrRejectValueParam = + std::conditional_t<IsExclusive, ResolveOrRejectValue&&, + const ResolveOrRejectValue&>; - typedef std::conditional_t<IsExclusive, ResolveValueType&&, - const ResolveValueType&> - ResolveValueTypeParam; + using ResolveValueTypeParam = + std::conditional_t<IsExclusive, ResolveValueType&&, + const ResolveValueType&>; - typedef std::conditional_t<IsExclusive, RejectValueType&&, - const RejectValueType&> - RejectValueTypeParam; + using RejectValueTypeParam = + std::conditional_t<IsExclusive, RejectValueType&&, + const RejectValueType&>; class AllSettledPromiseHolder : public MozPromiseRefcountable { public: @@ -648,15 +644,15 @@ class MozPromise : public MozPromiseBase { * make the resolve/reject value argument "optional". */ template <typename ThisType, typename MethodType, typename ValueType> - static std::enable_if_t<TakesArgument<MethodType>::value, - typename detail::MethodTrait<MethodType>::ReturnType> + static std::enable_if_t<TakesAnyArguments<MethodType>, + MethodReturnType<MethodType>> InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { return (aThisVal->*aMethod)(std::forward<ValueType>(aValue)); } template <typename ThisType, typename MethodType, typename ValueType> - static std::enable_if_t<!TakesArgument<MethodType>::value, - typename detail::MethodTrait<MethodType>::ReturnType> + static std::enable_if_t<!TakesAnyArguments<MethodType>, + MethodReturnType<MethodType>> InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { return (aThisVal->*aMethod)(); } @@ -697,18 +693,14 @@ class MozPromise : public MozPromiseBase { : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveMethodType>::ReturnType>::Type; - using R2 = typename RemoveSmartPointer< - typename detail::MethodTrait<RejectMethodType>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value && - std::is_same_v<R1, R2>>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveMethodType>>; + using R2 = RemoveSmartPointer<MethodReturnType<RejectMethodType>>; + constexpr static bool SupportChaining = + IsMozPromise<R1> && std::is_same_v<R1, R2>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, @@ -736,13 +728,13 @@ class MozPromise : public MozPromiseBase { void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { if (aValue.IsResolve()) { - InvokeCallbackMethod<SupportChaining::value>( - mThisVal.get(), mResolveMethod, MaybeMove(aValue.ResolveValue()), - std::move(mCompletionPromise)); + InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mResolveMethod, + MaybeMove(aValue.ResolveValue()), + std::move(mCompletionPromise)); } else { - InvokeCallbackMethod<SupportChaining::value>( - mThisVal.get(), mRejectMethod, MaybeMove(aValue.RejectValue()), - std::move(mCompletionPromise)); + InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mRejectMethod, + MaybeMove(aValue.RejectValue()), + std::move(mCompletionPromise)); } // Null out mThisVal after invoking the callback so that any references @@ -764,15 +756,12 @@ class MozPromise : public MozPromiseBase { class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer<typename detail::MethodTrait< - ResolveRejectMethodType>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectMethodType>>; + constexpr static bool SupportChaining = IsMozPromise<R1>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, @@ -798,7 +787,7 @@ class MozPromise : public MozPromiseBase { } void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mThisVal.get(), mResolveRejectMethod, MaybeMove(aValue), std::move(mCompletionPromise)); @@ -822,18 +811,14 @@ class MozPromise : public MozPromiseBase { class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveFunction>::ReturnType>::Type; - using R2 = typename RemoveSmartPointer< - typename detail::MethodTrait<RejectFunction>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value && - std::is_same_v<R1, R2>>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveFunction>>; + using R2 = RemoveSmartPointer<MethodReturnType<RejectFunction>>; + constexpr static bool SupportChaining = + IsMozPromise<R1> && std::is_same_v<R1, R2>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, @@ -867,11 +852,11 @@ class MozPromise : public MozPromiseBase { // easily. We could fix this if need be, though it's quite easy to work // around by just capturing something. if (aValue.IsResolve()) { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mResolveFunction.ptr(), &ResolveFunction::operator(), MaybeMove(aValue.ResolveValue()), std::move(mCompletionPromise)); } else { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mRejectFunction.ptr(), &RejectFunction::operator(), MaybeMove(aValue.RejectValue()), std::move(mCompletionPromise)); } @@ -896,15 +881,12 @@ class MozPromise : public MozPromiseBase { class ThenValue<ResolveRejectFunction> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveRejectFunction>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectFunction>>; + constexpr static bool SupportChaining = IsMozPromise<R1>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, @@ -935,7 +917,7 @@ class MozPromise : public MozPromiseBase { // classes with ::operator()), since it allows us to share code more // easily. We could fix this if need be, though it's quite easy to work // around by just capturing something. - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mResolveRejectFunction.ptr(), &ResolveRejectFunction::operator(), MaybeMove(aValue), std::move(mCompletionPromise)); @@ -998,7 +980,7 @@ class MozPromise : public MozPromiseBase { MozPromise* aReceiver) : mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {} - ThenCommand(ThenCommand&& aOther) = default; + ThenCommand(ThenCommand&& aOther) noexcept = default; public: ~ThenCommand() { @@ -1013,7 +995,7 @@ class MozPromise : public MozPromiseBase { // p->Then(thread2, ...); operator RefPtr<PromiseType>() { static_assert( - ThenValueType::SupportChaining::value, + ThenValueType::SupportChaining, "The resolve/reject callback needs to return a RefPtr<MozPromise> " "in order to do promise chaining."); @@ -1336,12 +1318,18 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private }; // A generic promise type that does the trick for simple use cases. -typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> GenericPromise; +// +// Vaguely deprecated: prefer explicitly naming the resolve- and reject-type. +// Additionally, prefer `mozilla::Ok` as the resolve-type if the boolean's value +// is irrelevant. +using GenericPromise = MozPromise<bool, nsresult, /* IsExclusive = */ true>; // A generic, non-exclusive promise type that does the trick for simple use // cases. -typedef MozPromise<bool, nsresult, /* IsExclusive = */ false> - GenericNonExclusivePromise; +// +// Vaguely deprecated, as above. +using GenericNonExclusivePromise = + MozPromise<bool, nsresult, /* IsExclusive = */ false>; /* * Class to encapsulate a promise for a particular role. Use this as the member @@ -1352,8 +1340,9 @@ class MozPromiseHolderBase { public: MozPromiseHolderBase() = default; - MozPromiseHolderBase(MozPromiseHolderBase&& aOther) = default; - MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) = default; + MozPromiseHolderBase(MozPromiseHolderBase&& aOther) noexcept = default; + MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) noexcept = + default; ~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); } @@ -1511,8 +1500,8 @@ class MozPromiseRequestHolder { // will never be called. void Disconnect() { MOZ_ASSERT(Exists()); - mRequest->Disconnect(); - mRequest = nullptr; + RefPtr request = std::move(mRequest); + request->Disconnect(); } void DisconnectIfExists() { @@ -1700,30 +1689,26 @@ class ProxyFunctionRunnable : public CancelableRunnable { UniquePtr<FunctionStorage> mFunction; }; -// Note: The following struct and function are not for public consumption (yet?) -// as we would prefer all calls to pass on-the-spot lambdas (or at least moved -// function objects). They could be moved outside of detail if really needed. +template <typename T> +constexpr static bool IsRefPtrMozPromise = false; +template <typename T, typename U, bool B> +constexpr static bool IsRefPtrMozPromise<RefPtr<MozPromise<T, U, B>>> = true; -// We prefer getting function objects by non-lvalue-ref (to avoid copying them -// and their captures). This struct is a tag that allows the use of objects -// through lvalue-refs where necessary. -struct AllowInvokeAsyncFunctionLVRef {}; +} // namespace detail -// Invoke a function object (e.g., lambda or std/mozilla::function) -// asynchronously; note that the object will be copied if provided by -// lvalue-ref. Return a promise that the function should eventually resolve or -// reject. +// Invoke a function object (e.g., lambda) asynchronously. +// Return a promise that the function should eventually resolve or reject. template <typename Function> static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, - AllowInvokeAsyncFunctionLVRef, Function&& aFunction) - -> decltype(aFunction()) { - static_assert( - IsRefcountedSmartPointer<decltype(aFunction())>::value && - IsMozPromise< - typename RemoveSmartPointer<decltype(aFunction())>::Type>::value, - "Function object must return RefPtr<MozPromise>"); + Function&& aFunction) -> decltype(aFunction()) { + static_assert(!std::is_lvalue_reference_v<Function>, + "Function object must not be passed by lvalue-ref (to avoid " + "unplanned copies); Consider move()ing the object."); + + static_assert(detail::IsRefPtrMozPromise<decltype(aFunction())>, + "Function object must return RefPtr<MozPromise>"); MOZ_ASSERT(aTarget); - typedef typename RemoveSmartPointer<decltype(aFunction())>::Type PromiseType; + typedef RemoveSmartPointer<decltype(aFunction())> PromiseType; typedef detail::ProxyFunctionRunnable<Function, PromiseType> ProxyRunnableType; @@ -1733,21 +1718,6 @@ static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, return p; } -} // namespace detail - -// Invoke a function object (e.g., lambda) asynchronously. -// Return a promise that the function should eventually resolve or reject. -template <typename Function> -static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, - Function&& aFunction) -> decltype(aFunction()) { - static_assert(!std::is_lvalue_reference_v<Function>, - "Function object must not be passed by lvalue-ref (to avoid " - "unplanned copies); Consider move()ing the object."); - return detail::InvokeAsync(aTarget, aCallerName, - detail::AllowInvokeAsyncFunctionLVRef(), - std::forward<Function>(aFunction)); -} - # undef PROMISE_LOG # undef PROMISE_ASSERT # undef PROMISE_DEBUG diff --git a/xpcom/threads/Mutex.h b/xpcom/threads/Mutex.h index 5116f1d7c3..8edb6ee773 100644 --- a/xpcom/threads/Mutex.h +++ b/xpcom/threads/Mutex.h @@ -227,7 +227,7 @@ class MOZ_RAII MOZ_SCOPED_CAPABILITY BaseAutoLock { public: /** * Constructor - * The constructor aquires the given lock. The destructor + * The constructor acquires the given lock. The destructor * releases the lock. * * @param aLock A valid mozilla::Mutex* returned by @@ -343,7 +343,7 @@ class MOZ_RAII MOZ_SCOPED_CAPABILITY ReleasableBaseAutoLock { public: /** * Constructor - * The constructor aquires the given lock. The destructor + * The constructor acquires the given lock. The destructor * releases the lock. * * @param aLock A valid mozilla::Mutex& returned by diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 805be6ee64..3ea324a6c6 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -672,11 +672,11 @@ void AutoNestedEventLoopAnnotation::AnnotateXPCOMSpinEventLoopStack( if (aStack.Length() > 0) { nsCString prefixedStack(XRE_GetProcessTypeString()); prefixedStack += ": "_ns + aStack; - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::XPCOMSpinEventLoopStack, prefixedStack); } else { - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::XPCOMSpinEventLoopStack, ""_ns); + CrashReporter::UnrecordAnnotation( + CrashReporter::Annotation::XPCOMSpinEventLoopStack); } } diff --git a/xpcom/threads/nsThreadUtils.h b/xpcom/threads/nsThreadUtils.h index 72041da295..755ec21c95 100644 --- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -562,71 +562,40 @@ using RunnableFunctionImpl = namespace detail { -template <typename CVRemoved> -struct IsRefcountedSmartPointerHelper : std::false_type {}; - -template <typename Pointee> -struct IsRefcountedSmartPointerHelper<RefPtr<Pointee>> : std::true_type {}; - -template <typename Pointee> -struct IsRefcountedSmartPointerHelper<nsCOMPtr<Pointee>> : std::true_type {}; - -} // namespace detail - template <typename T> -struct IsRefcountedSmartPointer - : detail::IsRefcountedSmartPointerHelper<std::remove_cv_t<T>> {}; - -namespace detail { - -template <typename T, typename CVRemoved> struct RemoveSmartPointerHelper { - typedef T Type; + using Type = T; }; -template <typename T, typename Pointee> -struct RemoveSmartPointerHelper<T, RefPtr<Pointee>> { - typedef Pointee Type; +template <typename T> +struct RemoveSmartPointerHelper<RefPtr<T>> { + using Type = T; }; -template <typename T, typename Pointee> -struct RemoveSmartPointerHelper<T, nsCOMPtr<Pointee>> { - typedef Pointee Type; +template <typename T> +struct RemoveSmartPointerHelper<nsCOMPtr<T>> { + using Type = T; }; -} // namespace detail - template <typename T> -struct RemoveSmartPointer - : detail::RemoveSmartPointerHelper<T, std::remove_cv_t<T>> {}; - -namespace detail { - -template <typename T, typename CVRemoved> struct RemoveRawOrSmartPointerHelper { - typedef T Type; -}; - -template <typename T, typename Pointee> -struct RemoveRawOrSmartPointerHelper<T, Pointee*> { - typedef Pointee Type; + using Type = typename RemoveSmartPointerHelper<T>::Type; }; -template <typename T, typename Pointee> -struct RemoveRawOrSmartPointerHelper<T, RefPtr<Pointee>> { - typedef Pointee Type; -}; - -template <typename T, typename Pointee> -struct RemoveRawOrSmartPointerHelper<T, nsCOMPtr<Pointee>> { - typedef Pointee Type; +template <typename T> +struct RemoveRawOrSmartPointerHelper<T*> { + using Type = T; }; } // namespace detail template <typename T> -struct RemoveRawOrSmartPointer - : detail::RemoveRawOrSmartPointerHelper<T, std::remove_cv_t<T>> {}; +using RemoveSmartPointer = + typename detail::RemoveSmartPointerHelper<std::remove_cv_t<T>>::Type; + +template <typename T> +using RemoveRawOrSmartPointer = + typename detail::RemoveRawOrSmartPointerHelper<std::remove_cv_t<T>>::Type; } // namespace mozilla @@ -797,23 +766,22 @@ struct nsRunnableMethodTraits; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (C::*)(As...), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (C::*)(As...) const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -822,22 +790,22 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind> struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)(), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -845,12 +813,11 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...) const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -858,12 +825,11 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind> struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)() const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; # endif @@ -881,19 +847,6 @@ struct IsParameterStorageClass : public std::false_type {}; // store arguments, and how to pass them to the target method. template <typename T> -struct StoreCopyPassByValue { - using stored_type = std::decay_t<T>; - typedef stored_type passed_type; - stored_type m; - template <typename A> - MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(std::forward<A>(a)) {} - passed_type PassAsParameter() { return m; } -}; -template <typename S> -struct IsParameterStorageClass<StoreCopyPassByValue<S>> - : public std::true_type {}; - -template <typename T> struct StoreCopyPassByConstLRef { using stored_type = std::decay_t<T>; typedef const stored_type& passed_type; @@ -907,19 +860,6 @@ struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>> : public std::true_type {}; template <typename T> -struct StoreCopyPassByLRef { - using stored_type = std::decay_t<T>; - typedef stored_type& passed_type; - stored_type m; - template <typename A> - MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(std::forward<A>(a)) {} - passed_type PassAsParameter() { return m; } -}; -template <typename S> -struct IsParameterStorageClass<StoreCopyPassByLRef<S>> : public std::true_type { -}; - -template <typename T> struct StoreCopyPassByRRef { using stored_type = std::decay_t<T>; typedef stored_type&& passed_type; @@ -996,32 +936,6 @@ template <typename S> struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>> : public std::true_type {}; -template <typename T> -struct StoreCopyPassByConstPtr { - typedef T stored_type; - typedef const T* passed_type; - stored_type m; - template <typename A> - MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(std::forward<A>(a)) {} - passed_type PassAsParameter() { return &m; } -}; -template <typename S> -struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>> - : public std::true_type {}; - -template <typename T> -struct StoreCopyPassByPtr { - typedef T stored_type; - typedef T* passed_type; - stored_type m; - template <typename A> - MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(std::forward<A>(a)) {} - passed_type PassAsParameter() { return &m; } -}; -template <typename S> -struct IsParameterStorageClass<StoreCopyPassByPtr<S>> : public std::true_type { -}; - namespace detail { template <typename> @@ -1035,94 +949,101 @@ template <class> static auto HasRefCountMethodsTest(long) -> std::false_type; template <class T> -struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0)) {}; - -template <typename TWithoutPointer> -struct NonnsISupportsPointerStorageClass - : std::conditional< - std::is_const_v<TWithoutPointer>, - StoreConstPtrPassByConstPtr<std::remove_const_t<TWithoutPointer>>, - StorePtrPassByPtr<TWithoutPointer>> { - using Type = typename NonnsISupportsPointerStorageClass::conditional::type; +constexpr static bool HasRefCountMethods = + decltype(HasRefCountMethodsTest<T>(0))::value; + +// Choose storage&passing strategy based on preferred storage type: +// - If IsParameterStorageClass<T>::value is true, use as-is. +// - RC* -> StoreRefPtrPassByPtr<RC> :Store RefPtr<RC>, pass RC* +// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods) +// - const T* -> StoreConstPtrPassByConstPtr<T> :Store const T*, pass const T* +// - T* -> StorePtrPassByPtr<T> :Store T*, pass T*. +// - const T& -> StoreConstRefPassByConstLRef<T>:Store const T&, pass const T&. +// - T& -> StoreRefPassByLRef<T> :Store T&, pass T&. +// - T&& -> StoreCopyPassByRRef<T> :Store T, pass std::move(T). +// - RefPtr<T>, nsCOMPtr<T> +// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T* +// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&. +// +// For anything less common, please use a lambda function rather than devising +// new parameter-storage classes. (In fact, consider doing that anyway.) + +template <typename T> +struct OtherParameterStorage; + +// The `IsParameterStorageClass` and `RC*` cases must be handled separately (see +// `ParameterStorageHelper`, below) until we can use C++20 concepts. + +template <typename T> +struct OtherParameterStorage<const T*> { + using Type = StoreConstPtrPassByConstPtr<T>; }; -template <typename TWithoutPointer> -struct PointerStorageClass - : std::conditional< - HasRefCountMethods<TWithoutPointer>::value, - StoreRefPtrPassByPtr<TWithoutPointer>, - typename NonnsISupportsPointerStorageClass<TWithoutPointer>::Type> { - using Type = typename PointerStorageClass::conditional::type; +template <typename T> +struct OtherParameterStorage<T*> { + using Type = StorePtrPassByPtr<T>; }; -template <typename TWithoutRef> -struct LValueReferenceStorageClass - : std::conditional< - std::is_const_v<TWithoutRef>, - StoreConstRefPassByConstLRef<std::remove_const_t<TWithoutRef>>, - StoreRefPassByLRef<TWithoutRef>> { - using Type = typename LValueReferenceStorageClass::conditional::type; +template <typename T> +struct OtherParameterStorage<const T&> { + using Type = StoreConstRefPassByConstLRef<T>; }; template <typename T> -struct SmartPointerStorageClass - : std::conditional< - mozilla::IsRefcountedSmartPointer<T>::value, - StoreRefPtrPassByPtr<typename mozilla::RemoveSmartPointer<T>::Type>, - StoreCopyPassByConstLRef<T>> { - using Type = typename SmartPointerStorageClass::conditional::type; +struct OtherParameterStorage<T&> { + using Type = StoreRefPassByLRef<T>; }; template <typename T> -struct NonLValueReferenceStorageClass - : std::conditional<std::is_rvalue_reference_v<T>, - StoreCopyPassByRRef<std::remove_reference_t<T>>, - typename SmartPointerStorageClass<T>::Type> { - using Type = typename NonLValueReferenceStorageClass::conditional::type; +struct OtherParameterStorage<RefPtr<T>> { + using Type = StoreRefPtrPassByPtr<T>; }; template <typename T> -struct NonPointerStorageClass - : std::conditional<std::is_lvalue_reference_v<T>, - typename LValueReferenceStorageClass< - std::remove_reference_t<T>>::Type, - typename NonLValueReferenceStorageClass<T>::Type> { - using Type = typename NonPointerStorageClass::conditional::type; +struct OtherParameterStorage<nsCOMPtr<T>> { + using Type = StoreRefPtrPassByPtr<T>; }; template <typename T> -struct NonParameterStorageClass - : std::conditional< - std::is_pointer_v<T>, - typename PointerStorageClass<std::remove_pointer_t<T>>::Type, - typename NonPointerStorageClass<T>::Type> { - using Type = typename NonParameterStorageClass::conditional::type; +struct OtherParameterStorage<T&&> { + using Type = StoreCopyPassByRRef<T>; +}; + +template <typename T> +struct OtherParameterStorage<const T&&> { + // This is good advice regardless of the types you're handling. + static_assert(!SFINAE1True<T>::value, "please use a lambda function"); +}; + +// default impl. +template <typename T> +struct OtherParameterStorage { + using Type = StoreCopyPassByConstLRef<T>; +}; + +template <typename T, bool A = IsParameterStorageClass<T>::value, + bool B = std::is_pointer_v<T> && + HasRefCountMethods<std::remove_pointer_t<T>>> +struct ParameterStorageHelper; + +template <typename T, bool B> +struct ParameterStorageHelper<T, true, B> { + using Type = T; +}; + +template <typename T> +struct ParameterStorageHelper<T, false, true> { + using Type = StoreRefPtrPassByPtr<std::remove_pointer_t<T>>; +}; + +template <typename T> +struct ParameterStorageHelper<T, false, false> { + using Type = typename OtherParameterStorage<std::remove_cv_t<T>>::Type; }; -// Choose storage&passing strategy based on preferred storage type: -// - If IsParameterStorageClass<T>::value is true, use as-is. -// - RC* -> StoreRefPtrPassByPtr<RC> :Store RefPtr<RC>, pass RC* -// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods) -// - const T* -> StoreConstPtrPassByConstPtr<T> :Store const T*, pass const T* -// - T* -> StorePtrPassByPtr<T> :Store T*, pass T*. -// - const T& -> StoreConstRefPassByConstLRef<T>:Store const T&, pass const T&. -// - T& -> StoreRefPassByLRef<T> :Store T&, pass T&. -// - T&& -> StoreCopyPassByRRef<T> :Store T, pass std::move(T). -// - RefPtr<T>, nsCOMPtr<T> -// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T* -// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&. -// Other available explicit options: -// - StoreCopyPassByValue<T> :Store T, pass T. -// - StoreCopyPassByLRef<T> :Store T, pass T& (of copy!) -// - StoreCopyPassByConstPtr<T> :Store T, pass const T* -// - StoreCopyPassByPtr<T> :Store T, pass T* (of copy!) -// Or create your own class with PassAsParameter() method, optional -// clean-up in destructor, and with associated IsParameterStorageClass<>. template <typename T> -struct ParameterStorage - : std::conditional<IsParameterStorageClass<T>::value, T, - typename NonParameterStorageClass<T>::Type> { - using Type = typename ParameterStorage::conditional::type; +struct ParameterStorage { + using Type = typename ParameterStorageHelper<T>::Type; }; template <class T> |