зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1294537 - introduce a non-null-checking placement operator new; r=sunfish,nbp
The default placement operator new is defined to always require that its result be null-checked. A sufficiently smart compiler can remove this check, but not all compilers are sufficiently smart. Better to have a custom placement operator new that will remove null checks in a way defined by the standard.
This commit is contained in:
Родитель
55cc220633
Коммит
0a6a801dc2
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
@ -166,6 +167,13 @@ struct TempObject
|
|||
"Placement new argument type must inherit from TempObject");
|
||||
return pos;
|
||||
}
|
||||
template <class T>
|
||||
inline void* operator new(size_t nbytes, mozilla::NotNullTag, T* pos) {
|
||||
static_assert(mozilla::IsConvertible<T*, TempObject*>::value,
|
||||
"Placement new argument type must inherit from TempObject");
|
||||
MOZ_ASSERT(pos);
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* A version of |operator new| that eschews mandatory null-checks. */
|
||||
|
||||
#ifndef mozilla_OperatorNewExtensions_h
|
||||
#define mozilla_OperatorNewExtensions_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// Credit goes to WebKit for this implementation, cf.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=74676
|
||||
namespace mozilla {
|
||||
enum NotNullTag {
|
||||
KnownNotNull,
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
/*
|
||||
* The logic here is a little subtle. [expr.new] states that if the allocation
|
||||
* function being called returns null, then object initialization must not be
|
||||
* done, and the entirety of the new expression must return null. Non-throwing
|
||||
* (noexcept) functions are defined to return null to indicate failure. The
|
||||
* standard placement operator new is defined in such a way, and so it requires
|
||||
* a null check, even when that null check would be extraneous. Functions
|
||||
* declared without such a specification are defined to throw std::bad_alloc if
|
||||
* they fail, and return a non-null pointer otherwise. We compile without
|
||||
* exceptions, so any placement new overload we define that doesn't declare
|
||||
* itself as noexcept must therefore avoid generating a null check. Below is
|
||||
* just such an overload.
|
||||
*
|
||||
* You might think that MOZ_NONNULL might perform the same function, but
|
||||
* MOZ_NONNULL isn't supported on all of our compilers, and even when it is
|
||||
* supported, doesn't work on all the versions we support. And even keeping
|
||||
* those limitations in mind, we can't put MOZ_NONNULL on the global,
|
||||
* standardized placement new function in any event.
|
||||
*
|
||||
* We do, however, add MOZ_NONNULL here for the potential benefit of static
|
||||
* analysis tools that understand such annotations.
|
||||
*/
|
||||
MOZ_NONNULL(3)
|
||||
inline void*
|
||||
operator new(size_t, mozilla::NotNullTag, void* p)
|
||||
{
|
||||
MOZ_ASSERT(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif // mozilla_OperatorNewExtensions_h
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/ReentrancyGuard.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
@ -62,7 +63,7 @@ struct VectorImpl
|
|||
MOZ_NONNULL(1)
|
||||
static inline void new_(T* aDst, Args&&... aArgs)
|
||||
{
|
||||
new(aDst) T(Forward<Args>(aArgs)...);
|
||||
new(KnownNotNull, aDst) T(Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
/* Destroys constructed objects in the range [aBegin, aEnd). */
|
||||
|
@ -819,7 +820,7 @@ Vector<T, N, AP>::operator=(Vector&& aRhs)
|
|||
{
|
||||
MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited");
|
||||
this->~Vector();
|
||||
new(this) Vector(Move(aRhs));
|
||||
new(KnownNotNull, this) Vector(Move(aRhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ EXPORTS.mozilla = [
|
|||
'NotNull.h',
|
||||
'NullPtr.h',
|
||||
'Opaque.h',
|
||||
'OperatorNewExtensions.h',
|
||||
'Pair.h',
|
||||
'PodOperations.h',
|
||||
'Poison.h',
|
||||
|
|
Загрузка…
Ссылка в новой задаче