From e2ee2f11df1a3a3ab9049b74ae6bd6aa13a9b2c6 Mon Sep 17 00:00:00 2001 From: Ray Kraesig Date: Wed, 24 Apr 2024 17:02:49 +0000 Subject: [PATCH] Bug 1891541 - [2/2] enforce that MozPromise only accepts static strings r=xpcom-reviewers,media-playback-reviewers,padenot,emilio All present uses of the call-site arguments to MozPromise's methods supply static strings. However, this is nowhere enforced. Do so. Additionally, since this is the third or fourth time the present author alone has personally implemented such an enforcement mechanism, create a helper class to simplify doing so. No functional changes. Differential Revision: https://phabricator.services.mozilla.com/D207462 --- dom/fetch/FetchService.cpp | 12 +- dom/fetch/FetchService.h | 12 +- dom/fs/parent/FileSystemAccessHandle.cpp | 2 +- dom/html/HTMLMediaElement.cpp | 2 +- dom/media/ExternalEngineStateMachine.h | 4 +- dom/media/MediaFormatReader.h | 8 +- dom/media/MediaManager.cpp | 2 +- dom/media/MediaManager.h | 2 +- dom/media/MediaTimer.cpp | 4 +- dom/media/MediaTimer.h | 6 +- dom/media/SeekJob.cpp | 4 +- dom/media/SeekJob.h | 4 +- dom/media/ipc/MFCDMChild.cpp | 7 +- dom/media/ipc/MFCDMChild.h | 2 +- .../mediacapabilities/KeyValueStorage.cpp | 2 +- .../agnostic/gmp/GMPVideoDecoder.cpp | 2 +- .../platforms/agnostic/gmp/GMPVideoDecoder.h | 2 +- dom/media/platforms/omx/OmxDataDecoder.cpp | 6 +- dom/media/platforms/omx/OmxDataDecoder.h | 4 +- dom/promise/PromiseNativeHandler.h | 5 +- dom/quota/QuotaCommon.cpp | 6 +- dom/quota/QuotaCommon.h | 10 +- netwerk/ipc/DocumentLoadListener.h | 2 +- .../components/uniffi-js/ScaffoldingCall.h | 9 +- .../dllservices/UntrustedModulesProcessor.cpp | 8 +- .../dllservices/UntrustedModulesProcessor.h | 2 +- widget/nsIDeviceContextSpec.cpp | 4 +- widget/nsIDeviceContextSpec.h | 2 +- xpcom/string/nsTLiteralString.h | 12 +- xpcom/threads/MozPromise.h | 110 +++++++++--------- xpcom/threads/StaticString.h | 102 ++++++++++++++++ xpcom/threads/moz.build | 1 + 32 files changed, 239 insertions(+), 121 deletions(-) create mode 100644 xpcom/threads/StaticString.h diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp index 624fa33e847f..9af967d6af7d 100644 --- a/dom/fetch/FetchService.cpp +++ b/dom/fetch/FetchService.cpp @@ -65,42 +65,42 @@ FetchServicePromises::GetResponseEndPromise() { } void FetchServicePromises::ResolveResponseAvailablePromise( - FetchServiceResponse&& aResponse, const char* aMethodName) { + FetchServiceResponse&& aResponse, StaticString aMethodName) { if (mAvailablePromise) { mAvailablePromise->Resolve(std::move(aResponse), aMethodName); } } void FetchServicePromises::RejectResponseAvailablePromise( - const CopyableErrorResult&& aError, const char* aMethodName) { + const CopyableErrorResult&& aError, StaticString aMethodName) { if (mAvailablePromise) { mAvailablePromise->Reject(aError, aMethodName); } } void FetchServicePromises::ResolveResponseTimingPromise( - ResponseTiming&& aTiming, const char* aMethodName) { + ResponseTiming&& aTiming, StaticString aMethodName) { if (mTimingPromise) { mTimingPromise->Resolve(std::move(aTiming), aMethodName); } } void FetchServicePromises::RejectResponseTimingPromise( - const CopyableErrorResult&& aError, const char* aMethodName) { + const CopyableErrorResult&& aError, StaticString aMethodName) { if (mTimingPromise) { mTimingPromise->Reject(aError, aMethodName); } } void FetchServicePromises::ResolveResponseEndPromise(ResponseEndArgs&& aArgs, - const char* aMethodName) { + StaticString aMethodName) { if (mEndPromise) { mEndPromise->Resolve(std::move(aArgs), aMethodName); } } void FetchServicePromises::RejectResponseEndPromise( - const CopyableErrorResult&& aError, const char* aMethodName) { + const CopyableErrorResult&& aError, StaticString aMethodName) { if (mEndPromise) { mEndPromise->Reject(aError, aMethodName); } diff --git a/dom/fetch/FetchService.h b/dom/fetch/FetchService.h index 47badef2fb08..36c2527ef0a1 100644 --- a/dom/fetch/FetchService.h +++ b/dom/fetch/FetchService.h @@ -48,17 +48,17 @@ class FetchServicePromises final { RefPtr GetResponseEndPromise(); void ResolveResponseAvailablePromise(FetchServiceResponse&& aResponse, - const char* aMethodName); + StaticString aMethodName); void RejectResponseAvailablePromise(const CopyableErrorResult&& aError, - const char* aMethodName); + StaticString aMethodName); void ResolveResponseTimingPromise(ResponseTiming&& aTiming, - const char* aMethodName); + StaticString aMethodName); void RejectResponseTimingPromise(const CopyableErrorResult&& aError, - const char* aMethodName); + StaticString aMethodName); void ResolveResponseEndPromise(ResponseEndArgs&& aArgs, - const char* aMethodName); + StaticString aMethodName); void RejectResponseEndPromise(const CopyableErrorResult&& aError, - const char* aMethodName); + StaticString aMethodName); private: ~FetchServicePromises() = default; diff --git a/dom/fs/parent/FileSystemAccessHandle.cpp b/dom/fs/parent/FileSystemAccessHandle.cpp index 07430ce47654..5fb2e02fc4ea 100644 --- a/dom/fs/parent/FileSystemAccessHandle.cpp +++ b/dom/fs/parent/FileSystemAccessHandle.cpp @@ -177,7 +177,7 @@ FileSystemAccessHandle::BeginInit() { mLocked = true; - auto CreateAndRejectInitPromise = [](const char* aFunc, nsresult aRv) { + auto CreateAndRejectInitPromise = [](StaticString aFunc, nsresult aRv) { return CreateAndRejectMozPromise(aFunc, aRv); }; diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 877f3ec3ba58..df48b63fedc4 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -994,7 +994,7 @@ class HTMLMediaElement::MediaStreamRenderer { graph->CreateSourceTrack(MediaSegment::AUDIO)); } - void ResolveAudioDevicePromiseIfExists(const char* aMethodName) { + void ResolveAudioDevicePromiseIfExists(StaticString aMethodName) { if (mSetAudioDevicePromise.IsEmpty()) { return; } diff --git a/dom/media/ExternalEngineStateMachine.h b/dom/media/ExternalEngineStateMachine.h index 83250b0f3c81..e020695bcce1 100644 --- a/dom/media/ExternalEngineStateMachine.h +++ b/dom/media/ExternalEngineStateMachine.h @@ -154,12 +154,12 @@ class ExternalEngineStateMachine final mSeekJob = SeekJob(); mSeekJob.mTarget = Some(aTarget); } - void Resolve(const char* aCallSite) { + void Resolve(StaticString aCallSite) { MOZ_ASSERT(mSeekJob.Exists()); mSeekJob.Resolve(aCallSite); mSeekJob = SeekJob(); } - void RejectIfExists(const char* aCallSite) { + void RejectIfExists(StaticString aCallSite) { mSeekJob.RejectIfExists(aCallSite); } bool IsSeeking() const { return mSeekRequest.Exists(); } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 5c4e04172dc4..6e4bb23d6a41 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -552,7 +552,7 @@ class MediaFormatReader final // Rejecting the promise will stop the reader from decoding ahead. virtual bool HasPromise() const = 0; virtual void RejectPromise(const MediaResult& aError, - const char* aMethodName) = 0; + StaticString aMethodName) = 0; // Clear track demuxer related data. void ResetDemuxer() { @@ -688,20 +688,20 @@ class MediaFormatReader final bool HasPromise() const override { return mHasPromise; } - RefPtr> EnsurePromise(const char* aMethodName) { + RefPtr> EnsurePromise(StaticString aMethodName) { MOZ_ASSERT(mOwner->OnTaskQueue()); mHasPromise = true; return mPromise.Ensure(aMethodName); } - void ResolvePromise(Type* aData, const char* aMethodName) { + void ResolvePromise(Type* aData, StaticString aMethodName) { MOZ_ASSERT(mOwner->OnTaskQueue()); mPromise.Resolve(aData, aMethodName); mHasPromise = false; } void RejectPromise(const MediaResult& aError, - const char* aMethodName) override { + StaticString aMethodName) override { MOZ_ASSERT(mOwner->OnTaskQueue()); mPromise.Reject(aError, aMethodName); mHasPromise = false; diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index f0ec23815a9d..bd6bc00cd805 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -2516,7 +2516,7 @@ void MediaManager::Dispatch(already_AddRefed task) { template /* static */ -RefPtr MediaManager::Dispatch(const char* aName, +RefPtr MediaManager::Dispatch(StaticString aName, FunctionType&& aFunction) { MozPromiseHolder holder; RefPtr promise = holder.Ensure(aName); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 738ccd795d41..81f23bfe05de 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -220,7 +220,7 @@ class MediaManager final : public nsIMediaManagerService, * manager thread. */ template - static RefPtr Dispatch(const char* aName, + static RefPtr Dispatch(StaticString aName, FunctionType&& aFunction); #ifdef DEBUG diff --git a/dom/media/MediaTimer.cpp b/dom/media/MediaTimer.cpp index c34eb816fac3..231e0e2441bf 100644 --- a/dom/media/MediaTimer.cpp +++ b/dom/media/MediaTimer.cpp @@ -68,12 +68,12 @@ bool MediaTimer::OnMediaTimerThread() { } RefPtr MediaTimer::WaitFor(const TimeDuration& aDuration, - const char* aCallSite) { + StaticString aCallSite) { return WaitUntil(TimeStamp::Now() + aDuration, aCallSite); } RefPtr MediaTimer::WaitUntil(const TimeStamp& aTimeStamp, - const char* aCallSite) { + StaticString aCallSite) { MonitorAutoLock mon(mMonitor); TIMER_LOG("MediaTimer::WaitUntil %" PRId64, RelativeMicroseconds(aTimeStamp)); Entry e(aTimeStamp, aCallSite); diff --git a/dom/media/MediaTimer.h b/dom/media/MediaTimer.h index 837a1591b367..2ab3f2e5697d 100644 --- a/dom/media/MediaTimer.h +++ b/dom/media/MediaTimer.h @@ -44,9 +44,9 @@ class MediaTimer { DispatchDestroy()); RefPtr WaitFor(const TimeDuration& aDuration, - const char* aCallSite); + StaticString aCallSite); RefPtr WaitUntil(const TimeStamp& aTimeStamp, - const char* aCallSite); + StaticString aCallSite); void Cancel(); // Cancel and reject any unresolved promises with false. private: @@ -81,7 +81,7 @@ class MediaTimer { TimeStamp mTimeStamp; RefPtr mPromise; - explicit Entry(const TimeStamp& aTimeStamp, const char* aCallSite) + explicit Entry(const TimeStamp& aTimeStamp, StaticString aCallSite) : mTimeStamp(aTimeStamp), mPromise(new MediaTimerPromise::Private(aCallSite)) {} diff --git a/dom/media/SeekJob.cpp b/dom/media/SeekJob.cpp index 93911638cefe..1760cceb35c2 100644 --- a/dom/media/SeekJob.cpp +++ b/dom/media/SeekJob.cpp @@ -18,12 +18,12 @@ bool SeekJob::Exists() const { return mTarget.isSome(); } -void SeekJob::Resolve(const char* aCallSite) { +void SeekJob::Resolve(StaticString aCallSite) { mPromise.Resolve(true, aCallSite); mTarget.reset(); } -void SeekJob::RejectIfExists(const char* aCallSite) { +void SeekJob::RejectIfExists(StaticString aCallSite) { mTarget.reset(); mPromise.RejectIfExists(true, aCallSite); } diff --git a/dom/media/SeekJob.h b/dom/media/SeekJob.h index 1bdd6913f3ed..9e1e404d9140 100644 --- a/dom/media/SeekJob.h +++ b/dom/media/SeekJob.h @@ -20,8 +20,8 @@ struct SeekJob { ~SeekJob(); bool Exists() const; - void Resolve(const char* aCallSite); - void RejectIfExists(const char* aCallSite); + void Resolve(StaticString aCallSite); + void RejectIfExists(StaticString aCallSite); Maybe mTarget; MozPromiseHolder mPromise; diff --git a/dom/media/ipc/MFCDMChild.cpp b/dom/media/ipc/MFCDMChild.cpp index 2ba2bdaf4e38..9df86b82f478 100644 --- a/dom/media/ipc/MFCDMChild.cpp +++ b/dom/media/ipc/MFCDMChild.cpp @@ -7,6 +7,7 @@ #include "mozilla/EMEUtils.h" #include "mozilla/KeySystemConfig.h" #include "mozilla/RefPtr.h" +#include "mozilla/StaticString.h" #include "mozilla/WMFCDMProxyCallback.h" #include "nsString.h" #include "RemoteDecoderManagerChild.h" @@ -44,7 +45,7 @@ namespace mozilla { #define INVOKE_ASYNC(method, promiseId, param1) \ do { \ - auto callsite = __func__; \ + StaticString callsite = __func__; \ using ParamType = std::remove_reference::type; \ mManagerThread->Dispatch(NS_NewRunnableFunction( \ callsite, [self = RefPtr{this}, callsite, promiseId, \ @@ -56,7 +57,7 @@ namespace mozilla { #define INVOKE_ASYNC2(method, promiseId, param1, param2) \ do { \ - auto callsite = __func__; \ + StaticString callsite = __func__; \ using ParamType1 = std::remove_reference::type; \ using ParamType2 = std::remove_reference::type; \ mManagerThread->Dispatch(NS_NewRunnableFunction( \ @@ -188,7 +189,7 @@ void MFCDMChild::AssertSendable() { template already_AddRefed MFCDMChild::InvokeAsync( - std::function&& aCall, const char* aCallerName, + std::function&& aCall, StaticString aCallerName, MozPromiseHolder& aPromise) { AssertSendable(); diff --git a/dom/media/ipc/MFCDMChild.h b/dom/media/ipc/MFCDMChild.h index 3396b0c79037..ec766cab2487 100644 --- a/dom/media/ipc/MFCDMChild.h +++ b/dom/media/ipc/MFCDMChild.h @@ -30,7 +30,7 @@ class MFCDMChild final : public PMFCDMChild { template already_AddRefed InvokeAsync( - std::function&& aCall, const char* aCallerName, + std::function&& aCall, StaticString aCallerName, MozPromiseHolder& aPromise); using InitPromise = MozPromise; diff --git a/dom/media/mediacapabilities/KeyValueStorage.cpp b/dom/media/mediacapabilities/KeyValueStorage.cpp index f0ac0aad7dbe..a2e007c59832 100644 --- a/dom/media/mediacapabilities/KeyValueStorage.cpp +++ b/dom/media/mediacapabilities/KeyValueStorage.cpp @@ -94,7 +94,7 @@ class VoidCallback final : public nsIKeyValueVoidCallback { mResultPromise.Reject(NS_ERROR_FAILURE, __func__); return NS_OK; } - RefPtr Ensure(const char* aMethodName) { + RefPtr Ensure(StaticString aMethodName) { return mResultPromise.Ensure(aMethodName); } diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp index a57da8da96b0..a5fcfa6881f1 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp @@ -201,7 +201,7 @@ void GMPVideoDecoder::Terminated() { } void GMPVideoDecoder::ProcessReorderQueue( - MozPromiseHolder& aPromise, const char* aMethodName) { + MozPromiseHolder& aPromise, StaticString aMethodName) { if (aPromise.IsEmpty()) { return; } diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h index 1f0f59c68515..6f831e5fbc29 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h @@ -72,7 +72,7 @@ class GMPVideoDecoder final : public MediaDataDecoder, virtual GMPUniquePtr CreateFrame(MediaRawData* aSample); virtual const VideoInfo& GetConfig() const; void ProcessReorderQueue(MozPromiseHolder& aPromise, - const char* aMethodName); + StaticString aMethodName); private: ~GMPVideoDecoder() = default; diff --git a/dom/media/platforms/omx/OmxDataDecoder.cpp b/dom/media/platforms/omx/OmxDataDecoder.cpp index e830f77dd2b9..6c40ca491075 100644 --- a/dom/media/platforms/omx/OmxDataDecoder.cpp +++ b/dom/media/platforms/omx/OmxDataDecoder.cpp @@ -521,14 +521,14 @@ nsTArray>* OmxDataDecoder::GetBuffers( return &mOutPortBuffers; } -void OmxDataDecoder::ResolveInitPromise(const char* aMethodName) { +void OmxDataDecoder::ResolveInitPromise(StaticString aMethodName) { MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn()); - LOG("called from %s", aMethodName); + LOG("called from %s", aMethodName.get()); mInitPromise.ResolveIfExists(mTrackInfo->GetType(), aMethodName); } void OmxDataDecoder::RejectInitPromise(MediaResult aError, - const char* aMethodName) { + StaticString aMethodName) { MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn()); mInitPromise.RejectIfExists(aError, aMethodName); } diff --git a/dom/media/platforms/omx/OmxDataDecoder.h b/dom/media/platforms/omx/OmxDataDecoder.h index 69c388ecee4b..a40aafea3622 100644 --- a/dom/media/platforms/omx/OmxDataDecoder.h +++ b/dom/media/platforms/omx/OmxDataDecoder.h @@ -88,9 +88,9 @@ class OmxDataDecoder final : public MediaDataDecoder, protected: void InitializationTask(); - void ResolveInitPromise(const char* aMethodName); + void ResolveInitPromise(StaticString aMethodName); - void RejectInitPromise(MediaResult aError, const char* aMethodName); + void RejectInitPromise(MediaResult aError, StaticString aMethodName); void OmxStateRunner(); diff --git a/dom/promise/PromiseNativeHandler.h b/dom/promise/PromiseNativeHandler.h index f311f2d29e00..d505316b1314 100644 --- a/dom/promise/PromiseNativeHandler.h +++ b/dom/promise/PromiseNativeHandler.h @@ -12,6 +12,7 @@ #include "js/Value.h" #include "mozilla/ErrorResult.h" #include "mozilla/Maybe.h" +#include "mozilla/StaticString.h" #include "nsISupports.h" namespace mozilla::dom { @@ -58,7 +59,7 @@ class MozPromiseRejectOnDestruction final // (Accepting RefPtr instead of T* because compiler fails to implicitly // convert it at call sites) MozPromiseRejectOnDestruction(const RefPtr& aMozPromise, - const char* aCallSite) + StaticString aCallSite) : mMozPromise(aMozPromise), mCallSite(aCallSite) { MOZ_ASSERT(aMozPromise); } @@ -70,7 +71,7 @@ class MozPromiseRejectOnDestruction final } RefPtr mMozPromise; - const char* mCallSite; + StaticString mCallSite; }; } // namespace mozilla::dom diff --git a/dom/quota/QuotaCommon.cpp b/dom/quota/QuotaCommon.cpp index 71b6186d00af..a05d52ee3ca1 100644 --- a/dom/quota/QuotaCommon.cpp +++ b/dom/quota/QuotaCommon.cpp @@ -38,18 +38,18 @@ namespace mozilla { -RefPtr CreateAndRejectBoolPromise(const char* aFunc, +RefPtr CreateAndRejectBoolPromise(StaticString aFunc, nsresult aRv) { return CreateAndRejectMozPromise(aFunc, aRv); } -RefPtr CreateAndRejectInt64Promise(const char* aFunc, +RefPtr CreateAndRejectInt64Promise(StaticString aFunc, nsresult aRv) { return CreateAndRejectMozPromise(aFunc, aRv); } RefPtr CreateAndRejectBoolPromiseFromQMResult( - const char* aFunc, const QMResult& aRv) { + StaticString aFunc, const QMResult& aRv) { return CreateAndRejectMozPromise(aFunc, aRv); } diff --git a/dom/quota/QuotaCommon.h b/dom/quota/QuotaCommon.h index 648e81a96392..166e8de969d4 100644 --- a/dom/quota/QuotaCommon.h +++ b/dom/quota/QuotaCommon.h @@ -22,6 +22,7 @@ #include "mozilla/MacroArgs.h" #include "mozilla/Maybe.h" #include "mozilla/ResultExtensions.h" +#include "mozilla/StaticString.h" #include "mozilla/Try.h" #if defined(QM_LOG_ERROR_ENABLED) && defined(QM_ERROR_STACKS_ENABLED) # include "mozilla/Variant.h" @@ -1133,7 +1134,7 @@ auto ErrToDefaultOk(const nsresult aValue) -> Result { } template -auto CreateAndRejectMozPromise(const char* aFunc, const RejectValueT& aRv) +auto CreateAndRejectMozPromise(StaticString aFunc, const RejectValueT& aRv) -> decltype(auto) { if constexpr (std::is_same_v) { return MozPromiseType::CreateAndReject(aRv, aFunc); @@ -1142,12 +1143,13 @@ auto CreateAndRejectMozPromise(const char* aFunc, const RejectValueT& aRv) } } -RefPtr CreateAndRejectBoolPromise(const char* aFunc, nsresult aRv); +RefPtr CreateAndRejectBoolPromise(StaticString aFunc, + nsresult aRv); -RefPtr CreateAndRejectInt64Promise(const char* aFunc, +RefPtr CreateAndRejectInt64Promise(StaticString aFunc, nsresult aRv); -RefPtr CreateAndRejectBoolPromiseFromQMResult(const char* aFunc, +RefPtr CreateAndRejectBoolPromiseFromQMResult(StaticString aFunc, const QMResult& aRv); // Like Rust's collect with a step function, not a generic iterator/range. diff --git a/netwerk/ipc/DocumentLoadListener.h b/netwerk/ipc/DocumentLoadListener.h index a8e4ffa7ab72..6f6ad357aebb 100644 --- a/netwerk/ipc/DocumentLoadListener.h +++ b/netwerk/ipc/DocumentLoadListener.h @@ -603,7 +603,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor, RefPtr mContentParent; void RejectOpenPromise(nsresult aStatus, nsresult aLoadGroupStatus, - bool aContinueNavigating, const char* aLocation) { + bool aContinueNavigating, StaticString aLocation) { // It is possible for mOpenPromise to not be set if AsyncOpen failed and // the DocumentChannel got canceled. if (!mOpenPromiseResolved && mOpenPromise) { diff --git a/toolkit/components/uniffi-js/ScaffoldingCall.h b/toolkit/components/uniffi-js/ScaffoldingCall.h index 02b016c5130f..b36a91a88c71 100644 --- a/toolkit/components/uniffi-js/ScaffoldingCall.h +++ b/toolkit/components/uniffi-js/ScaffoldingCall.h @@ -72,7 +72,8 @@ class ScaffoldingCallHandler { // Create a second promise that gets resolved by a background task that // calls the scaffolding function - RefPtr taskPromise = new typename TaskPromiseType::Private(aFuncName.get()); + RefPtr taskPromise = + new typename TaskPromiseType::Private(StaticString(aFuncName)); nsresult dispatchResult = NS_DispatchBackgroundTask( NS_NewRunnableFunction(aFuncName.get(), [args = std::move(convertedArgs), taskPromise, @@ -80,16 +81,16 @@ class ScaffoldingCallHandler { auto callResult = CallScaffoldingFunc( aScaffoldingFunc, std::move(args)); taskPromise->Resolve(std::move(callResult), - aFuncName.get()); + StaticString(aFuncName)); }), NS_DISPATCH_EVENT_MAY_BLOCK); if (NS_FAILED(dispatchResult)) { - taskPromise->Reject(dispatchResult, aFuncName.get()); + taskPromise->Reject(dispatchResult, StaticString(aFuncName)); } // When the background task promise completes, resolve the JS promise taskPromise->Then( - GetCurrentSerialEventTarget(), aFuncName.get(), + GetCurrentSerialEventTarget(), StaticString(aFuncName), [xpcomGlobal, returnPromise, aFuncName](typename TaskPromiseType::ResolveOrRejectValue&& aResult) { if (!aResult.IsResolve()) { diff --git a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp b/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp index 1d1183735541..35dd814acddd 100644 --- a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp +++ b/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp @@ -409,7 +409,7 @@ RefPtr UntrustedModulesProcessor::GetModulesTrust( RefPtr p( new ModulesTrustPromise::Private(__func__)); nsCOMPtr evtTarget(mThread); - const char* source = __func__; + StaticString source = __func__; auto runWrap = [evtTarget = std::move(evtTarget), p, source, run = std::move(run)]() mutable -> void { @@ -441,7 +441,7 @@ UntrustedModulesProcessor::GetProcessedDataInternal() { } RefPtr UntrustedModulesProcessor::GetAllProcessedData( - const char* aSource) { + StaticString aSource) { AssertRunningOnLazyIdleThread(); UntrustedModulesData result; @@ -471,7 +471,7 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() { new UntrustedModulesPromise::Private(__func__)); nsCOMPtr evtTarget(mThread); - const char* source = __func__; + StaticString source = __func__; auto completionRoutine = [evtTarget = std::move(evtTarget), p, self = std::move(self), source, whenProcessed = std::move(whenProcessed)]() { @@ -570,7 +570,7 @@ void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueueChildProcess() { RefPtr self(this); nsCOMPtr evtTarget(mThread); - const char* source = __func__; + constexpr StaticString const source = __func__; auto completionRoutine = [evtTarget = std::move(evtTarget), self = std::move(self), source, whenProcessed = std::move(whenProcessed)]() { diff --git a/toolkit/xre/dllservices/UntrustedModulesProcessor.h b/toolkit/xre/dllservices/UntrustedModulesProcessor.h index b91d88961a3d..3af6eab923f9 100644 --- a/toolkit/xre/dllservices/UntrustedModulesProcessor.h +++ b/toolkit/xre/dllservices/UntrustedModulesProcessor.h @@ -149,7 +149,7 @@ class UntrustedModulesProcessor final : public nsIObserver, Priority aPriority); void CompleteProcessing(ModulesMapResultWithLoads&& aModulesAndLoads); - RefPtr GetAllProcessedData(const char* aSource); + RefPtr GetAllProcessedData(StaticString aSource); private: RefPtr mThread; diff --git a/widget/nsIDeviceContextSpec.cpp b/widget/nsIDeviceContextSpec.cpp index 5ab442415dea..2ec5946bb055 100644 --- a/widget/nsIDeviceContextSpec.cpp +++ b/widget/nsIDeviceContextSpec.cpp @@ -58,8 +58,8 @@ gfxPoint nsIDeviceContextSpec::GetPrintingTranslate() { } RefPtr -nsIDeviceContextSpec::EndDocumentPromiseFromResult(nsresult aResult, - const char* aSite) { +nsIDeviceContextSpec::EndDocumentPromiseFromResult( + nsresult aResult, mozilla::StaticString aSite) { return NS_SUCCEEDED(aResult) ? PrintEndDocumentPromise::CreateAndResolve(true, aSite) : PrintEndDocumentPromise::CreateAndReject(aResult, aSite); diff --git a/widget/nsIDeviceContextSpec.h b/widget/nsIDeviceContextSpec.h index 6afe4ea850a9..33ebaecd6214 100644 --- a/widget/nsIDeviceContextSpec.h +++ b/widget/nsIDeviceContextSpec.h @@ -95,7 +95,7 @@ class nsIDeviceContextSpec : public nsISupports { const char* aCallSite, AsyncEndDocumentFunction aFunction); static RefPtr - EndDocumentPromiseFromResult(nsresult aResult, const char* aSite); + EndDocumentPromiseFromResult(nsresult aResult, mozilla::StaticString aSite); nsCOMPtr mPrintSettings; diff --git a/xpcom/string/nsTLiteralString.h b/xpcom/string/nsTLiteralString.h index 38ffd32bdbdf..0d14614583d2 100644 --- a/xpcom/string/nsTLiteralString.h +++ b/xpcom/string/nsTLiteralString.h @@ -8,6 +8,7 @@ #define nsTLiteralString_h #include "nsTStringRepr.h" +#include "mozilla/StaticString.h" /** * nsTLiteralString_CharT @@ -78,8 +79,10 @@ class nsTLiteralString : public mozilla::detail::nsTStringRepr { * Prohibit get() on temporaries as in "x"_ns.get(). * These should be written as just "x", using a string literal directly. */ - const typename raw_type::type get() const&& = delete; - const typename raw_type::type get() const& { return this->mData; } + constexpr const typename raw_type::type get() const&& = delete; + constexpr const typename raw_type::type get() const& { + return this->mData; + } // At least older gcc versions do not accept these friend declarations, // complaining about an "invalid argument list" here, but not where the actual @@ -110,4 +113,9 @@ class nsTLiteralString : public mozilla::detail::nsTStringRepr { extern template class nsTLiteralString; extern template class nsTLiteralString; +namespace mozilla { +constexpr MOZ_IMPLICIT StaticString::StaticString(nsLiteralCString const& str) + : mStr(str.get()) {} +} // namespace mozilla + #endif diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index c53037e11917..3155d9ea63d3 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 [[nodiscard]] static RefPtr CreateAndResolve( - ResolveValueType_&& aResolveValue, const char* aResolveSite) { + ResolveValueType_&& aResolveValue, StaticString aResolveSite) { static_assert(std::is_convertible_v, "Resolve() argument must be implicitly convertible to " "MozPromise's ResolveValueT"); @@ -269,7 +270,7 @@ class MozPromise : public MozPromiseBase { template [[nodiscard]] static RefPtr CreateAndReject( - RejectValueType_&& aRejectValue, const char* aRejectSite) { + RejectValueType_&& aRejectValue, StaticString aRejectSite) { static_assert(std::is_convertible_v, "Reject() argument must be implicitly convertible to " "MozPromise's RejectValueT"); @@ -281,7 +282,7 @@ class MozPromise : public MozPromiseBase { template [[nodiscard]] static RefPtr CreateAndResolveOrReject( - ResolveOrRejectValueType_&& aValue, const char* aSite) { + ResolveOrRejectValueType_&& aValue, StaticString aSite) { RefPtr p = new MozPromise::Private(aSite); p->ResolveOrReject(std::forward(aValue), aSite); return p; @@ -497,7 +498,7 @@ class MozPromise : public MozPromiseBase { RefPtr 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(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(f))) {} @@ -1030,7 +1031,7 @@ class MozPromise : public MozPromiseBase { public: void ThenInternal(already_AddRefed aThenValue, - const char* aCallSite) { + StaticString aCallSite) { PROMISE_ASSERT(mMagic1 == sMagic && mMagic2 == sMagic && mMagic3 == sMagic && mMagic4 == &mMutex); RefPtr 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 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 mThenValue; RefPtr mReceiver; }; @@ -1146,7 +1147,7 @@ class MozPromise : public MozPromiseBase { template , typename ReturnType = ThenCommand> - ReturnType Then(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + ReturnType Then(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, ThisType* aThisVal, Methods... aMethods) { RefPtr thenValue = new ThenValueType(aResponseTarget, aThisVal, aMethods..., aCallSite); @@ -1156,7 +1157,7 @@ class MozPromise : public MozPromiseBase { template , typename ReturnType = ThenCommand> - ReturnType Then(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + ReturnType Then(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Functions&&... aFunctions) { RefPtr 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 - auto Map(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + auto Map(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Function&& function) { RefPtr> thenValue = new MapValue( aResponseTarget, std::forward(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 - auto MapErr(nsISerialEventTarget* aResponseTarget, const char* aCallSite, + auto MapErr(nsISerialEventTarget* aResponseTarget, StaticString aCallSite, Function&& function) { RefPtr> thenValue = new MapErrValue( aResponseTarget, std::forward(function), aCallSite); @@ -1185,7 +1186,7 @@ class MozPromise : public MozPromiseBase { } void ChainTo(already_AddRefed aChainedPromise, - const char* aCallSite) { + StaticString aCallSite) { MutexAutoLock lock(mMutex); MOZ_DIAGNOSTIC_ASSERT( !IsExclusive || !mHaveRequest, @@ -1194,7 +1195,7 @@ class MozPromise : public MozPromiseBase { RefPtr 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 class MozPromise::Private : public MozPromise { public: - explicit Private(const char* aCreationSite, bool aIsCompletionPromise = false) + explicit Private(StaticString aCreationSite, + bool aIsCompletionPromise = false) : MozPromise(aCreationSite, aIsCompletionPromise) {} template - 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(aResolveValue)); @@ -1357,17 +1359,17 @@ class MozPromise::Private } template - 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(aRejectValue)); @@ -1375,17 +1377,17 @@ class MozPromise::Private } template - 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(aValue); @@ -1403,7 +1405,7 @@ class MozPromise::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::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::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 Ensure(const char* aMethodName) { + already_AddRefed Ensure(StaticString aMethodName) { static_cast(this)->Check(); if (!mPromise) { mPromise = new (typename PromiseType::Private)(aMethodName); @@ -1498,7 +1500,7 @@ class MozPromiseHolderBase { } template - void Resolve(ResolveValueType_&& aResolveValue, const char* aMethodName) { + void Resolve(ResolveValueType_&& aResolveValue, StaticString aMethodName) { static_assert(std::is_convertible_v, "Resolve() argument must be implicitly convertible to " @@ -1513,14 +1515,14 @@ class MozPromiseHolderBase { template void ResolveIfExists(ResolveValueType_&& aResolveValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { Resolve(std::forward(aResolveValue), aMethodName); } } template - void Reject(RejectValueType_&& aRejectValue, const char* aMethodName) { + void Reject(RejectValueType_&& aRejectValue, StaticString aMethodName) { static_assert(std::is_convertible_v, "Reject() argument must be implicitly convertible to " @@ -1534,7 +1536,7 @@ class MozPromiseHolderBase { template void RejectIfExists(RejectValueType_&& aRejectValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { Reject(std::forward(aRejectValue), aMethodName); } @@ -1542,7 +1544,7 @@ class MozPromiseHolderBase { template void ResolveOrReject(ResolveOrRejectValueType_&& aValue, - const char* aMethodName) { + StaticString aMethodName) { static_cast(this)->Check(); MOZ_ASSERT(mPromise); mPromise->ResolveOrReject(std::forward(aValue), @@ -1552,7 +1554,7 @@ class MozPromiseHolderBase { template void ResolveOrRejectIfExists(ResolveOrRejectValueType_&& aValue, - const char* aMethodName) { + StaticString aMethodName) { if (!IsEmpty()) { ResolveOrReject(std::forward(aValue), aMethodName); @@ -1718,7 +1720,7 @@ class ProxyRunnable : public CancelableRunnable { template static RefPtr InvokeAsyncImpl( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { MOZ_ASSERT(aTarget); @@ -1758,7 +1760,7 @@ template = 0> static RefPtr InvokeAsync( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { static_assert( @@ -1777,7 +1779,7 @@ template = 0> static RefPtr InvokeAsync( - nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCallerName, + nsISerialEventTarget* aTarget, ThisType* aThisVal, StaticString aCallerName, RefPtr (ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { static_assert( @@ -1831,7 +1833,7 @@ constexpr static bool IsRefPtrMozPromise>> = true; // Invoke a function object (e.g., lambda) asynchronously. // Return a promise that the function should eventually resolve or reject. template -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 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 000000000000..26c8675b2496 --- /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 +#include "mozilla/Attributes.h" + +// from "nsStringFwd.h" +template +class nsTLiteralString; +using nsLiteralCString = nsTLiteralString; + +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 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 + 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/moz.build b/xpcom/threads/moz.build index 06d10ad33112..09d7649c6f30 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",