diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:37 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:37 +0000 |
commit | a90a5cba08fdf6c0ceb95101c275108a152a3aed (patch) | |
tree | 532507288f3defd7f4dcf1af49698bcb76034855 /xpcom/threads | |
parent | Adding debian version 126.0.1-1. (diff) | |
download | firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.tar.xz firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.zip |
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xpcom/threads')
-rw-r--r-- | xpcom/threads/MozPromise.h | 110 | ||||
-rw-r--r-- | xpcom/threads/StaticString.h | 102 | ||||
-rw-r--r-- | xpcom/threads/TaskController.cpp | 2 | ||||
-rw-r--r-- | xpcom/threads/moz.build | 1 | ||||
-rw-r--r-- | xpcom/threads/nsIThreadManager.idl | 2 | ||||
-rw-r--r-- | xpcom/threads/nsThreadManager.cpp | 4 |
6 files changed, 166 insertions, 55 deletions
diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index c53037e119..3155d9ea63 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -17,6 +17,7 @@ #include "mozilla/Monitor.h" #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" +#include "mozilla/StaticString.h" #include "mozilla/UniquePtr.h" #include "mozilla/Variant.h" #include "nsIDirectTaskDispatcher.h" @@ -231,7 +232,7 @@ class MozPromise : public MozPromiseBase { protected: // MozPromise is the public type, and never constructed directly. Construct // a MozPromise::Private, defined below. - MozPromise(const char* aCreationSite, bool aIsCompletionPromise) + MozPromise(StaticString aCreationSite, bool aIsCompletionPromise) : mCreationSite(aCreationSite), mMutex("MozPromise Mutex"), mHaveRequest(false), @@ -241,7 +242,7 @@ class MozPromise : public MozPromiseBase { mMagic4(&mMutex) #endif { - PROMISE_LOG("%s creating MozPromise (%p)", mCreationSite, this); + PROMISE_LOG("%s creating MozPromise (%p)", mCreationSite.get(), this); } public: @@ -257,7 +258,7 @@ class MozPromise : public MozPromiseBase { template <typename ResolveValueType_> [[nodiscard]] static RefPtr<MozPromise> CreateAndResolve( - ResolveValueType_&& aResolveValue, const char* aResolveSite) { + ResolveValueType_&& aResolveValue, StaticString aResolveSite) { static_assert(std::is_convertible_v<ResolveValueType_, ResolveValueT>, "Resolve() argument must be implicitly convertible to " "MozPromise's ResolveValueT"); @@ -269,7 +270,7 @@ class MozPromise : public MozPromiseBase { template <typename RejectValueType_> [[nodiscard]] static RefPtr<MozPromise> CreateAndReject( - RejectValueType_&& aRejectValue, const char* aRejectSite) { + RejectValueType_&& aRejectValue, StaticString aRejectSite) { static_assert(std::is_convertible_v<RejectValueType_, RejectValueT>, "Reject() argument must be implicitly convertible to " "MozPromise's RejectValueT"); @@ -281,7 +282,7 @@ class MozPromise : public MozPromiseBase { template <typename ResolveOrRejectValueType_> [[nodiscard]] static RefPtr<MozPromise> CreateAndResolveOrReject( - ResolveOrRejectValueType_&& aValue, const char* aSite) { + ResolveOrRejectValueType_&& aValue, StaticString aSite) { RefPtr<typename MozPromise::Private> p = new MozPromise::Private(aSite); p->ResolveOrReject(std::forward<ResolveOrRejectValueType_>(aValue), aSite); return p; @@ -497,7 +498,7 @@ class MozPromise : public MozPromiseBase { RefPtr<MozPromise> mPromise; }; - ThenValueBase(nsISerialEventTarget* aResponseTarget, const char* aCallSite) + ThenValueBase(nsISerialEventTarget* aResponseTarget, StaticString aCallSite) : mResponseTarget(aResponseTarget), mCallSite(aCallSite) { MOZ_ASSERT(aResponseTarget); } @@ -526,7 +527,7 @@ class MozPromise : public MozPromiseBase { MOZ_CRASH_UNSAFE_PRINTF( "MozPromise::ThenValue created from '%s' destroyed without being " "either disconnected, resolved, or rejected (dispatchRv: %s)", - mCallSite, + mCallSite.get(), mDispatchRv ? GetStaticErrorName(*mDispatchRv) : "not dispatched"); } @@ -543,8 +544,8 @@ class MozPromise : public MozPromiseBase { PROMISE_LOG( "%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p] " "%s dispatch", - aPromise->mValue.IsResolve() ? "Resolving" : "Rejecting", mCallSite, - r.get(), aPromise, this, + aPromise->mValue.IsResolve() ? "Resolving" : "Rejecting", + mCallSite.get(), r.get(), aPromise, this, aPromise->mUseSynchronousTaskDispatch ? "synchronous" : aPromise->mUseDirectTaskDispatch ? "directtask" : "normal"); @@ -631,7 +632,7 @@ class MozPromise : public MozPromiseBase { #ifdef PROMISE_DEBUG uint32_t mMagic1 = sMagic; #endif - const char* mCallSite; + StaticString mCallSite; #ifdef PROMISE_DEBUG uint32_t mMagic2 = sMagic; #endif @@ -706,7 +707,7 @@ class MozPromise : public MozPromiseBase { public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod, - const char* aCallSite) + StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite), mThisVal(aThisVal), mResolveMethod(aResolveMethod), @@ -767,7 +768,7 @@ class MozPromise : public MozPromiseBase { public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, ResolveRejectMethodType aResolveRejectMethod, - const char* aCallSite) + StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite), mThisVal(aThisVal), mResolveRejectMethod(aResolveRejectMethod) {} @@ -824,7 +825,7 @@ class MozPromise : public MozPromiseBase { public: ThenValue(nsISerialEventTarget* aResponseTarget, ResolveFunction&& aResolveFunction, - RejectFunction&& aRejectFunction, const char* aCallSite) + RejectFunction&& aRejectFunction, StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite) { mResolveFunction.emplace(std::move(aResolveFunction)); mRejectFunction.emplace(std::move(aRejectFunction)); @@ -892,7 +893,7 @@ class MozPromise : public MozPromiseBase { public: ThenValue(nsISerialEventTarget* aResponseTarget, ResolveRejectFunction&& aResolveRejectFunction, - const char* aCallSite) + StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite) { mResolveRejectFunction.emplace(std::move(aResolveRejectFunction)); } @@ -945,7 +946,7 @@ class MozPromise : public MozPromiseBase { public: explicit MapValue(nsISerialEventTarget* aResponseTarget, - ResolveFunction&& f, const char* aCallSite) + ResolveFunction&& f, StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite), mResolveFunction(Some(std::forward<ResolveFunction>(f))) {} @@ -991,7 +992,7 @@ class MozPromise : public MozPromiseBase { public: explicit MapErrValue(nsISerialEventTarget* aResponseTarget, - RejectFunction&& f, const char* aCallSite) + RejectFunction&& f, StaticString aCallSite) : ThenValueBase(aResponseTarget, aCallSite), mRejectFunction(Some(std::forward<RejectFunction>(f))) {} @@ -1030,7 +1031,7 @@ class MozPromise : public MozPromiseBase { public: void ThenInternal(already_AddRefed<ThenValueBase> aThenValue, - const char* aCallSite) { + StaticString aCallSite) { PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex); RefPtr<ThenValueBase> thenValue = aThenValue; @@ -1040,7 +1041,7 @@ class MozPromise : public MozPromiseBase { "Using an exclusive promise in a non-exclusive fashion"); mHaveRequest = true; PROMISE_LOG("%s invoking Then() [this=%p, aThenValue=%p, isPending=%d]", - aCallSite, this, thenValue.get(), (int)IsPending()); + aCallSite.get(), this, thenValue.get(), (int)IsPending()); if (!IsPending()) { thenValue->Dispatch(this); } else { @@ -1072,7 +1073,7 @@ class MozPromise : public MozPromiseBase { using PromiseType = typename ThenValueType::PromiseType; using Private = typename PromiseType::Private; - ThenCommand(const char* aCallSite, + ThenCommand(StaticString aCallSite, already_AddRefed<ThenValueType> aThenValue, MozPromise* aReceiver) : mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {} @@ -1137,7 +1138,7 @@ class MozPromise : public MozPromiseBase { ThenCommand* operator->() { return this; } private: - const char* mCallSite; + StaticString mCallSite; RefPtr<ThenValueType> mThenValue; RefPtr<MozPromise> mReceiver; }; @@ -1146,7 +1147,7 @@ class MozPromise : public MozPromiseBase { template <typename ThisType, typename... Methods, typename ThenValueType = ThenValue<ThisType*, Methods...>, typename ReturnType = ThenCommand<ThenValueType>> - ReturnType Then(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + ReturnType Then(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, ThisType* aThisVal, Methods... aMethods) { RefPtr<ThenValueType> thenValue = new ThenValueType(aResponseTarget, aThisVal, aMethods..., aCallSite); @@ -1156,7 +1157,7 @@ class MozPromise : public MozPromiseBase { template <typename... Functions, typename ThenValueType = ThenValue<Functions...>, typename ReturnType = ThenCommand<ThenValueType>> - ReturnType Then(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + ReturnType Then(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Functions&&... aFunctions) { RefPtr<ThenValueType> thenValue = new ThenValueType(aResponseTarget, std::move(aFunctions)..., aCallSite); @@ -1166,7 +1167,7 @@ class MozPromise : public MozPromiseBase { // Shorthand for a `Then` which simply forwards the reject-value, but performs // some additional work with the resolve-value. template <typename Function> - auto Map(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + auto Map(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Function&& function) { RefPtr<MapValue<Function>> thenValue = new MapValue<Function>( aResponseTarget, std::forward<Function>(function), aCallSite); @@ -1176,7 +1177,7 @@ class MozPromise : public MozPromiseBase { // Shorthand for a `Then` which simply forwards the resolve-value, but // performs some additional work with the reject-value. template <typename Function> - auto MapErr(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + auto MapErr(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Function&& function) { RefPtr<MapErrValue<Function>> thenValue = new MapErrValue<Function>( aResponseTarget, std::forward<Function>(function), aCallSite); @@ -1185,7 +1186,7 @@ class MozPromise : public MozPromiseBase { } void ChainTo(already_AddRefed<Private> aChainedPromise, - const char* aCallSite) { + StaticString aCallSite) { MutexAutoLock lock(mMutex); MOZ_DIAGNOSTIC_ASSERT( !IsExclusive || !mHaveRequest, @@ -1194,7 +1195,7 @@ class MozPromise : public MozPromiseBase { RefPtr<Private> chainedPromise = aChainedPromise; PROMISE_LOG( "%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]", - aCallSite, this, chainedPromise.get(), (int)IsPending()); + aCallSite.get(), this, chainedPromise.get(), (int)IsPending()); // We want to use the same type of dispatching method with the chained // promises. @@ -1305,7 +1306,7 @@ class MozPromise : public MozPromiseBase { #endif }; - const char* mCreationSite; // For logging + StaticString mCreationSite; // For logging Mutex mMutex MOZ_UNANNOTATED; ResolveOrRejectValue mValue; bool mUseSynchronousTaskDispatch = false; @@ -1335,21 +1336,22 @@ template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private : public MozPromise<ResolveValueT, RejectValueT, IsExclusive> { public: - explicit Private(const char* aCreationSite, bool aIsCompletionPromise = false) + explicit Private(StaticString aCreationSite, + bool aIsCompletionPromise = false) : MozPromise(aCreationSite, aIsCompletionPromise) {} template <typename ResolveValueT_> - void Resolve(ResolveValueT_&& aResolveValue, const char* aResolveSite) { + void Resolve(ResolveValueT_&& aResolveValue, StaticString aResolveSite) { PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); - PROMISE_LOG("%s resolving MozPromise (%p created at %s)", aResolveSite, - this, mCreationSite); + PROMISE_LOG("%s resolving MozPromise (%p created at %s)", + aResolveSite.get(), this, mCreationSite.get()); if (!IsPending()) { PROMISE_LOG( "%s ignored already resolved or rejected MozPromise (%p created at " "%s)", - aResolveSite, this, mCreationSite); + aResolveSite.get(), this, mCreationSite.get()); return; } mValue.SetResolve(std::forward<ResolveValueT_>(aResolveValue)); @@ -1357,17 +1359,17 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private } template <typename RejectValueT_> - void Reject(RejectValueT_&& aRejectValue, const char* aRejectSite) { + void Reject(RejectValueT_&& aRejectValue, StaticString aRejectSite) { PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); - PROMISE_LOG("%s rejecting MozPromise (%p created at %s)", aRejectSite, this, - mCreationSite); + PROMISE_LOG("%s rejecting MozPromise (%p created at %s)", aRejectSite.get(), + this, mCreationSite.get()); if (!IsPending()) { PROMISE_LOG( "%s ignored already resolved or rejected MozPromise (%p created at " "%s)", - aRejectSite, this, mCreationSite); + aRejectSite.get(), this, mCreationSite.get()); return; } mValue.SetReject(std::forward<RejectValueT_>(aRejectValue)); @@ -1375,17 +1377,17 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private } template <typename ResolveOrRejectValue_> - void ResolveOrReject(ResolveOrRejectValue_&& aValue, const char* aSite) { + void ResolveOrReject(ResolveOrRejectValue_&& aValue, StaticString aSite) { PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); - PROMISE_LOG("%s resolveOrRejecting MozPromise (%p created at %s)", aSite, - this, mCreationSite); + PROMISE_LOG("%s resolveOrRejecting MozPromise (%p created at %s)", + aSite.get(), this, mCreationSite.get()); if (!IsPending()) { PROMISE_LOG( "%s ignored already resolved or rejected MozPromise (%p created at " "%s)", - aSite, this, mCreationSite); + aSite.get(), this, mCreationSite.get()); return; } mValue = std::forward<ResolveOrRejectValue_>(aValue); @@ -1403,7 +1405,7 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); PROMISE_LOG("%s UseSynchronousTaskDispatch MozPromise (%p created at %s)", - aSite, this, mCreationSite); + aSite, this, mCreationSite.get()); MOZ_ASSERT(IsPending(), "A Promise must not have been already resolved or rejected to " "set dispatch state"); @@ -1420,7 +1422,7 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); PROMISE_LOG("%s UseDirectTaskDispatch MozPromise (%p created at %s)", aSite, - this, mCreationSite); + this, mCreationSite.get()); MOZ_ASSERT(IsPending(), "A Promise must not have been already resolved or rejected to " "set dispatch state"); @@ -1437,7 +1439,7 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private mMagic3 == sMagic && mMagic4 == &mMutex); MutexAutoLock lock(mMutex); PROMISE_LOG("%s TaskPriority MozPromise (%p created at %s)", aSite, this, - mCreationSite); + mCreationSite.get()); MOZ_ASSERT(IsPending(), "A Promise must not have been already resolved or rejected to " "set dispatch state"); @@ -1478,7 +1480,7 @@ class MozPromiseHolderBase { ~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); } - already_AddRefed<PromiseType> Ensure(const char* aMethodName) { + already_AddRefed<PromiseType> Ensure(StaticString aMethodName) { static_cast<ImplType*>(this)->Check(); if (!mPromise) { mPromise = new (typename PromiseType::Private)(aMethodName); @@ -1498,7 +1500,7 @@ class MozPromiseHolderBase { } template <typename ResolveValueType_> - void Resolve(ResolveValueType_&& aResolveValue, const char* aMethodName) { + void Resolve(ResolveValueType_&& aResolveValue, StaticString aMethodName) { static_assert(std::is_convertible_v<ResolveValueType_, typename PromiseType::ResolveValueType>, "Resolve() argument must be implicitly convertible to " @@ -1513,14 +1515,14 @@ class MozPromiseHolderBase { template <typename ResolveValueType_> void ResolveIfExists(ResolveValueType_&& aResolveValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { Resolve(std::forward<ResolveValueType_>(aResolveValue), aMethodName); } } template <typename RejectValueType_> - void Reject(RejectValueType_&& aRejectValue, const char* aMethodName) { + void Reject(RejectValueType_&& aRejectValue, StaticString aMethodName) { static_assert(std::is_convertible_v<RejectValueType_, typename PromiseType::RejectValueType>, "Reject() argument must be implicitly convertible to " @@ -1534,7 +1536,7 @@ class MozPromiseHolderBase { template <typename RejectValueType_> void RejectIfExists(RejectValueType_&& aRejectValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { Reject(std::forward<RejectValueType_>(aRejectValue), aMethodName); } @@ -1542,7 +1544,7 @@ class MozPromiseHolderBase { template <typename ResolveOrRejectValueType_> void ResolveOrReject(ResolveOrRejectValueType_&& aValue, - const char* aMethodName) { + StaticString aMethodName) { static_cast<ImplType*>(this)->Check(); MOZ_ASSERT(mPromise); mPromise->ResolveOrReject(std::forward<ResolveOrRejectValueType_>(aValue), @@ -1552,7 +1554,7 @@ class MozPromiseHolderBase { template <typename ResolveOrRejectValueType_> void ResolveOrRejectIfExists(ResolveOrRejectValueType_&& aValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { ResolveOrReject(std::forward<ResolveOrRejectValueType_>(aValue), aMethodName); @@ -1718,7 +1720,7 @@ class ProxyRunnable : public CancelableRunnable { template <typename... Storages, typename PromiseType, typename ThisType, typename... ArgTypes, typename... ActualArgTypes> static RefPtr<PromiseType> InvokeAsyncImpl( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr<PromiseType> (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { MOZ_ASSERT(aTarget); @@ -1758,7 +1760,7 @@ template <typename... Storages, typename PromiseType, typename ThisType, typename... ArgTypes, typename... ActualArgTypes, std::enable_if_t<sizeof...(Storages) != 0, int> = 0> static RefPtr<PromiseType> InvokeAsync( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr<PromiseType> (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { static_assert( @@ -1777,7 +1779,7 @@ template <typename... Storages, typename PromiseType, typename ThisType, typename... ArgTypes, typename... ActualArgTypes, std::enable_if_t<sizeof...(Storages) == 0, int> = 0> static RefPtr<PromiseType> InvokeAsync( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr<PromiseType> (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { static_assert( @@ -1831,7 +1833,7 @@ constexpr static bool IsRefPtrMozPromise<RefPtr<MozPromise<T, U, B>>> = true; // 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, +static auto InvokeAsync(nsISerialEventTarget* aTarget, StaticString aCallerName, Function&& aFunction) -> decltype(aFunction()) { static_assert(!std::is_lvalue_reference_v<Function>, "Function object must not be passed by lvalue-ref (to avoid " diff --git a/xpcom/threads/StaticString.h b/xpcom/threads/StaticString.h new file mode 100644 index 0000000000..26c8675b24 --- /dev/null +++ b/xpcom/threads/StaticString.h @@ -0,0 +1,102 @@ +/* -*- 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 XPCOM_THREADS_STATICSTRING_H_ +#define XPCOM_THREADS_STATICSTRING_H_ + +#include <cstddef> +#include "mozilla/Attributes.h" + +// from "nsStringFwd.h" +template <typename T> +class nsTLiteralString; +using nsLiteralCString = nsTLiteralString<char>; + +namespace mozilla { +// class StaticString +// +// Wrapper type containing a C-style string which is guaranteed[*] to have been +// created (potentially indirectly) from static data. Primarily intended for +// text that may eventually be sent up via telemetry, to avoid the possibility +// of accidentally exfiltrating PII. +// +// `StaticString`, like `template <size_t N> const char (&str)[N]`, can be +// freely and implicitly converted to `const char *`, to simplify its use as a +// drop-in replacement when detemplatizing functions. +// +// ### Comparison/contrast with `nsLiteralCString` +// +// Concretely, `StaticString` is smaller than `nsLiteralCString`, as it does not +// store the string-length. It's also trivial to construct a `StaticString` from +// the variable `__func__` or the preprocessor token `__FILE__`, which would +// require additional work to be used with the latter's `_ns` constructor. +// +// Conventionally, the primary intended use case of `StaticString` is subtly +// different from that of `nsLiteralCString`: +// * `StaticString` is intended for correctness (etc.) in contexts where the +// consumer of the string requires that it be static. +// * `nsLiteralCString` is more for efficiency in contexts where the source +// string _happens to be_ static, but in which the consumer does not care +// (and so accepts `nsACString const &` or similar). +// +// This is not a hard rule, however, and is notably bent in dom::Promise. (See +// comments below.) +// +// Both are trivially-copyable/-movable/-destructible, guaranteed non-null, and +// can only contain static data. +// +// #### Footnotes +// +// [*] ``` +// CHORUS: "What, never?" +// CAPTAIN: "Well... hardly ever!" +// CHORUS: "He's hardly ever sick of C!" +// -- Gilbert & Sullivan, _H.M.S. Pinafore_ (emended) +// ``` +// +class StaticString { + /* TODO(C++20): convert `constexpr` to `consteval` wherever possible. */ + const char* mStr; // guaranteed nonnull + + public: + template <size_t N> + constexpr MOZ_IMPLICIT StaticString(const char (&str)[N]) : mStr(str) {} + + // `nsLiteralCString` has the same guarantees as `StaticString` (both in being + // nonnull and containing only static data), so it's safe to construct either + // from the other. + // + // At present we only support construction of a `StaticString` from an + // `nsLiteralCString`, since this is zero-cost (the converse would not be), + // and is probably the simplest way to support dom::Promise's interoperation + // with MozPromise. + // + // (A more principled approach, in some sense, would be to create a third type + // `StaticStringWithLength` (or whatever) acting as the lattice-join of the + // two, which could then decay to either one as necessary. This is overkill + // for our current goals... but might be worthwhile if, _e.g._, you really + // need to get `__func__` into an `nsLiteralCString` rather than just an + // `nsDependentCString` for some reason.) + // + constexpr explicit StaticString(nsLiteralCString const& str); + + constexpr StaticString(StaticString const&) = default; + constexpr StaticString(StaticString&&) = default; + ~StaticString() = default; + + constexpr MOZ_IMPLICIT operator const char*() const { return mStr; } + + // Not normally needed, but useful for variadic logging functions. + constexpr const char* get() const { return mStr; } +}; + +// Under the covers, StaticString is as lightweight as a single pointer: it does +// not store the length of its deta. +static_assert(sizeof(StaticString) == sizeof(const char*)); +static_assert(alignof(StaticString) == alignof(const char*)); +} // namespace mozilla + +#endif diff --git a/xpcom/threads/TaskController.cpp b/xpcom/threads/TaskController.cpp index d8c2d5e176..b9559bdb74 100644 --- a/xpcom/threads/TaskController.cpp +++ b/xpcom/threads/TaskController.cpp @@ -16,6 +16,7 @@ #include "mozilla/InputTaskManager.h" #include "mozilla/VsyncTaskManager.h" #include "mozilla/IOInterposer.h" +#include "mozilla/Perfetto.h" #include "mozilla/StaticPtr.h" #include "mozilla/SchedulerGroup.h" #include "mozilla/ScopeExit.h" @@ -135,6 +136,7 @@ class MOZ_RAII AutoProfileTask { # define AUTO_PROFILE_FOLLOWING_TASK(task) \ nsAutoCString name; \ (task)->GetName(name); \ + PERFETTO_TRACE_EVENT("task", perfetto::DynamicString{name.get()}); \ AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("Task", OTHER, name); \ mozilla::AutoProfileTask PROFILER_RAII(name, (task)->GetPriority()); #else diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index 06d10ad331..09d7649c6f 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -70,6 +70,7 @@ EXPORTS.mozilla += [ "SpinEventLoopUntil.h", "StateMirroring.h", "StateWatching.h", + "StaticString.h", "SynchronizedEventQueue.h", "SyncRunnable.h", "TaskController.h", diff --git a/xpcom/threads/nsIThreadManager.idl b/xpcom/threads/nsIThreadManager.idl index 9629cb630a..2c5de409fe 100644 --- a/xpcom/threads/nsIThreadManager.idl +++ b/xpcom/threads/nsIThreadManager.idl @@ -29,7 +29,7 @@ interface nsINestedEventLoopCondition : nsISupports /** * An interface for creating and locating nsIThread instances. */ -[scriptable, uuid(1be89eca-e2f7-453b-8d38-c11ba247f6f3)] +[scriptable, builtinclass, uuid(1be89eca-e2f7-453b-8d38-c11ba247f6f3)] interface nsIThreadManager : nsISupports { /** diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 3ea324a6c6..52c7db1be4 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -21,6 +21,7 @@ #include "mozilla/InputTaskManager.h" #include "mozilla/Mutex.h" #include "mozilla/NeverDestroyed.h" +#include "mozilla/Perfetto.h" #include "mozilla/Preferences.h" #include "mozilla/ProfilerMarkers.h" #include "mozilla/SpinEventLoopUntil.h" @@ -270,6 +271,9 @@ nsThreadManager::nsThreadManager() nsThreadManager::~nsThreadManager() = default; nsresult nsThreadManager::Init() { + // Initialize perfetto if on Android. + InitPerfetto(); + // Child processes need to initialize the thread manager before they // initialize XPCOM in order to set up the crash reporter. This leads to // situations where we get initialized twice. |