[libc-commits] [libc] [libc] add basic arena allocator (PR #121173)
Tristan Ross via libc-commits
libc-commits at lists.llvm.org
Thu Dec 26 17:48:46 PST 2024
https://github.com/RossComputerGuy created https://github.com/llvm/llvm-project/pull/121173
This PR adds support for multiple allocator implementations. This will be beneficial for distros and embedded systems where different kinds of allocators can be better than others. To start out with, I just added a primitive arena allocator. This PR also adds `getpagesize` which supports dynamic and static page sizes.
>From 80079de7da385496a22338896b7f79836d763e00 Mon Sep 17 00:00:00 2001
From: Tristan Ross <tristan.ross at midstall.com>
Date: Thu, 26 Dec 2024 11:48:23 -0800
Subject: [PATCH 1/2] [libc] add getpagesize
---
libc/config/config.json | 6 +++++
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/docs/configure.rst | 2 ++
libc/hdrgen/yaml/unistd.yaml | 6 +++++
libc/src/__support/macros/CMakeLists.txt | 6 +++++
libc/src/__support/macros/page_size.h | 17 +++++++++++++
libc/src/unistd/CMakeLists.txt | 29 +++++++++++++++++++++++
libc/src/unistd/generic/CMakeLists.txt | 12 ++++++++++
libc/src/unistd/generic/getpagesize.cpp | 22 +++++++++++++++++
libc/src/unistd/getpagesize.h | 20 ++++++++++++++++
libc/src/unistd/linux/CMakeLists.txt | 13 ++++++++++
libc/src/unistd/linux/getpagesize.cpp | 29 +++++++++++++++++++++++
libc/test/src/unistd/CMakeLists.txt | 10 ++++++++
libc/test/src/unistd/getpagesize_test.cpp | 16 +++++++++++++
15 files changed, 190 insertions(+)
create mode 100644 libc/src/__support/macros/page_size.h
create mode 100644 libc/src/unistd/generic/CMakeLists.txt
create mode 100644 libc/src/unistd/generic/getpagesize.cpp
create mode 100644 libc/src/unistd/getpagesize.h
create mode 100644 libc/src/unistd/linux/getpagesize.cpp
create mode 100644 libc/test/src/unistd/getpagesize_test.cpp
diff --git a/libc/config/config.json b/libc/config/config.json
index 9a5d5c3c68da60..23c057570d6fd7 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -116,5 +116,11 @@
"value": true,
"doc": "Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior."
}
+ },
+ "unistd": {
+ "LIBC_CONF_PAGE_SIZE": {
+ "value": "LIBC_PAGE_SIZE_SYSTEM",
+ "doc": "The value to use for the system page size, acceptable values are LIBC_CONF_PAGE_SIZE_SYSTEM, LIBC_CONF_PAGE_SIZE_4K, LIBC_CONF_PAGE_SIZE_16K, LIBC_CONF_PAGE_SIZE_64K."
+ }
}
}
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 00f0c6a8bfb8e4..ce67118545c9a5 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -323,6 +323,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.ftruncate
libc.src.unistd.getcwd
libc.src.unistd.geteuid
+ libc.src.unistd.getpagesize
libc.src.unistd.getpid
libc.src.unistd.getppid
libc.src.unistd.gettid
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 49a8d61b938027..3b53396b5943b2 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -320,6 +320,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.ftruncate
libc.src.unistd.getcwd
libc.src.unistd.geteuid
+ libc.src.unistd.getpagesize
libc.src.unistd.getpid
libc.src.unistd.getppid
libc.src.unistd.gettid
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 3db750b1aed214..89bfd93b8a99c2 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -60,3 +60,5 @@ to learn about the defaults for your platform and target.
- ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.
* **"time" options**
- ``LIBC_CONF_TIME_64BIT``: Force the size of time_t to 64 bits, even on platforms where compatibility considerations would otherwise make it 32-bit.
+* **"unistd" options**
+ - ``LIBC_CONF_PAGE_SIZE``: The value to use for the system page size, acceptable values are LIBC_CONF_PAGE_SIZE_SYSTEM, LIBC_CONF_PAGE_SIZE_4K, LIBC_CONF_PAGE_SIZE_16K, LIBC_CONF_PAGE_SIZE_64K.
diff --git a/libc/hdrgen/yaml/unistd.yaml b/libc/hdrgen/yaml/unistd.yaml
index c6441c04ce3a3d..a044a4290aed85 100644
--- a/libc/hdrgen/yaml/unistd.yaml
+++ b/libc/hdrgen/yaml/unistd.yaml
@@ -141,6 +141,12 @@ functions:
- type: int
- type: __getoptargv_t
- type: const char *
+ - name: getpagesize
+ standards:
+ - POSIX
+ return_type: int
+ arguments:
+ - type: void
- name: getpid
standards:
- POSIX
diff --git a/libc/src/__support/macros/CMakeLists.txt b/libc/src/__support/macros/CMakeLists.txt
index 99d4f640f283a4..5ef209f4f9c8f6 100644
--- a/libc/src/__support/macros/CMakeLists.txt
+++ b/libc/src/__support/macros/CMakeLists.txt
@@ -20,6 +20,12 @@ add_header_library(
libc.src.__support.macros.properties.compiler
)
+add_header_library(
+ page_size
+ HDRS
+ page_size.h
+)
+
add_header_library(
sanitizer
HDRS
diff --git a/libc/src/__support/macros/page_size.h b/libc/src/__support/macros/page_size.h
new file mode 100644
index 00000000000000..bc45dcc672d345
--- /dev/null
+++ b/libc/src/__support/macros/page_size.h
@@ -0,0 +1,17 @@
+//===-- Convenient page size macros -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PAGE_SIZE_H
+#define LLVM_LIBC_SRC___SUPPORT_MACROS_PAGE_SIZE_H
+
+#define LIBC_PAGE_SIZE_SYSTEM 0
+#define LIBC_PAGE_SIZE_4K (4 * 1024)
+#define LIBC_PAGE_SIZE_16K (16 * 1024)
+#define LIBC_PAGE_SIZE_64K (64 * 1024)
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PAGE_SIZE_H
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 1a0b2e3293d03c..668da5c939ed6b 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -1,7 +1,33 @@
+function(add_unistd_entrypoint_object name)
+ if(TARGET libc.src.unistd.${LIBC_TARGET_OS}.${name})
+ add_entrypoint_object(
+ ${name}
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.${name}
+ )
+ elseif(TARGET libc.src.unistd.generic.${name})
+ add_entrypoint_object(
+ ${name}
+ ALIAS
+ DEPENDS
+ .generic.${name}
+ )
+ endif()
+endfunction(add_unistd_entrypoint_object)
+
+if(LIBC_CONF_PAGE_SIZE)
+ set(getpagesize_config_copts "-DLIBC_PAGE_SIZE=${LIBC_CONF_PAGE_SIZE}")
+endif()
+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
+if(NOT LIBC_TARGET_OS_IS_BAREMETAL AND NOT LIBC_TARGET_OS_IS_GPU)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/generic)
+endif()
+
add_entrypoint_object(
_exit
SRCS
@@ -350,3 +376,6 @@ add_entrypoint_object(
DEPENDS
libc.src.__support.threads.identifier
)
+
+# These entrypoints have multiple potential implementations.
+add_unistd_entrypoint_object(getpagesize)
diff --git a/libc/src/unistd/generic/CMakeLists.txt b/libc/src/unistd/generic/CMakeLists.txt
new file mode 100644
index 00000000000000..36111c975d172b
--- /dev/null
+++ b/libc/src/unistd/generic/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+ getpagesize
+ SRCS
+ getpagesize.cpp
+ HDRS
+ ../getpagesize.h
+ COMPILE_OPTIONS
+ ${getpagesize_config_copts}
+ DEPENDS
+ libc.include.unistd
+ libc.src.__support.macros.page_size
+)
diff --git a/libc/src/unistd/generic/getpagesize.cpp b/libc/src/unistd/generic/getpagesize.cpp
new file mode 100644
index 00000000000000..efd921f36a1e7e
--- /dev/null
+++ b/libc/src/unistd/generic/getpagesize.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of getpagesize -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getpagesize.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/page_size.h"
+
+#if LIBC_PAGE_SIZE == LIBC_PAGE_SIZE_SYSTEM
+#error "System implementation for getpagesize is missing"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, getpagesize, ()) { return LIBC_PAGE_SIZE; }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/unistd/getpagesize.h b/libc/src/unistd/getpagesize.h
new file mode 100644
index 00000000000000..f391f2b6c6240a
--- /dev/null
+++ b/libc/src/unistd/getpagesize.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for getpagesize -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_GETPAGESIZE_H
+#define LLVM_LIBC_SRC_UNISTD_GETPAGESIZE_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int getpagesize();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_UNISTD_GETPAGESIZE_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index ed360c73354ac4..4347f36fd5f935 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -207,6 +207,19 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
)
+add_entrypoint_object(
+ getpagesize
+ SRCS
+ getpagesize.cpp
+ HDRS
+ ../getpagesize.h
+ DEPENDS
+ .sysconf
+ libc.include.unistd
+ libc.src.__support.macros.page_size
+ libc.src.sys.auxv.getauxval
+)
+
add_entrypoint_object(
getpid
SRCS
diff --git a/libc/src/unistd/linux/getpagesize.cpp b/libc/src/unistd/linux/getpagesize.cpp
new file mode 100644
index 00000000000000..b714d671ac1ad8
--- /dev/null
+++ b/libc/src/unistd/linux/getpagesize.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of getpagesize -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getpagesize.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/page_size.h"
+#include "src/sys/auxv/getauxval.h"
+#include "src/unistd/sysconf.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, getpagesize, ()) {
+#if LIBC_PAGE_SIZE == LIBC_PAGE_SIZE_SYSTEM
+ int r = (int)getauxval(AT_PAGESZ);
+ if (r == 0)
+ return (int)sysconf(_SC_PAGESIZE);
+ return r;
+#else
+ return LIBC_PAGE_SIZE;
+#endif
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index e036e09cde702e..dd0d5f0d0b8283 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -417,6 +417,16 @@ add_libc_unittest(
libc.src.unistd.geteuid
)
+add_libc_unittest(
+ getpagesize
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ getpagesize_test.cpp
+ DEPENDS
+ libc.src.unistd.getpagesize
+)
+
add_libc_unittest(
syscall_test
SUITE
diff --git a/libc/test/src/unistd/getpagesize_test.cpp b/libc/test/src/unistd/getpagesize_test.cpp
new file mode 100644
index 00000000000000..65a92320a62ae6
--- /dev/null
+++ b/libc/test/src/unistd/getpagesize_test.cpp
@@ -0,0 +1,16 @@
+//===-- Unittests for getpagesize -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getpagesize.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcGetPageSizeTest, SmokeTest) {
+ int r = LIBC_NAMESPACE::getpagesize();
+ ASSERT_GT(r, 0);
+ ASSERT_EQ(r % 1024, 0);
+}
>From bce6b17907db8f952851a53aa8f23985871584be Mon Sep 17 00:00:00 2001
From: Tristan Ross <tristan.ross at midstall.com>
Date: Thu, 26 Dec 2024 17:46:39 -0800
Subject: [PATCH 2/2] [libc] add basic arena allocator
---
libc/CMakeLists.txt | 6 ++
libc/config/config.json | 4 ++
libc/docs/configure.rst | 1 +
libc/src/__support/CMakeLists.txt | 2 +
libc/src/__support/alloc/CMakeLists.txt | 57 +++++++++++++++
libc/src/__support/alloc/alloc.cpp | 13 ++++
libc/src/__support/alloc/alloc.h | 22 ++++++
libc/src/__support/alloc/arena.cpp | 71 +++++++++++++++++++
libc/src/__support/alloc/arena.h | 47 ++++++++++++
.../__support/alloc/baremetal/CMakeLists.txt | 13 ++++
libc/src/__support/alloc/baremetal/page.cpp | 22 ++++++
libc/src/__support/alloc/base.cpp | 16 +++++
libc/src/__support/alloc/base.h | 44 ++++++++++++
libc/src/__support/alloc/linux/CMakeLists.txt | 16 +++++
libc/src/__support/alloc/linux/page.cpp | 41 +++++++++++
libc/src/__support/alloc/page.h | 23 ++++++
libc/src/__support/memory_size.h | 14 ++++
libc/src/stdlib/CMakeLists.txt | 51 +++++++++++++
libc/src/stdlib/aligned_alloc.cpp | 12 ++++
libc/src/stdlib/calloc.cpp | 12 ++++
libc/src/stdlib/free.cpp | 13 ++++
libc/src/stdlib/malloc.cpp | 13 ++++
libc/src/stdlib/realloc.cpp | 12 ++++
23 files changed, 525 insertions(+)
create mode 100644 libc/src/__support/alloc/CMakeLists.txt
create mode 100644 libc/src/__support/alloc/alloc.cpp
create mode 100644 libc/src/__support/alloc/alloc.h
create mode 100644 libc/src/__support/alloc/arena.cpp
create mode 100644 libc/src/__support/alloc/arena.h
create mode 100644 libc/src/__support/alloc/baremetal/CMakeLists.txt
create mode 100644 libc/src/__support/alloc/baremetal/page.cpp
create mode 100644 libc/src/__support/alloc/base.cpp
create mode 100644 libc/src/__support/alloc/base.h
create mode 100644 libc/src/__support/alloc/linux/CMakeLists.txt
create mode 100644 libc/src/__support/alloc/linux/page.cpp
create mode 100644 libc/src/__support/alloc/page.h
create mode 100644 libc/src/stdlib/aligned_alloc.cpp
create mode 100644 libc/src/stdlib/calloc.cpp
create mode 100644 libc/src/stdlib/free.cpp
create mode 100644 libc/src/stdlib/malloc.cpp
create mode 100644 libc/src/stdlib/realloc.cpp
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 00a07ea3c8ac75..eebab925ba489d 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -386,6 +386,12 @@ else()
set(libc_opt_high_flag "-O3")
endif()
+if(${LIBC_CONF_ALLOC_TYPE} MATCHES "LIBC_ALLOC_TYPE_SCUDO")
+ set(LLVM_LIBC_INCLUDE_SCUDO ON)
+elseif(LLVM_LIBC_INCLUDE_SCUDO)
+ message(FATAL_ERROR "Cannot include scudo and use a different allocator.")
+endif()
+
add_subdirectory(include)
add_subdirectory(config)
add_subdirectory(hdr)
diff --git a/libc/config/config.json b/libc/config/config.json
index 23c057570d6fd7..6017d2e004de3e 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -115,6 +115,10 @@
"LIBC_ADD_NULL_CHECKS": {
"value": true,
"doc": "Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior."
+ },
+ "LIBC_CONF_ALLOC_TYPE": {
+ "value": "LIBC_ALLOC_TYPE_ARENA",
+ "doc": "The implementation used for allocations, acceptable values are LIBC_ALLOC_TYPE_EXTERN, LIBC_ALLOC_TYPE_SCUDO, LIBC_ALLOC_TYPE_ARENA."
}
},
"unistd": {
diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst
index 89bfd93b8a99c2..036e8fc7a93832 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -32,6 +32,7 @@ to learn about the defaults for your platform and target.
- ``LIBC_CONF_ERRNO_MODE``: The implementation used for errno, acceptable values are LIBC_ERRNO_MODE_DEFAULT, LIBC_ERRNO_MODE_UNDEFINED, LIBC_ERRNO_MODE_THREAD_LOCAL, LIBC_ERRNO_MODE_SHARED, LIBC_ERRNO_MODE_EXTERNAL, and LIBC_ERRNO_MODE_SYSTEM.
* **"general" options**
- ``LIBC_ADD_NULL_CHECKS``: Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior.
+ - ``LIBC_CONF_ALLOC_TYPE``: The implementation used for allocations, acceptable values are LIBC_ALLOC_TYPE_EXTERN, LIBC_ALLOC_TYPE_SCUDO, LIBC_ALLOC_TYPE_ARENA.
* **"math" options**
- ``LIBC_CONF_FREXP_INF_NAN_EXPONENT``: The value written back to the second parameter when calling frexp/frexpf/frexpl` with `+/-Inf`/`NaN` is unspecified. Configue an explicit exp value for Inf/NaN inputs.
- ``LIBC_CONF_MATH_OPTIMIZATIONS``: Configures optimizations for math functions. Values accepted are LIBC_MATH_SKIP_ACCURATE_PASS, LIBC_MATH_SMALL_TABLES, LIBC_MATH_NO_ERRNO, LIBC_MATH_NO_EXCEPT, and LIBC_MATH_FAST.
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 4e90aad9a45b40..45f4dde264122a 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -370,3 +370,5 @@ add_subdirectory(HashTable)
add_subdirectory(fixed_point)
add_subdirectory(time)
+
+add_subdirectory(alloc)
diff --git a/libc/src/__support/alloc/CMakeLists.txt b/libc/src/__support/alloc/CMakeLists.txt
new file mode 100644
index 00000000000000..f7142bb0d7c0b8
--- /dev/null
+++ b/libc/src/__support/alloc/CMakeLists.txt
@@ -0,0 +1,57 @@
+add_object_library(
+ base
+ SRCS
+ base.cpp
+ HDRS
+ base.h
+ DEPENDS
+ libc.hdr.types.size_t
+ libc.src.__support.macros.config
+)
+
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+endif()
+
+if(TARGET libc.src.__support.alloc.${LIBC_TARGET_OS}.page)
+ add_object_library(
+ page
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.page
+ )
+endif()
+
+add_object_library(
+ arena
+ SRCS
+ arena.cpp
+ HDRS
+ arena.h
+ COMPILE_OPTIONS
+ -DLIBC_PAGE_SIZE=${LIBC_CONF_PAGE_SIZE}
+ DEPENDS
+ .base
+ .page
+ libc.include.llvm-libc-macros.stdint_macros
+ libc.src.string.memmove
+ libc.src.unistd.getpagesize
+)
+
+if(NOT ${LIBC_CONF_ALLOC_TYPE} MATCHES "LIBC_ALLOC_TYPE_SCUDO" AND NOT ${LIBC_CONF_ALLOC_TYPE} MATCHES "LIBC_ALLOC_TYPE_EXTERN")
+ string(TOLOWER ${LIBC_CONF_ALLOC_TYPE} LIBC_CONF_ALLOC_TYPE_NAME)
+ string(REPLACE "libc_alloc_type_" "" LIBC_CONF_ALLOC_TYPE_NAME "${LIBC_CONF_ALLOC_TYPE_NAME}")
+ if(TARGET libc.src.__support.alloc.${LIBC_CONF_ALLOC_TYPE_NAME})
+ add_object_library(
+ alloc
+ SRCS
+ alloc.cpp
+ HDRS
+ alloc.h
+ COMPILE_OPTIONS
+ -DLIBC_CONF_ALLOC_TYPE=${LIBC_CONF_ALLOC_TYPE_NAME}
+ DEPENDS
+ .${LIBC_CONF_ALLOC_TYPE_NAME}
+ )
+ endif()
+endif()
diff --git a/libc/src/__support/alloc/alloc.cpp b/libc/src/__support/alloc/alloc.cpp
new file mode 100644
index 00000000000000..f5f1832bb58a8f
--- /dev/null
+++ b/libc/src/__support/alloc/alloc.cpp
@@ -0,0 +1,13 @@
+#include <src/__support/alloc/alloc.h>
+#include <src/__support/alloc/arena.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+#define CONCAT(a, b) a##b
+#define EXPAND_AND_CONCAT(a, b) CONCAT(a, b)
+
+#define ALLOCATOR EXPAND_AND_CONCAT(LIBC_CONF_ALLOC_TYPE, _allocator)
+
+BaseAllocator *allocator = reinterpret_cast<BaseAllocator *>(&ALLOCATOR);
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/alloc/alloc.h b/libc/src/__support/alloc/alloc.h
new file mode 100644
index 00000000000000..88b5fbfb84680f
--- /dev/null
+++ b/libc/src/__support/alloc/alloc.h
@@ -0,0 +1,22 @@
+//===-- libc-wide allocator -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_ALLOC_ALLOC_H
+#define LLVM_LIBC_SRC___SUPPORT_ALLOC_ALLOC_H
+
+#include "src/__support/alloc/base.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// The primary allocator to use
+extern BaseAllocator *allocator;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif
diff --git a/libc/src/__support/alloc/arena.cpp b/libc/src/__support/alloc/arena.cpp
new file mode 100644
index 00000000000000..f39d80630f2477
--- /dev/null
+++ b/libc/src/__support/alloc/arena.cpp
@@ -0,0 +1,71 @@
+#include "src/__support/alloc/arena.h"
+#include "src/__support/alloc/page.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/page_size.h"
+#include "src/__support/memory_size.h"
+#include "src/string/memmove.h"
+#include "src/unistd/getpagesize.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void *arena_allocate(BaseAllocator *base, size_t alignment, size_t size) {
+ ArenaAllocator *self = reinterpret_cast<ArenaAllocator *>(base);
+
+ if (self->buffer == nullptr) {
+ self->buffer = reinterpret_cast<uint8_t *>(page_allocate(1));
+ self->buffer_size = self->get_page_size();
+ }
+
+ uintptr_t curr_ptr = (uintptr_t)self->buffer + (uintptr_t)self->curr_offset;
+ uintptr_t offset = internal::align_forward<uintptr_t>(curr_ptr, alignment);
+ offset -= (uintptr_t)self->buffer;
+
+ if (offset + size > self->buffer_size) {
+ self->buffer = reinterpret_cast<uint8_t *>(
+ page_expand(self->buffer, self->buffer_size / self->get_page_size()));
+ self->buffer_size += self->get_page_size();
+ }
+
+ if (offset + size <= self->buffer_size) {
+ void *ptr = &self->buffer[offset];
+ self->prev_offset = offset;
+ self->curr_offset = offset + size;
+ return ptr;
+ }
+ return nullptr;
+}
+
+void *arena_expand(BaseAllocator *base, void *ptr, size_t alignment,
+ size_t size) {
+ ArenaAllocator *self = reinterpret_cast<ArenaAllocator *>(base);
+
+ if (self->buffer + self->prev_offset == ptr) {
+ self->curr_offset = self->prev_offset + size;
+ return ptr;
+ } else {
+ void *new_mem = arena_allocate(base, alignment, size);
+ memmove(new_mem, ptr, size);
+ return new_mem;
+ }
+ return nullptr;
+}
+
+bool arena_free(BaseAllocator *base, void *ptr) {
+ (void)base;
+ (void)ptr;
+ return true;
+}
+
+size_t ArenaAllocator::get_page_size() {
+ if (page_size == LIBC_PAGE_SIZE_SYSTEM) {
+ page_size = getpagesize();
+ }
+ return page_size;
+}
+
+static ArenaAllocator default_arena_allocator(LIBC_PAGE_SIZE,
+ 2 * sizeof(void *));
+BaseAllocator *block_allocator = &default_arena_allocator;
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/alloc/arena.h b/libc/src/__support/alloc/arena.h
new file mode 100644
index 00000000000000..45b6915139e712
--- /dev/null
+++ b/libc/src/__support/alloc/arena.h
@@ -0,0 +1,47 @@
+//===-- An arena allocator using pages. -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_ALLOC_ARENA_H
+#define LLVM_LIBC_SRC___SUPPORT_ALLOC_ARENA_H
+
+#include "hdr/types/size_t.h"
+#include "include/llvm-libc-macros/stdint-macros.h"
+#include "src/__support/alloc/base.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void *arena_allocate(BaseAllocator *base, size_t alignment, size_t size);
+void *arena_expand(BaseAllocator *base, void *ptr, size_t alignment,
+ size_t size);
+bool arena_free(BaseAllocator *base, void *ptr);
+
+class ArenaAllocator : public BaseAllocator {
+public:
+ uint8_t *buffer;
+ size_t buffer_size;
+ size_t prev_offset;
+ size_t curr_offset;
+
+private:
+ size_t page_size;
+
+public:
+ constexpr ArenaAllocator(size_t page_size, size_t default_alignment)
+ : BaseAllocator(arena_allocate, arena_expand, arena_free,
+ default_alignment),
+ buffer(nullptr), buffer_size(0), prev_offset(0), curr_offset(0),
+ page_size(page_size) {}
+
+ size_t get_page_size();
+};
+
+extern BaseAllocator *arena_allocator;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif
diff --git a/libc/src/__support/alloc/baremetal/CMakeLists.txt b/libc/src/__support/alloc/baremetal/CMakeLists.txt
new file mode 100644
index 00000000000000..845d2f5287bfbf
--- /dev/null
+++ b/libc/src/__support/alloc/baremetal/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_object_library(
+ page
+ SRCS
+ page.cpp
+ HDRS
+ ../page.h
+ DEPENDS
+ libc.src.__support.alloc.base
+ libc.src.sys.mman.mmap
+ libc.src.sys.mman.mremap
+ libc.src.sys.mman.munmap
+ libc.src.unistd.getpagesize
+)
diff --git a/libc/src/__support/alloc/baremetal/page.cpp b/libc/src/__support/alloc/baremetal/page.cpp
new file mode 100644
index 00000000000000..4d92141bcc8276
--- /dev/null
+++ b/libc/src/__support/alloc/baremetal/page.cpp
@@ -0,0 +1,22 @@
+#include "src/__support/alloc/page.h"
+#include "src/__suport/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+extern "C" void *__llvm_libc_page_allocate(size_t n_pages);
+extern "C" void *__llvm_libc_page_expand(void *ptr, size_t n_pages);
+extern "C" bool __llvm_libc_page_free(void *ptr, size_t n_pages);
+
+void *page_allocate(size_t n_pages) {
+ return __llvm_libc_page_allocate(n_pages);
+}
+
+void *page_expand(void *ptr, size_t n_pages) {
+ return __llvm_libc_page_expand(ptr, n_pages);
+}
+
+bool page_free(void *ptr, size_t n_pages) {
+ return __llvm_libc_page_free(ptr, n_pages);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/alloc/base.cpp b/libc/src/__support/alloc/base.cpp
new file mode 100644
index 00000000000000..93684d457ee42d
--- /dev/null
+++ b/libc/src/__support/alloc/base.cpp
@@ -0,0 +1,16 @@
+#include "src/__support/alloc/base.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void *BaseAllocator::alloc(size_t alignment, size_t size) {
+ return impl_alloc(this, alignment, size);
+}
+
+void *BaseAllocator::expand(void *ptr, size_t alignment, size_t size) {
+ return impl_expand(this, ptr, alignment, size);
+}
+
+bool BaseAllocator::free(void *ptr) { return impl_free(this, ptr); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/alloc/base.h b/libc/src/__support/alloc/base.h
new file mode 100644
index 00000000000000..59370352953d3e
--- /dev/null
+++ b/libc/src/__support/alloc/base.h
@@ -0,0 +1,44 @@
+//===-- A generic base allocator. -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_ALLOC_BASE_H
+#define LLVM_LIBC_SRC___SUPPORT_ALLOC_BASE_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+class BaseAllocator {
+public:
+ using AllocFunc = void *(BaseAllocator *self, size_t, size_t);
+ using ExpandFunc = void *(BaseAllocator *self, void *, size_t, size_t);
+ using FreeFunc = bool(BaseAllocator *self, void *);
+
+private:
+ // Implementation specific functions
+ AllocFunc *impl_alloc;
+ ExpandFunc *impl_expand;
+ FreeFunc *impl_free;
+
+public:
+ constexpr BaseAllocator(AllocFunc *ia, ExpandFunc *ie, FreeFunc *ifr,
+ size_t default_alignment)
+ : impl_alloc(ia), impl_expand(ie), impl_free(ifr),
+ default_alignment(default_alignment) {}
+
+ size_t default_alignment;
+
+ void *alloc(size_t alignment, size_t size);
+ void *expand(void *ptr, size_t alignment, size_t size);
+ bool free(void *ptr);
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_ALLOC_BASE_H
diff --git a/libc/src/__support/alloc/linux/CMakeLists.txt b/libc/src/__support/alloc/linux/CMakeLists.txt
new file mode 100644
index 00000000000000..4484a5d60c9635
--- /dev/null
+++ b/libc/src/__support/alloc/linux/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_object_library(
+ page
+ SRCS
+ page.cpp
+ HDRS
+ ../page.h
+ DEPENDS
+ libc.hdr.types.size_t
+ libc.include.llvm-libc-macros.stdlib_macros
+ libc.include.llvm-libc-macros.stdint_macros
+ libc.src.__support.alloc.base
+ libc.src.sys.mman.mmap
+ libc.src.sys.mman.mremap
+ libc.src.sys.mman.munmap
+ libc.src.unistd.getpagesize
+)
diff --git a/libc/src/__support/alloc/linux/page.cpp b/libc/src/__support/alloc/linux/page.cpp
new file mode 100644
index 00000000000000..1d9f04e951856e
--- /dev/null
+++ b/libc/src/__support/alloc/linux/page.cpp
@@ -0,0 +1,41 @@
+#include "src/__support/alloc/page.h"
+#include "include/llvm-libc-macros/stdint-macros.h"
+#include "include/llvm-libc-macros/stdlib-macros.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/memory_size.h"
+#include "src/sys/mman/mmap.h"
+#include "src/sys/mman/mremap.h"
+#include "src/sys/mman/munmap.h"
+#include "src/unistd/getpagesize.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static void *alloc_hint = NULL;
+
+void *page_allocate(size_t n_pages) {
+ size_t page_size = getpagesize();
+ size_t size = n_pages * page_size;
+ size_t aligned_size = internal::SafeMemSize(size).align_up(page_size);
+
+ void *ptr = mmap(&alloc_hint, aligned_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ptr == NULL)
+ return nullptr;
+
+ alloc_hint = (void *)(((uintptr_t)ptr) + aligned_size);
+ return ptr;
+}
+
+void *page_expand(void *ptr, size_t n_pages) {
+ (void)ptr;
+ (void)n_pages;
+ return nullptr;
+}
+
+bool page_free(void *ptr, size_t n_pages) {
+ (void)ptr;
+ (void)n_pages;
+ return false;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/alloc/page.h b/libc/src/__support/alloc/page.h
new file mode 100644
index 00000000000000..bb627b50cd6eb4
--- /dev/null
+++ b/libc/src/__support/alloc/page.h
@@ -0,0 +1,23 @@
+//===-- Page allocations ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_ALLOC_PAGE_H
+#define LLVM_LIBC_SRC___SUPPORT_ALLOC_PAGE_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void *page_allocate(size_t n_pages);
+void *page_expand(void *ptr, size_t n_pages);
+bool page_free(void *ptr, size_t n_pages);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_ALLOC_BASE_H
diff --git a/libc/src/__support/memory_size.h b/libc/src/__support/memory_size.h
index cdd6a10222de10..a9df814be7156b 100644
--- a/libc/src/__support/memory_size.h
+++ b/libc/src/__support/memory_size.h
@@ -12,6 +12,7 @@
#include "src/__support/CPP/bit.h" // has_single_bit
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/type_traits.h"
+#include "src/__support/libc_assert.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
@@ -32,6 +33,19 @@ template <class T> LIBC_INLINE bool mul_overflow(T a, T b, T *res) {
return overflow;
#endif
}
+
+template <class T> LIBC_INLINE T align_forward(T ptr, size_t align) {
+ LIBC_ASSERT((align & (align - 1)) == 0);
+
+ T p = ptr;
+ T a = (T)align;
+
+ T modulo = p & (a - 1);
+ if (modulo != 0)
+ p += a - modulo;
+ return p;
+}
+
// Limit memory size to the max of ssize_t
class SafeMemSize {
private:
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 40ba9ead9a7ae6..18c7b48190f2c2 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -388,6 +388,57 @@ if(NOT LIBC_TARGET_OS_IS_BAREMETAL AND NOT LIBC_TARGET_OS_IS_GPU)
DEPENDS
${SCUDO_DEPS}
)
+ elseif(NOT ${LIBC_CONF_ALLOC_TYPE} MATCHES "LIBC_CONF_ALLOC_TYPE_EXTERN")
+ add_entrypoint_object(
+ aligned_alloc
+ SRCS
+ aligned_alloc.cpp
+ HDRS
+ aligned_alloc.h
+ DEPENDS
+ libc.src.__support.alloc.alloc
+ )
+
+ add_entrypoint_object(
+ malloc
+ SRCS
+ malloc.cpp
+ HDRS
+ malloc.h
+ DEPENDS
+ .aligned_alloc
+ )
+
+ add_entrypoint_object(
+ calloc
+ SRCS
+ calloc.cpp
+ HDRS
+ calloc.h
+ DEPENDS
+ .malloc
+ )
+
+ add_entrypoint_object(
+ realloc
+ SRCS
+ realloc.cpp
+ HDRS
+ realloc.h
+ DEPENDS
+ libc.src.__support.alloc.alloc
+ )
+
+ add_entrypoint_object(
+ free
+ SRCS
+ free.cpp
+ HDRS
+ free.h
+ DEPENDS
+ libc.src.__support.libc_assert
+ libc.src.__support.alloc.alloc
+ )
else()
add_entrypoint_external(
malloc
diff --git a/libc/src/stdlib/aligned_alloc.cpp b/libc/src/stdlib/aligned_alloc.cpp
new file mode 100644
index 00000000000000..d7883363486f8b
--- /dev/null
+++ b/libc/src/stdlib/aligned_alloc.cpp
@@ -0,0 +1,12 @@
+#include "src/stdlib/aligned_alloc.h"
+#include "src/__support/alloc/alloc.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void *, aligned_alloc, (size_t alignment, size_t size)) {
+ return allocator->alloc(alignment, size);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/calloc.cpp b/libc/src/stdlib/calloc.cpp
new file mode 100644
index 00000000000000..d2bebd2eb7d7a1
--- /dev/null
+++ b/libc/src/stdlib/calloc.cpp
@@ -0,0 +1,12 @@
+#include "src/stdlib/calloc.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/stdlib/malloc.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void *, calloc, (size_t nmeb, size_t size)) {
+ return malloc(nmeb * size);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/free.cpp b/libc/src/stdlib/free.cpp
new file mode 100644
index 00000000000000..71a77e615cf2d1
--- /dev/null
+++ b/libc/src/stdlib/free.cpp
@@ -0,0 +1,13 @@
+#include "src/stdlib/free.h"
+#include "src/__support/alloc/alloc.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_assert.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, free, (void *ptr)) {
+ LIBC_ASSERT(allocator->free(ptr));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/malloc.cpp b/libc/src/stdlib/malloc.cpp
new file mode 100644
index 00000000000000..a8a51d10ebb732
--- /dev/null
+++ b/libc/src/stdlib/malloc.cpp
@@ -0,0 +1,13 @@
+#include "src/stdlib/malloc.h"
+#include "src/__support/alloc/alloc.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/stdlib/aligned_alloc.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void *, malloc, (size_t size)) {
+ return aligned_alloc(allocator->default_alignment, size);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/realloc.cpp b/libc/src/stdlib/realloc.cpp
new file mode 100644
index 00000000000000..60043bf8ad287a
--- /dev/null
+++ b/libc/src/stdlib/realloc.cpp
@@ -0,0 +1,12 @@
+#include "src/stdlib/realloc.h"
+#include "src/__support/alloc/alloc.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void *, realloc, (void *ptr, size_t size)) {
+ return allocator->expand(ptr, allocator->default_alignment, size);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
More information about the libc-commits
mailing list