Commit 68b03455 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

mark Function exec pointer as noexcept

Summary:
Function implements move and nuke operations via a type-erased pointer to an exec function. Both operations are explicitly noexcept but the function pointer which these operations call is not marked as noexcept. So the compiler emits unnecessary exception-handling code/data around the call. The exception-handling stuff make generated code larger and in theory may also hinder possible optimizations.

But when the exec function pointer as marked as `noexcept`, the compiler may elide the exception-handling stuff, shrinking generated code and in theory permitting a class of optimizations.

It is not possible for the underlying move operation to throw an exception since, if the move operation of the contained callable could throw an exception, the contained callable would be on-heap and not in-situ, and the underlying move operation would just be an infallible relocation of the in-situ `Function` state.

It is possible for the underlying nuke operation to throw an exception since the destructor of the contained callable could throw an exception. But this is rare. In this case, the exec function would contain exception-handling stuff; but in general, it would not. And this would merely moves where the exception-handling stuff is for the nuke operation, from one side of the type-erasure to the other side.

Reviewed By: ot, philippv, luciang

Differential Revision: D32904616

fbshipit-source-id: 5853a2d81a30bef565b350b72f5f35e6c9c9a45b
parent b1cf29bd
......@@ -565,8 +565,25 @@ struct FunctionTraits<ReturnType(Args...) const noexcept> {
};
#endif
// These are control functions. They type-erase the operations of move-
// construction, destruction, and conversion to bool.
//
// The interface operations are noexcept, so the implementations are as well.
// Having the implementations be noexcept in the type permits callers to omit
// exception-handling machinery.
// Portably aliasing the type pointer-to-noexcept-function is tricky. Compilers
// sometimes reject the straightforward approach with an error. Even with this
// technique, some compilers accept the program while discarding the exception
// specification. This is best-effort.
std::size_t exec_(Op, Data*, Data*) noexcept;
using Exec = decltype(&exec_);
#if __cpp_noexcept_function_type >= 201510L || FOLLY_CPLUSPLUS >= 201702
static_assert(noexcept(Exec(nullptr)(Op{}, nullptr, nullptr)), "");
#endif
template <typename Fun>
std::size_t execSmall(Op o, Data* src, Data* dst) {
std::size_t execSmall(Op o, Data* src, Data* dst) noexcept {
switch (o) {
case Op::MOVE:
::new (static_cast<void*>(&dst->tiny))
......@@ -582,7 +599,7 @@ std::size_t execSmall(Op o, Data* src, Data* dst) {
}
template <typename Fun>
std::size_t execBig(Op o, Data* src, Data* dst) {
std::size_t execBig(Op o, Data* src, Data* dst) noexcept {
switch (o) {
case Op::MOVE:
dst->big = src->big;
......@@ -613,7 +630,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
using Traits = detail::function::FunctionTraits<FunctionType>;
using Call = typename Traits::Call;
using Exec = std::size_t (*)(Op, Data*, Data*);
using Exec = detail::function::Exec;
template <typename Fun>
using IsSmall = detail::function::IsSmall<Fun>;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment