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:
Nathan Froyd 2016-08-12 22:43:49 -04:00
Родитель 55cc220633
Коммит 0a6a801dc2
4 изменённых файлов: 65 добавлений и 2 удалений

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

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