diff --git a/gfx/layers/ipc/LayersMessageUtils.h b/gfx/layers/ipc/LayersMessageUtils.h index c06ad6f69f80..01a780677f37 100644 --- a/gfx/layers/ipc/LayersMessageUtils.h +++ b/gfx/layers/ipc/LayersMessageUtils.h @@ -1124,9 +1124,9 @@ struct ParamTraits { MOZ_ASSERT(rv, "Serialize ##type_## failed"); \ WriteParam(aWriter, std::move(v)); \ } \ - static mozilla::Maybe Read(MessageReader* aReader) { \ + static ReadResult Read(MessageReader* aReader) { \ mozilla::ipc::ByteBuf in; \ - mozilla::Maybe result; \ + ReadResult result; \ if (!ReadParam(aReader, &in) || !in.mData) { \ return result; \ } \ @@ -1135,7 +1135,7 @@ struct ParamTraits { if (!Servo_##type_##_Deserialize(&in, value.addr())) { \ return result; \ } \ - result.emplace(std::move(*value.addr())); \ + result = std::move(*value.addr()); \ value.addr()->~paramType(); \ return result; \ } \ diff --git a/ipc/chromium/src/chrome/common/ipc_message_utils.h b/ipc/chromium/src/chrome/common/ipc_message_utils.h index daf2ca71b398..9794b840214f 100644 --- a/ipc/chromium/src/chrome/common/ipc_message_utils.h +++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h @@ -208,6 +208,156 @@ class MOZ_STACK_CLASS MessageReader final { mozilla::ipc::IProtocol* actor_; }; +namespace detail { + +// Helper for checking `T::kHasDeprecatedReadParamPrivateConstructor` using a +// fallback when the member isn't defined. +template +inline constexpr auto HasDeprecatedReadParamPrivateConstructor(int) + -> decltype(T::kHasDeprecatedReadParamPrivateConstructor) { + return T::kHasDeprecatedReadParamPrivateConstructor; +} + +template +inline constexpr bool HasDeprecatedReadParamPrivateConstructor(...) { + return false; +} + +} // namespace detail + +/** + * Result type returned from some `ParamTraits::Read` implementations, and + * from `IPC::ReadParam(MessageReader*)`. Either contains the value or + * indicates a failure to deserialize. + * + * This type can be thought of as a variant on `Maybe`, except that it + * unconditionally constructs the underlying value if it is default + * constructible. This helps keep code size down, especially when calling + * outparameter-based ReadParam implementations (bug 1815177). + */ +template || + detail::HasDeprecatedReadParamPrivateConstructor(0)> +class ReadResult { + public: + ReadResult() = default; + + template , int> = 0> + MOZ_IMPLICIT ReadResult(U&& aData) + : mIsOk(true), mData(std::forward(aData)) {} + + template + explicit ReadResult(std::in_place_t, Args&&... aArgs) + : mIsOk(true), mData(std::forward(aArgs)...) {} + + ReadResult(const ReadResult&) = default; + ReadResult(ReadResult&&) = default; + + template , int> = 0> + MOZ_IMPLICIT ReadResult& operator=(U&& aData) { + mIsOk = true; + mData = std::forward(aData); + return *this; + } + + ReadResult& operator=(const ReadResult&) = default; + ReadResult& operator=(ReadResult&&) noexcept = default; + + // Check if the ReadResult contains a valid value. + explicit operator bool() const { return isOk(); } + bool isOk() const { return mIsOk; } + + // Get the data from this ReadResult. + T& get() { + MOZ_ASSERT(mIsOk); + return mData; + } + const T& get() const { + MOZ_ASSERT(mIsOk); + return mData; + } + + T& operator*() { return get(); } + const T& operator*() const { return get(); } + + T* operator->() { return &get(); } + const T* operator->() const { return &get(); } + + // Try to extract a `Maybe` from this ReadResult. + mozilla::Maybe TakeMaybe() { + if (mIsOk) { + mIsOk = false; + return mozilla::Some(std::move(mData)); + } + return mozilla::Nothing(); + } + + // Get the underlying data from this ReadResult, even if not OK. + // + // This is only available for types which are default constructible, and is + // used to optimize old-style `ReadParam` calls. + T& GetStorage() { return mData; } + + // Compliment to `GetStorage` used to set the ReadResult into an OK state + // without constructing the underlying value. + void SetOk(bool aIsOk) { mIsOk = aIsOk; } + + private: + bool mIsOk = false; + T mData{}; +}; + +template +class ReadResult { + public: + ReadResult() = default; + + template , int> = 0> + MOZ_IMPLICIT ReadResult(U&& aData) + : mData(std::in_place, std::forward(aData)) {} + + template + explicit ReadResult(std::in_place_t, Args&&... aArgs) + : mData(std::in_place, std::forward(aArgs)...) {} + + ReadResult(const ReadResult&) = default; + ReadResult(ReadResult&&) = default; + + template , int> = 0> + MOZ_IMPLICIT ReadResult& operator=(U&& aData) { + mData.reset(); + mData.emplace(std::forward(aData)); + return *this; + } + + ReadResult& operator=(const ReadResult&) = default; + ReadResult& operator=(ReadResult&&) noexcept = default; + + // Check if the ReadResult contains a valid value. + explicit operator bool() const { return isOk(); } + bool isOk() const { return mData.isSome(); } + + // Get the data from this ReadResult. + T& get() { return mData.ref(); } + const T& get() const { return mData.ref(); } + + T& operator*() { return get(); } + const T& operator*() const { return get(); } + + T* operator->() { return &get(); } + const T* operator->() const { return &get(); } + + // Try to extract a `Maybe` from this ReadResult. + mozilla::Maybe TakeMaybe() { return std::move(mData); } + + // These methods are only available if the type is default constructible. + T& GetStorage() = delete; + void SetOk(bool aIsOk) = delete; + + private: + mozilla::Maybe mData; +}; + //----------------------------------------------------------------------------- // An iterator class for reading the fields contained within a Message. @@ -313,33 +463,24 @@ template inline bool WARN_UNUSED_RESULT ReadParam(MessageReader* reader, P* p) { if constexpr (!detail::ParamTraitsReadUsesOutParam

()) { auto maybe = ParamTraits

::Read(reader); - if (maybe.isNothing()) { - return false; + if (maybe) { + *p = std::move(*maybe); + return true; } - *p = maybe.extract(); - return true; + return false; } else { return ParamTraits

::Read(reader, p); } } template -inline mozilla::Maybe

WARN_UNUSED_RESULT ReadParam(MessageReader* reader) { +inline ReadResult

WARN_UNUSED_RESULT ReadParam(MessageReader* reader) { if constexpr (!detail::ParamTraitsReadUsesOutParam

()) { return ParamTraits

::Read(reader); - } else if constexpr (std::is_default_constructible_v

) { - mozilla::Maybe

p{std::in_place}; - if (!ParamTraits

::Read(reader, p.ptr())) { - p.reset(); - } - return p; } else { - static_assert(P::kHasDeprecatedReadParamPrivateConstructor); - P p{}; - if (!ParamTraits

::Read(reader, &p)) { - return mozilla::Nothing(); - } - return mozilla::Some(std::move(p)); + ReadResult

p; + p.SetOk(ParamTraits

::Read(reader, &p.GetStorage())); + return p; } } @@ -507,7 +648,7 @@ bool ReadSequenceParamImpl(MessageReader* reader, mozilla::Maybe&& data, if (!elt) { return false; } - *data.ref() = elt.extract(); + *data.ref() = std::move(*elt); ++data.ref(); } return true; @@ -920,16 +1061,16 @@ struct ParamTraitsMozilla> { ParamTraits::Write(writer, p.get()); } - static mozilla::Maybe> Read(MessageReader* reader) { + static ReadResult> Read(MessageReader* reader) { auto ptr = ReadParam(reader); if (!ptr) { - return mozilla::Nothing(); + return {}; } if (!*ptr) { reader->FatalError("unexpected null value"); - return mozilla::Nothing(); + return {}; } - return mozilla::Some(mozilla::WrapNotNull(std::move(*ptr))); + return mozilla::WrapNotNull(std::move(*ptr)); } }; diff --git a/ipc/glue/IPCForwards.h b/ipc/glue/IPCForwards.h index 32a7a087838b..8aef88525745 100644 --- a/ipc/glue/IPCForwards.h +++ b/ipc/glue/IPCForwards.h @@ -22,14 +22,17 @@ namespace IPC { class Message; class MessageReader; class MessageWriter; -template -inline mozilla::Maybe

ReadParam(MessageReader*); +template +class ReadResult; } // namespace IPC // TODO(bug 1812271): Remove users of this macro. #define ALLOW_DEPRECATED_READPARAM \ + public: \ enum { kHasDeprecatedReadParamPrivateConstructor = true }; \ - template \ - friend mozilla::Maybe

IPC::ReadParam(IPC::MessageReader*); + template \ + friend class IPC::ReadResult; \ + \ + private: #endif diff --git a/ipc/glue/IPCMessageUtilsSpecializations.h b/ipc/glue/IPCMessageUtilsSpecializations.h index d83461e0ff00..25507dd779f9 100644 --- a/ipc/glue/IPCMessageUtilsSpecializations.h +++ b/ipc/glue/IPCMessageUtilsSpecializations.h @@ -458,7 +458,7 @@ struct ParamTraits> { return false; } if (isSome) { - mozilla::Maybe tmp = ReadParam(reader); + mozilla::Maybe tmp = ReadParam(reader).TakeMaybe(); if (!tmp) { return false; } diff --git a/ipc/glue/SideVariant.h b/ipc/glue/SideVariant.h index 8ac0bb9087a5..3082feebde30 100644 --- a/ipc/glue/SideVariant.h +++ b/ipc/glue/SideVariant.h @@ -161,16 +161,24 @@ struct ParamTraits> { } } - static mozilla::Maybe Read(IPC::MessageReader* aReader) { + static ReadResult Read(IPC::MessageReader* aReader) { if (!aReader->GetActor()) { aReader->FatalError("actor required to deserialize this type"); - return mozilla::Nothing(); + return {}; } if (aReader->GetActor()->GetSide() == mozilla::ipc::ParentSide) { - return ReadParam(aReader); + auto parentSide = ReadParam(aReader); + if (!parentSide) { + return {}; + } + return std::move(*parentSide); } - return ReadParam(aReader); + auto childSide = ReadParam(aReader); + if (!childSide) { + return {}; + } + return std::move(*childSide); } }; diff --git a/ipc/ipdl/ipdl/cxx/ast.py b/ipc/ipdl/ipdl/cxx/ast.py index e28cdcf5a14d..62790ef4dedb 100644 --- a/ipc/ipdl/ipdl/cxx/ast.py +++ b/ipc/ipdl/ipdl/cxx/ast.py @@ -855,16 +855,6 @@ class ExprMove(ExprCall): ExprCall.__init__(self, ExprVar("std::move"), args=[arg]) -class ExprNothing(ExprCall): - def __init__(self): - ExprCall.__init__(self, ExprVar("mozilla::Nothing")) - - -class ExprSome(ExprCall): - def __init__(self, arg): - ExprCall.__init__(self, ExprVar("mozilla::Some"), args=[arg]) - - class ExprNew(Node): # XXX taking some poetic license ... def __init__(self, ctype, args=[], newargs=None): diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index ef317939bbc7..c3b1e30b6e57 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -317,6 +317,16 @@ def _cxxMaybeType(basetype, const=False, ref=False): ) +def _cxxReadResultType(basetype, const=False, ref=False): + return Type( + "IPC::ReadResult", + T=basetype, + const=const, + ref=ref, + hasimplicitcopyctor=basetype.hasimplicitcopyctor, + ) + + def _cxxNotNullType(basetype, const=False, ref=False): return Type( "mozilla::NotNull", @@ -462,6 +472,10 @@ def errfnUnreachable(msg): return [_logicError(msg)] +def readResultError(): + return ExprCode("{}") + + class _DestroyReason: @staticmethod def Type(): @@ -2016,14 +2030,14 @@ class _ParamTraits: ifbad = StmtIf(ExprNot(readbytes)) errmsg = "Error bulk reading fields from %s" % first.ipdltype.name() ifbad.addifstmts( - [cls.fatalError(cls.readervar, errmsg), StmtReturn(ExprNothing())] + [cls.fatalError(cls.readervar, errmsg), StmtReturn(readResultError())] ) block.addstmt(ifbad) block.addstmts( cls.readSentinel( cls.readervar, cls.bulkSentinelKey(fields), - errfnSentinel(ExprNothing())(errmsg), + errfnSentinel(readResultError())(errmsg), ) ) @@ -2074,7 +2088,7 @@ class _ParamTraits: @classmethod def _checkedRead(cls, ipdltype, cxxtype, var, sentinelKey, what): def errfn(msg): - return [cls.fatalError(cls.readervar, msg), StmtReturn(ExprNothing())] + return [cls.fatalError(cls.readervar, msg), StmtReturn(readResultError())] return cls.checkedRead( ipdltype, @@ -2084,7 +2098,7 @@ class _ParamTraits: errfn=errfn, paramtype=what, sentinelKey=sentinelKey, - errfnSentinel=errfnSentinel(ExprNothing()), + errfnSentinel=errfnSentinel(readResultError()), ) @classmethod @@ -2119,15 +2133,14 @@ class _ParamTraits: writemthd.addstmts(write) pt.addstmt(writemthd) - # static Maybe Read(MessageReader*); - outtype = Type("paramType", ptr=True) + # static ReadResult Read(MessageReader*); readmthd = MethodDefn( MethodDecl( "Read", params=[ Decl(Type("IPC::MessageReader", ptr=True), cls.readervar.name), ], - ret=Type("mozilla::Maybe"), + ret=Type("IPC::ReadResult"), methodspec=MethodSpec.STATIC, ) ) @@ -2185,9 +2198,12 @@ class _ParamTraits: MOZ_RELEASE_ASSERT( ${readervar}->GetActor(), "Cannot deserialize managed actors without an actor"); - return ${readervar}->GetActor() - ->ReadActor(${readervar}, true, ${actortype}, ${protocolid}) - .map([](mozilla::ipc::IProtocol* actor) { return static_cast<${cxxtype}>(actor); }); + mozilla::Maybe actor = ${readervar}->GetActor() + ->ReadActor(${readervar}, true, ${actortype}, ${protocolid}); + if (actor.isSome()) { + return static_cast<${cxxtype}>(actor.ref()); + } + return {}; """, readervar=cls.readervar, actortype=ExprLiteral.String(actortype.name()), @@ -2249,7 +2265,7 @@ class _ParamTraits: resultvar = ExprVar("result__") read.append( StmtDecl( - Decl(_cxxMaybeType(Type("paramType")), resultvar.name), + Decl(_cxxReadResultType(Type("paramType")), resultvar.name), initargs=[ExprVar("std::in_place")] + ctorargs, ) ) @@ -2333,7 +2349,7 @@ class _ParamTraits: origenum, "variant " + origenum + " of union " + uniontype.name(), ), - StmtReturn(ExprSome(ExprMove(tmpvar))), + StmtReturn(ExprMove(tmpvar)), ] ) readswitch.addcase(caselabel, readcase) @@ -2357,7 +2373,7 @@ class _ParamTraits: cls.fatalError( cls.readervar, "unknown variant of union " + uniontype.name() ), - StmtReturn(ExprNothing()), + StmtReturn(readResultError()), ] ), )