Bug 1357463 Add CopyableErrorResult to opt in to auto-cloning ErrorResult values. r=bz

This commit is contained in:
Ben Kelly 2018-04-26 13:50:56 -07:00
Родитель f3a5cf22ea
Коммит d4090dc614
3 изменённых файлов: 146 добавлений и 2 удалений

Просмотреть файл

@ -182,6 +182,12 @@ struct TErrorResult<CleanupPolicy>::Message {
{
return GetErrorArgCount(mErrorNumber) == mArgs.Length();
}
bool operator==(const TErrorResult<CleanupPolicy>::Message& aRight)
{
return mErrorNumber == aRight.mErrorNumber &&
mArgs == aRight.mArgs;
}
};
template<typename CleanupPolicy>
@ -333,6 +339,12 @@ struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
nsCString mMessage;
nsresult mRv;
bool operator==(const TErrorResult<CleanupPolicy>::DOMExceptionInfo& aRight)
{
return mRv == aRight.mRv &&
mMessage == aRight.mMessage;
}
};
template<typename CleanupPolicy>
@ -502,7 +514,6 @@ TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
{
AssertInOwningThread();
aRv.AssertInOwningThread();
aRv.ClearUnionData();
aRv.mResult = mResult;
#ifdef DEBUG
@ -612,6 +623,7 @@ TErrorResult<CleanupPolicy>::NoteJSContextException(JSContext* aCx)
template class TErrorResult<JustAssertCleanupPolicy>;
template class TErrorResult<AssertAndSuppressCleanupPolicy>;
template class TErrorResult<JustSuppressCleanupPolicy>;
template class TErrorResult<ThreadSafeJustSuppressCleanupPolicy>;
} // namespace binding_danger

Просмотреть файл

@ -79,6 +79,23 @@ struct ParamTraits<mozilla::ErrorResult>
}
};
template<>
struct ParamTraits<mozilla::CopyableErrorResult>
{
typedef mozilla::CopyableErrorResult paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
ParamTraits<mozilla::ErrorResult>::Write(aMsg, aParam);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
mozilla::ErrorResult& ref = static_cast<mozilla::ErrorResult&>(*aResult);
return ParamTraits<mozilla::ErrorResult>::Read(aMsg, aIter, &ref);
}
};
} // namespace IPC
#endif

Просмотреть файл

@ -165,6 +165,7 @@ public:
}
operator ErrorResult&();
operator const ErrorResult&() const;
operator OOMReporter&();
void MOZ_MUST_RETURN_FROM_CALLER Throw(nsresult rv) {
@ -391,6 +392,8 @@ public:
return static_cast<uint32_t>(ErrorCode());
}
bool operator==(const ErrorResult& aRight) const;
protected:
nsresult ErrorCode() const {
return mResult;
@ -439,7 +442,9 @@ private:
MOZ_ALWAYS_INLINE void AssertInOwningThread() const {
#ifdef DEBUG
NS_ASSERT_OWNINGTHREAD(TErrorResult);
if (CleanupPolicy::assertSameThread) {
NS_ASSERT_OWNINGTHREAD(TErrorResult);
}
#endif
}
@ -566,16 +571,25 @@ private:
struct JustAssertCleanupPolicy {
static const bool assertHandled = true;
static const bool suppress = false;
static const bool assertSameThread = true;
};
struct AssertAndSuppressCleanupPolicy {
static const bool assertHandled = true;
static const bool suppress = true;
static const bool assertSameThread = true;
};
struct JustSuppressCleanupPolicy {
static const bool assertHandled = false;
static const bool suppress = true;
static const bool assertSameThread = true;
};
struct ThreadSafeJustSuppressCleanupPolicy {
static const bool assertHandled = false;
static const bool suppress = true;
static const bool assertSameThread = false;
};
} // namespace binding_danger
@ -625,6 +639,39 @@ binding_danger::TErrorResult<CleanupPolicy>::operator ErrorResult&()
reinterpret_cast<TErrorResult<AssertAndSuppressCleanupPolicy>*>(this));
}
template<typename CleanupPolicy>
binding_danger::TErrorResult<CleanupPolicy>::operator const ErrorResult&() const
{
return *static_cast<const ErrorResult*>(
reinterpret_cast<const TErrorResult<AssertAndSuppressCleanupPolicy>*>(this));
}
template<typename CleanupPolicy>
bool
binding_danger::TErrorResult<CleanupPolicy>::operator==(const ErrorResult& aRight) const
{
auto right = reinterpret_cast<const TErrorResult<CleanupPolicy>*>(&aRight);
if (mResult != right->mResult) {
return false;
}
if (IsJSException()) {
// js exceptions are always non-equal
return false;
}
if (IsErrorWithMessage()) {
return *mExtra.mMessage == *right->mExtra.mMessage;
}
if (IsDOMException()) {
return *mExtra.mDOMExceptionInfo == *right->mExtra.mDOMExceptionInfo;
}
return true;
}
// A class for use when an ErrorResult should just automatically be ignored.
// This doesn't inherit from ErrorResult so we don't make two separate calls to
// SuppressException.
@ -633,6 +680,74 @@ class IgnoredErrorResult :
{
};
// A class for use when an ErrorResult needs to be copied to a lambda, into
// an IPDL structure, etc. Since this will often involve crossing thread
// boundaries this class will assert if you try to copy a JS exception. Only
// use this if you are propagating internal errors. In general its best
// to use ErrorResult by default and only convert to a CopyableErrorResult when
// you need it.
class CopyableErrorResult :
public binding_danger::TErrorResult<binding_danger::ThreadSafeJustSuppressCleanupPolicy>
{
typedef binding_danger::TErrorResult<binding_danger::ThreadSafeJustSuppressCleanupPolicy> BaseErrorResult;
public:
CopyableErrorResult()
: BaseErrorResult()
{}
explicit CopyableErrorResult(const ErrorResult& aRight)
: BaseErrorResult()
{
auto val = reinterpret_cast<const CopyableErrorResult&>(aRight);
operator=(val);
}
CopyableErrorResult(CopyableErrorResult&& aRHS)
: BaseErrorResult(Move(aRHS))
{}
explicit CopyableErrorResult(nsresult aRv)
: BaseErrorResult(aRv)
{}
void operator=(nsresult rv)
{
BaseErrorResult::operator=(rv);
}
CopyableErrorResult& operator=(CopyableErrorResult&& aRHS)
{
BaseErrorResult::operator=(Move(aRHS));
return *this;
}
CopyableErrorResult(const CopyableErrorResult& aRight)
: BaseErrorResult()
{
operator=(aRight);
}
CopyableErrorResult&
operator=(const CopyableErrorResult& aRight)
{
// We must not copy JS exceptions since it can too easily lead to
// off-thread use. Assert this and fall back to a generic error
// in release builds.
MOZ_DIAGNOSTIC_ASSERT(!IsJSException(),
"Attempt to copy to ErrorResult with a JS exception value.");
MOZ_DIAGNOSTIC_ASSERT(!aRight.IsJSException(),
"Attempt to copy from ErrorResult with a JS exception value.");
if (aRight.IsJSException()) {
SuppressException();
Throw(NS_ERROR_FAILURE);
} else {
aRight.CloneTo(*this);
}
return *this;
}
};
namespace dom {
namespace binding_detail {
class FastErrorResult :