Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/pybind11/attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ struct function_record {
/// Pointer to next overload
function_record *next = nullptr;
};
// The main purpose of this macro is to make it easy to pin-point the critically related code
// sections.
#define PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(...) \
static_assert( \
__VA_ARGS__, \
"Violation of precondition for pybind11/functional.h performance optimizations!")

/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
Expand Down
8 changes: 8 additions & 0 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@
# endif
#endif

#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914))
# define PYBIND11_STD_LAUNDER std::launder
# define PYBIND11_HAS_STD_LAUNDER 1
#else
# define PYBIND11_STD_LAUNDER
# define PYBIND11_HAS_STD_LAUNDER 0
#endif

#if defined(PYBIND11_CPP20)
# define PYBIND11_CONSTINIT constinit
# define PYBIND11_DTOR_CONSTEXPR constexpr
Expand Down
8 changes: 7 additions & 1 deletion include/pybind11/functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,14 @@ struct type_caster<std::function<Return(Args...)>> {
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
struct capture {
function_type f;

static capture *from_data(void **data) {
return PYBIND11_STD_LAUNDER(reinterpret_cast<capture *>(data));
}
};
value = ((capture *) &rec->data)->f;
PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(
std::is_standard_layout<capture>::value);
value = capture::from_data(rec->data)->f;
return true;
}
rec = rec->next;
Expand Down
19 changes: 9 additions & 10 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
#endif

#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914))
# define PYBIND11_STD_LAUNDER std::launder
# define PYBIND11_HAS_STD_LAUNDER 1
#else
# define PYBIND11_STD_LAUNDER
# define PYBIND11_HAS_STD_LAUNDER 0
#endif
#if defined(__GNUG__) && !defined(__clang__)
# include <cxxabi.h>
#endif
Expand Down Expand Up @@ -345,6 +338,10 @@ class cpp_function : public function {
using namespace detail;
struct capture {
remove_reference_t<Func> f;

static capture *from_data(void **data) {
return PYBIND11_STD_LAUNDER(reinterpret_cast<capture *>(data));
}
};

/* Store the function including any extra state it might have (e.g. a lambda capture
Expand All @@ -364,7 +361,7 @@ class cpp_function : public function {
PYBIND11_WARNING_DISABLE_GCC("-Wplacement-new")
#endif

new ((capture *) &rec->data) capture{std::forward<Func>(f)};
new (capture::from_data(rec->data)) capture{std::forward<Func>(f)};

#if !PYBIND11_HAS_STD_LAUNDER
PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing")
Expand All @@ -374,8 +371,8 @@ class cpp_function : public function {
// a significant refactoring it's "impossible" to solve.
if (!std::is_trivially_destructible<capture>::value) {
rec->free_data = [](function_record *r) {
auto data = PYBIND11_STD_LAUNDER((capture *) &r->data);
(void) data;
auto data = capture::from_data(r->data);
(void) data; // suppress "unused variable" warnings
data->~capture();
};
}
Expand Down Expand Up @@ -492,6 +489,8 @@ class cpp_function : public function {
using FunctionType = Return (*)(Args...);
constexpr bool is_function_ptr
= std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);
PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(
!is_function_ptr || std::is_standard_layout<capture>::value);
if (is_function_ptr) {
rec->is_stateless = true;
rec->data[1]
Expand Down
Loading