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
This commit is contained in:
Ray Kraesig 2024-04-24 17:02:49 +00:00
parent 53b8555503
commit e2ee2f11df
32 changed files with 239 additions and 121 deletions

View File

@ -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);
}

View File

@ -48,17 +48,17 @@ class FetchServicePromises final {
RefPtr<FetchServiceResponseEndPromise> 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;

View File

@ -177,7 +177,7 @@ FileSystemAccessHandle::BeginInit() {
mLocked = true;
auto CreateAndRejectInitPromise = [](const char* aFunc, nsresult aRv) {
auto CreateAndRejectInitPromise = [](StaticString aFunc, nsresult aRv) {
return CreateAndRejectMozPromise<InitPromise>(aFunc, aRv);
};

View File

@ -994,7 +994,7 @@ class HTMLMediaElement::MediaStreamRenderer {
graph->CreateSourceTrack(MediaSegment::AUDIO));
}
void ResolveAudioDevicePromiseIfExists(const char* aMethodName) {
void ResolveAudioDevicePromiseIfExists(StaticString aMethodName) {
if (mSetAudioDevicePromise.IsEmpty()) {
return;
}

View File

@ -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(); }

View File

@ -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<DataPromise<Type>> EnsurePromise(const char* aMethodName) {
RefPtr<DataPromise<Type>> 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;

View File

@ -2516,7 +2516,7 @@ void MediaManager::Dispatch(already_AddRefed<Runnable> task) {
template <typename MozPromiseType, typename FunctionType>
/* static */
RefPtr<MozPromiseType> MediaManager::Dispatch(const char* aName,
RefPtr<MozPromiseType> MediaManager::Dispatch(StaticString aName,
FunctionType&& aFunction) {
MozPromiseHolder<MozPromiseType> holder;
RefPtr<MozPromiseType> promise = holder.Ensure(aName);

View File

@ -220,7 +220,7 @@ class MediaManager final : public nsIMediaManagerService,
* manager thread.
*/
template <typename MozPromiseType, typename FunctionType>
static RefPtr<MozPromiseType> Dispatch(const char* aName,
static RefPtr<MozPromiseType> Dispatch(StaticString aName,
FunctionType&& aFunction);
#ifdef DEBUG

View File

@ -68,12 +68,12 @@ bool MediaTimer::OnMediaTimerThread() {
}
RefPtr<MediaTimerPromise> MediaTimer::WaitFor(const TimeDuration& aDuration,
const char* aCallSite) {
StaticString aCallSite) {
return WaitUntil(TimeStamp::Now() + aDuration, aCallSite);
}
RefPtr<MediaTimerPromise> MediaTimer::WaitUntil(const TimeStamp& aTimeStamp,
const char* aCallSite) {
StaticString aCallSite) {
MonitorAutoLock mon(mMonitor);
TIMER_LOG("MediaTimer::WaitUntil %" PRId64, RelativeMicroseconds(aTimeStamp));
Entry e(aTimeStamp, aCallSite);

View File

@ -44,9 +44,9 @@ class MediaTimer {
DispatchDestroy());
RefPtr<MediaTimerPromise> WaitFor(const TimeDuration& aDuration,
const char* aCallSite);
StaticString aCallSite);
RefPtr<MediaTimerPromise> 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<MediaTimerPromise::Private> mPromise;
explicit Entry(const TimeStamp& aTimeStamp, const char* aCallSite)
explicit Entry(const TimeStamp& aTimeStamp, StaticString aCallSite)
: mTimeStamp(aTimeStamp),
mPromise(new MediaTimerPromise::Private(aCallSite)) {}

View File

@ -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);
}

View File

@ -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<SeekTarget> mTarget;
MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;

View File

@ -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<decltype(param1)>::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<decltype(param1)>::type; \
using ParamType2 = std::remove_reference<decltype(param2)>::type; \
mManagerThread->Dispatch(NS_NewRunnableFunction( \
@ -188,7 +189,7 @@ void MFCDMChild::AssertSendable() {
template <typename PromiseType>
already_AddRefed<PromiseType> MFCDMChild::InvokeAsync(
std::function<void()>&& aCall, const char* aCallerName,
std::function<void()>&& aCall, StaticString aCallerName,
MozPromiseHolder<PromiseType>& aPromise) {
AssertSendable();

View File

@ -30,7 +30,7 @@ class MFCDMChild final : public PMFCDMChild {
template <typename PromiseType>
already_AddRefed<PromiseType> InvokeAsync(
std::function<void()>&& aCall, const char* aCallerName,
std::function<void()>&& aCall, StaticString aCallerName,
MozPromiseHolder<PromiseType>& aPromise);
using InitPromise = MozPromise<MFCDMInitIPDL, nsresult, true>;

View File

@ -94,7 +94,7 @@ class VoidCallback final : public nsIKeyValueVoidCallback {
mResultPromise.Reject(NS_ERROR_FAILURE, __func__);
return NS_OK;
}
RefPtr<GenericPromise> Ensure(const char* aMethodName) {
RefPtr<GenericPromise> Ensure(StaticString aMethodName) {
return mResultPromise.Ensure(aMethodName);
}

View File

@ -201,7 +201,7 @@ void GMPVideoDecoder::Terminated() {
}
void GMPVideoDecoder::ProcessReorderQueue(
MozPromiseHolder<DecodePromise>& aPromise, const char* aMethodName) {
MozPromiseHolder<DecodePromise>& aPromise, StaticString aMethodName) {
if (aPromise.IsEmpty()) {
return;
}

View File

@ -72,7 +72,7 @@ class GMPVideoDecoder final : public MediaDataDecoder,
virtual GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(MediaRawData* aSample);
virtual const VideoInfo& GetConfig() const;
void ProcessReorderQueue(MozPromiseHolder<DecodePromise>& aPromise,
const char* aMethodName);
StaticString aMethodName);
private:
~GMPVideoDecoder() = default;

View File

@ -521,14 +521,14 @@ nsTArray<RefPtr<OmxPromiseLayer::BufferData>>* 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);
}

View File

@ -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();

View File

@ -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<T> instead of T* because compiler fails to implicitly
// convert it at call sites)
MozPromiseRejectOnDestruction(const RefPtr<T>& aMozPromise,
const char* aCallSite)
StaticString aCallSite)
: mMozPromise(aMozPromise), mCallSite(aCallSite) {
MOZ_ASSERT(aMozPromise);
}
@ -70,7 +71,7 @@ class MozPromiseRejectOnDestruction final
}
RefPtr<T> mMozPromise;
const char* mCallSite;
StaticString mCallSite;
};
} // namespace mozilla::dom

View File

@ -38,18 +38,18 @@
namespace mozilla {
RefPtr<BoolPromise> CreateAndRejectBoolPromise(const char* aFunc,
RefPtr<BoolPromise> CreateAndRejectBoolPromise(StaticString aFunc,
nsresult aRv) {
return CreateAndRejectMozPromise<BoolPromise>(aFunc, aRv);
}
RefPtr<Int64Promise> CreateAndRejectInt64Promise(const char* aFunc,
RefPtr<Int64Promise> CreateAndRejectInt64Promise(StaticString aFunc,
nsresult aRv) {
return CreateAndRejectMozPromise<Int64Promise>(aFunc, aRv);
}
RefPtr<BoolPromise> CreateAndRejectBoolPromiseFromQMResult(
const char* aFunc, const QMResult& aRv) {
StaticString aFunc, const QMResult& aRv) {
return CreateAndRejectMozPromise<BoolPromise>(aFunc, aRv);
}

View File

@ -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<V, nsresult> {
}
template <typename MozPromiseType, typename RejectValueT = nsresult>
auto CreateAndRejectMozPromise(const char* aFunc, const RejectValueT& aRv)
auto CreateAndRejectMozPromise(StaticString aFunc, const RejectValueT& aRv)
-> decltype(auto) {
if constexpr (std::is_same_v<RejectValueT, nsresult>) {
return MozPromiseType::CreateAndReject(aRv, aFunc);
@ -1142,12 +1143,13 @@ auto CreateAndRejectMozPromise(const char* aFunc, const RejectValueT& aRv)
}
}
RefPtr<BoolPromise> CreateAndRejectBoolPromise(const char* aFunc, nsresult aRv);
RefPtr<BoolPromise> CreateAndRejectBoolPromise(StaticString aFunc,
nsresult aRv);
RefPtr<Int64Promise> CreateAndRejectInt64Promise(const char* aFunc,
RefPtr<Int64Promise> CreateAndRejectInt64Promise(StaticString aFunc,
nsresult aRv);
RefPtr<BoolPromise> CreateAndRejectBoolPromiseFromQMResult(const char* aFunc,
RefPtr<BoolPromise> CreateAndRejectBoolPromiseFromQMResult(StaticString aFunc,
const QMResult& aRv);
// Like Rust's collect with a step function, not a generic iterator/range.

View File

@ -603,7 +603,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
RefPtr<dom::ContentParent> 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) {

View File

@ -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()) {

View File

@ -409,7 +409,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrust(
RefPtr<ModulesTrustPromise::Private> p(
new ModulesTrustPromise::Private(__func__));
nsCOMPtr<nsISerialEventTarget> 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<UntrustedModulesPromise> UntrustedModulesProcessor::GetAllProcessedData(
const char* aSource) {
StaticString aSource) {
AssertRunningOnLazyIdleThread();
UntrustedModulesData result;
@ -471,7 +471,7 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() {
new UntrustedModulesPromise::Private(__func__));
nsCOMPtr<nsISerialEventTarget> 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<UntrustedModulesProcessor> self(this);
nsCOMPtr<nsISerialEventTarget> 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)]() {

View File

@ -149,7 +149,7 @@ class UntrustedModulesProcessor final : public nsIObserver,
Priority aPriority);
void CompleteProcessing(ModulesMapResultWithLoads&& aModulesAndLoads);
RefPtr<UntrustedModulesPromise> GetAllProcessedData(const char* aSource);
RefPtr<UntrustedModulesPromise> GetAllProcessedData(StaticString aSource);
private:
RefPtr<LazyIdleThread> mThread;

View File

@ -58,8 +58,8 @@ gfxPoint nsIDeviceContextSpec::GetPrintingTranslate() {
}
RefPtr<PrintEndDocumentPromise>
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);

View File

@ -95,7 +95,7 @@ class nsIDeviceContextSpec : public nsISupports {
const char* aCallSite, AsyncEndDocumentFunction aFunction);
static RefPtr<mozilla::gfx::PrintEndDocumentPromise>
EndDocumentPromiseFromResult(nsresult aResult, const char* aSite);
EndDocumentPromiseFromResult(nsresult aResult, mozilla::StaticString aSite);
nsCOMPtr<nsIPrintSettings> mPrintSettings;

View File

@ -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<T> {
* 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<T, int>::type get() const&& = delete;
const typename raw_type<T, int>::type get() const& { return this->mData; }
constexpr const typename raw_type<T, int>::type get() const&& = delete;
constexpr const typename raw_type<T, int>::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<T> {
extern template class nsTLiteralString<char>;
extern template class nsTLiteralString<char16_t>;
namespace mozilla {
constexpr MOZ_IMPLICIT StaticString::StaticString(nsLiteralCString const& str)
: mStr(str.get()) {}
} // namespace mozilla
#endif

View File

@ -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 "

View File

@ -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

View File

@ -70,6 +70,7 @@ EXPORTS.mozilla += [
"SpinEventLoopUntil.h",
"StateMirroring.h",
"StateWatching.h",
"StaticString.h",
"SynchronizedEventQueue.h",
"SyncRunnable.h",
"TaskController.h",