Skip to content

Commit c0b5bf6

Browse files
committed
Refactoring building
This makes most components compilable without needing exceptions. The tails calls in the main code should mean we land on the exception path without any other snmalloc frames in the way.
1 parent a3f758a commit c0b5bf6

File tree

3 files changed

+137
-65
lines changed

3 files changed

+137
-65
lines changed

CMakeLists.txt

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -503,29 +503,30 @@ if(NOT SNMALLOC_HEADER_ONLY_LIBRARY)
503503
message(WARNING "Compiler does not support `-march=native` required by SNMALLOC_OPTIMISE_FOR_CURRENT_MACHINE")
504504
set(SNMALLOC_OPTIMISE_FOR_CURRENT_MACHINE FALSE)
505505
endif()
506-
endif()
506+
endif()
507507

508508

509-
function(add_shim name type)
510-
add_library(${name} ${type} ${ARGN})
509+
function(compile_object name ${ARGN})
510+
add_library(${name} OBJECT ${ARGN})
511511
target_link_libraries(${name} snmalloc)
512512
set_target_properties(${name} PROPERTIES CXX_VISIBILITY_PRESET hidden INTERPROCEDURAL_OPTIMIZATION ${SNMALLOC_COMPILER_SUPPORT_IPO})
513513
target_compile_definitions(${name} PRIVATE "SNMALLOC_USE_${SNMALLOC_CLEANUP}")
514514

515-
if(MSVC)
516-
target_compile_definitions(${name} PRIVATE -D_HAS_EXCEPTIONS=0)
517-
endif()
518-
519515
add_warning_flags(${name})
520516
if(NOT MSVC)
521517
target_compile_definitions(${name} PRIVATE "SNMALLOC_EXPORT=__attribute__((visibility(\"default\")))")
522-
target_compile_options(${name} PRIVATE
523-
-fomit-frame-pointer -ffunction-sections)
518+
set_target_properties(${name} PROPERTIES CXX_VISIBILITY_PRESET hidden INTERPROCEDURAL_OPTIMIZATION ${SNMALLOC_COMPILER_SUPPORT_IPO})
519+
# Make debugging harder, and code faster.
520+
target_compile_options(${name} PRIVATE -fomit-frame-pointer)
524521

522+
set_property(TARGET ${name} PROPERTY POSITION_INDEPENDENT_CODE ON)
523+
524+
# Check for prefetch write support.
525525
check_cxx_compiler_flag("-Werror -Wextra -Wall -mprfchw" SUPPORT_PREFETCH_WRITE)
526526
if (SUPPORT_PREFETCH_WRITE)
527527
target_compile_options(${name} PRIVATE -mprfchw)
528528
endif()
529+
529530
# Static TLS model is unsupported on Haiku.
530531
if (SNMALLOC_STATIC_MODE_TLS)
531532
target_compile_options(${name} PRIVATE -ftls-model=initial-exec)
@@ -536,18 +537,8 @@ endif()
536537
target_compile_options(${name} PRIVATE -march=native)
537538
endif()
538539

539-
# Ensure that we do not link against C++ stdlib when compiling shims.
540-
# If the compiler supports excluding the C++ stdlib implementation, use
541-
# it. Otherwise, fall back to linking the library as if it were C, which
542-
# has roughly the same effect.
543-
# if (NOT ${SNMALLOC_CLEANUP} STREQUAL CXX11_DESTRUCTORS)
544-
# if (SNMALLOC_LINKER_SUPPORT_NOSTDLIBXX)
545-
# target_link_options(${name} PRIVATE -nostdlib++)
546-
# else()
547-
# set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C)
548-
# endif()
549-
# endif()
550540
# Remove all the duplicate new/malloc and free/delete definitions
541+
target_compile_options(${name} PRIVATE -ffunction-sections)
551542
target_link_options(${name} PRIVATE $<$<BOOL:${LLD_WORKS}>:$<$<BOOL:${SNMALLOC_LINK_ICF}>:-Wl,--icf=all> -fuse-ld=lld>)
552543
endif()
553544

@@ -556,40 +547,80 @@ endif()
556547
target_compile_definitions(${name} PRIVATE
557548
SNMALLOC_PAGEID=$<IF:$<BOOL:${SNMALLOC_PAGEID}>,true,false>)
558549

550+
if (SNMALLOC_RUST_LIBC_API)
551+
target_compile_definitions(${name} PRIVATE SNMALLOC_RUST_LIBC_API)
552+
endif()
559553
install(TARGETS ${name} EXPORT snmallocConfig)
554+
endfunction()
555+
556+
function(compile_object_noexc name ${ARGN})
557+
compile_object(${name} ${ARGN})
560558

559+
if(MSVC)
560+
target_compile_definitions(${name} PRIVATE -D_HAS_EXCEPTIONS=0)
561+
else()
562+
# Ensure that we do not link against C++ stdlib when compiling shims.
563+
# If the compiler supports excluding the C++ stdlib implementation, use
564+
# it. Otherwise, fall back to linking the library as if it were C, which
565+
# has roughly the same effect.
566+
if (NOT ${SNMALLOC_CLEANUP} STREQUAL CXX11_DESTRUCTORS)
567+
if (SNMALLOC_LINKER_SUPPORT_NOSTDLIBXX)
568+
target_link_options(${name} PRIVATE -nostdlib++)
569+
else()
570+
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C)
571+
endif()
572+
endif()
573+
endif()
561574
endfunction()
562575

563-
set(SHIM_FILES src/snmalloc/override/malloc.cc src/snmalloc/override/new.cc)
564-
set(SHIM_FILES_MEMCPY src/snmalloc/override/memcpy.cc)
576+
function(add_shim name type)
577+
add_library(${name} ${type})
578+
target_link_libraries(${name} ${ARGN})
579+
install(TARGETS ${name} EXPORT snmallocConfig)
580+
endfunction()
565581

566-
add_shim(snmalloc-new-override STATIC src/snmalloc/override/new.cc)
582+
compile_object(snmalloc_exception_handler src/snmalloc/override/failure.cc)
583+
compile_object_noexc(snmalloc_core src/snmalloc/override/malloc.cc)
584+
compile_object_noexc(snmalloc_new src/snmalloc/override/new.cc)
585+
compile_object_noexc(snmalloc_memcpy src/snmalloc/override/memcpy.cc)
586+
compile_object_noexc(snmalloc_rust src/snmalloc/override/rust.cc)
587+
588+
compile_object(snmalloc_exception_handler_checks src/snmalloc/override/failure.cc)
589+
target_compile_definitions(snmalloc_exception_handler_checks PRIVATE SNMALLOC_CHECK_CLIENT)
590+
compile_object_noexc(snmalloc_core_checks src/snmalloc/override/malloc.cc)
591+
target_compile_definitions(snmalloc_core_checks PRIVATE SNMALLOC_CHECK_CLIENT)
592+
compile_object_noexc(snmalloc_new_checks src/snmalloc/override/new.cc)
593+
target_compile_definitions(snmalloc_new_checks PRIVATE SNMALLOC_CHECK_CLIENT)
594+
compile_object_noexc(snmalloc_memcpy_checks src/snmalloc/override/memcpy.cc)
595+
target_compile_definitions(snmalloc_memcpy_checks PRIVATE SNMALLOC_CHECK_CLIENT)
596+
compile_object_noexc(snmalloc_rust_checks src/snmalloc/override/rust.cc)
597+
target_compile_definitions(snmalloc_rust_checks PRIVATE SNMALLOC_CHECK_CLIENT)
598+
599+
add_shim(snmalloc-new-override STATIC snmalloc_new snmalloc_exception_handler)
567600

568601
if (SNMALLOC_STATIC_LIBRARY)
569-
add_shim(snmallocshim-static STATIC ${SHIM_FILES})
602+
add_shim(snmallocshim-static STATIC snmalloc_core snmalloc_exception_handler snmalloc_new snmalloc_memcpy)
570603
target_compile_definitions(snmallocshim-static PRIVATE
571604
SNMALLOC_STATIC_LIBRARY_PREFIX=${SNMALLOC_STATIC_LIBRARY_PREFIX})
572605
endif ()
573606

607+
set(SNMALLOC_UNCHECK_OBJECTS snmalloc_core snmalloc_exception_handler snmalloc_new)
608+
set(SNMALLOC_CHECK_OBJECTS snmalloc_core_checks snmalloc_exception_handler_checks snmalloc_new_checks)
609+
574610
if(NOT WIN32)
575-
add_shim(snmallocshim SHARED ${SHIM_FILES})
611+
add_shim(snmallocshim SHARED ${SNMALLOC_UNCHECK_OBJECTS})
576612
if (SNMALLOC_MEMCPY_OVERRIDE)
577-
add_shim(snmallocshim-checks-memcpy-only SHARED ${SHIM_FILES} ${SHIM_FILES_MEMCPY})
578-
add_shim(snmallocshim-checks SHARED ${SHIM_FILES} ${SHIM_FILES_MEMCPY})
613+
add_shim(snmallocshim-checks-memcpy-only SHARED ${SNMALLOC_UNCHECK_OBJECTS} snmalloc_memcpy)
614+
add_shim(snmallocshim-checks SHARED ${SNMALLOC_CHECK_OBJECTS} snmalloc_new_checks snmalloc_memcpy_checks)
579615
else()
580-
add_shim(snmallocshim-checks SHARED ${SHIM_FILES})
616+
add_shim(snmallocshim-checks SHARED ${SNMALLOC_CHECK_OBJECTS})
581617
endif()
582-
target_compile_definitions(snmallocshim-checks PRIVATE SNMALLOC_CHECK_CLIENT)
583618
endif()
584619

585620
if(SNMALLOC_RUST_SUPPORT)
586-
add_shim(snmallocshim-rust STATIC src/snmalloc/override/rust.cc)
587-
add_shim(snmallocshim-checks-rust STATIC src/snmalloc/override/rust.cc)
621+
add_shim(snmallocshim-rust STATIC snmalloc_rust)
622+
add_shim(snmallocshim-checks-rust STATIC snmalloc_rust_checks)
588623
target_compile_definitions(snmallocshim-checks-rust PRIVATE SNMALLOC_CHECK_CLIENT)
589-
if (SNMALLOC_RUST_LIBC_API)
590-
target_compile_definitions(snmallocshim-rust PRIVATE SNMALLOC_RUST_LIBC_API)
591-
target_compile_definitions(snmallocshim-checks-rust PRIVATE SNMALLOC_RUST_LIBC_API)
592-
endif()
593624
endif()
594625

595626
if (SNMALLOC_BUILD_TESTING)

src/snmalloc/override/failure.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <cerrno>
2+
#include <cstddef>
3+
#include <new>
4+
5+
namespace snmalloc
6+
{
7+
void* alloc_nothrow(size_t size);
8+
void* alloc_throw(size_t size);
9+
10+
template<bool ShouldThrow>
11+
class SetHandlerContinuations;
12+
13+
void* failure_throw(std::size_t size)
14+
{
15+
auto new_handler = std::get_new_handler();
16+
if (new_handler != nullptr)
17+
{
18+
// Call the new handler, which may throw an exception.
19+
new_handler();
20+
// Retry now new_handler has been called.
21+
// I dislike the unbounded retrying here, but that seems to be what
22+
// other implementations do.
23+
return alloc_nothrow(size);
24+
}
25+
26+
// Throw std::bad_alloc on failure.
27+
throw std::bad_alloc();
28+
}
29+
30+
void* failure_nothrow(std::size_t size)
31+
{
32+
auto new_handler = std::get_new_handler();
33+
if (new_handler != nullptr)
34+
{
35+
try
36+
{
37+
// Call the new handler, which may throw an exception.
38+
new_handler();
39+
}
40+
catch (...)
41+
{
42+
// If the new handler throws, we just return nullptr.
43+
return nullptr;
44+
}
45+
// Retry now new_handler has been called.
46+
return alloc_nothrow(size);
47+
}
48+
49+
// If we are here, then the allocation failed.
50+
// Set errno to ENOMEM, as per the C standard.
51+
errno = ENOMEM;
52+
53+
// Return nullptr on failure.
54+
return nullptr;
55+
}
56+
}

src/snmalloc/override/new.cc

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
namespace snmalloc
2525
{
26+
void* failure_throw(size_t size);
27+
void* failure_nothrow(size_t size);
28+
2629
template<bool ShouldThrow = true>
2730
class SetHandlerContinuations
2831
{
@@ -41,49 +44,31 @@ namespace snmalloc
4144

4245
static void* failure(size_t size)
4346
{
44-
UNUSED(size);
45-
46-
auto new_handler = std::get_new_handler();
47-
if (new_handler != nullptr)
48-
{
49-
if constexpr (ShouldThrow)
50-
{
51-
try
52-
{
53-
// Call the new handler, which may throw an exception.
54-
new_handler();
55-
}
56-
catch (...)
57-
{
58-
// If the new handler throws, we just return nullptr.
59-
return nullptr;
60-
}
61-
}
62-
// Retry now new_handler has been called.
63-
// I dislike the unbounded retrying here, but that seems to be what
64-
// other implementations do.
65-
return snmalloc::alloc<SetHandlerContinuations<ShouldThrow>>(size);
66-
}
67-
6847
if constexpr (ShouldThrow)
6948
{
7049
// Throw std::bad_alloc on failure.
71-
throw std::bad_alloc();
50+
return failure_throw(size);
7251
}
7352
else
7453
{
75-
// If we are here, then the allocation failed.
76-
// Set errno to ENOMEM, as per the C standard.
77-
errno = ENOMEM;
78-
7954
// Return nullptr on failure.
80-
return nullptr;
55+
return failure_nothrow(size);
8156
}
8257
}
8358
};
8459

8560
using NoThrow = SetHandlerContinuations<false>;
8661
using Throw = SetHandlerContinuations<true>;
62+
63+
void* alloc_nothrow(size_t size)
64+
{
65+
return alloc<NoThrow>(size);
66+
}
67+
68+
void* alloc_throw(size_t size)
69+
{
70+
return alloc<Throw>(size);
71+
}
8772
} // namespace snmalloc
8873

8974
void* operator new(size_t size)

0 commit comments

Comments
 (0)