Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🍒] Unconditionally lower std::string's alignment requirement from 16 to 8 (#68925) #79480

Merged
merged 1 commit into from
Feb 7, 2024

Conversation

EricWF
Copy link
Member

@EricWF EricWF commented Jan 25, 2024

This change saves memory by providing the allocator more freedom to allocate the most
efficient size class by dropping the alignment requirements for std::string's
pointer from 16 to 8. This changes the output of std::string::max_size, which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value of "max_size()" changes, which in turn changes whether std::bad_alloc or std::length_error is thrown for large allocations.

This change is the child of PR #68807, which enabled the change behind an ABI flag.

…8. (llvm#68925)

Unconditionally change std::string's alignment to 8.

This change saves memory by providing the allocator more freedom to
allocate the most
efficient size class by dropping the alignment requirements for
std::string's
pointer from 16 to 8. This changes the output of std::string::max_size,
which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI
break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value
of "max_size()" changes, which in turn changes whether `std::bad_alloc`
or `std::length_error` is thrown for large allocations.

This change is the child of PR llvm#68807, which enabled the change behind
an ABI flag.
@EricWF EricWF added this to the LLVM 18.0.X Release milestone Jan 25, 2024
@EricWF EricWF requested a review from a team as a code owner January 25, 2024 18:24
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jan 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 25, 2024

@llvm/pr-subscribers-libcxx

Author: Eric (EricWF)

Changes

…8. (#68925)

Unconditionally change std::string's alignment to 8.

This change saves memory by providing the allocator more freedom to allocate the most
efficient size class by dropping the alignment requirements for std::string's
pointer from 16 to 8. This changes the output of std::string::max_size, which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value of "max_size()" changes, which in turn changes whether std::bad_alloc or std::length_error is thrown for large allocations.

This change is the child of PR #68807, which enabled the change behind an ABI flag.


Full diff: https://github.com/llvm/llvm-project/pull/79480.diff

6 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/18.rst (+4-5)
  • (modified) libcxx/include/__config (-5)
  • (modified) libcxx/include/string (+1-6)
  • (modified) libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp (+4-8)
  • (modified) libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp (+2-8)
  • (modified) libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp (+6)
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index fb3d2af544c287e..80b42ad7f653aa2 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -275,11 +275,10 @@ ABI Affecting Changes
   results in an ABI break, however in practice we expect uses of ``std::projected`` in ABI-sensitive places to be
   extremely rare. Any error resulting from this change should result in a link-time error.
 
-- Under the unstable ABI, the internal alignment requirements for heap allocations
-  inside ``std::string`` has decreased from 16 to 8. This saves memory since string requests fewer additional
-  bytes than it did previously. However, this also changes the return value of ``std::string::max_size``
-  and can cause code compiled against older libc++ versions but linked at runtime to a new version
-  to throw a different exception when attempting allocations that are too large
+- The internal alignment requirements for heap allocations inside ``std::string`` has decreased from 16 to 8. This
+  saves memory since string requests fewer additional bytes than it did previously. However, this also changes the
+  return value of ``std::string::max_size`` and can cause code compiled against older libc++ versions but linked at
+  runtime to a new version to throw a different exception when attempting allocations that are too large
   (``std::bad_alloc`` vs ``std::length_error``).
 
 - The layout of some range adaptors that use the ``movable-box`` exposition-only type as an implementation
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 18875e1b61e6fbd..ad9a15f780703e7 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -174,11 +174,6 @@
 // The implementation moved to the header, but we still export the symbols from
 // the dylib for backwards compatibility.
 #    define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
-// Save memory by providing the allocator more freedom to allocate the most
-// efficient size class by dropping the alignment requirements for std::string's
-// pointer from 16 to 8. This changes the output of std::string::max_size,
-// which makes it ABI breaking
-#    define _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
 #  elif _LIBCPP_ABI_VERSION == 1
 #    if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
 // Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/string b/libcxx/include/string
index e97139206d4fa7c..ba169c3dbfc9e6c 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1937,12 +1937,7 @@ private:
     return (__s + (__a - 1)) & ~(__a - 1);
   }
   enum {
-    __alignment =
-#ifdef _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
-        8
-#else
-        16
-#endif
+    __alignment = 8
   };
   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __s) _NOEXCEPT {
     if (__s < __min_cap) {
diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
index c7df56c815a8054..1110e3d3ec568a2 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/allocation_size.pass.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx{{10.13|10.15|11.0}}
+
 // <string>
 
 // This test demonstrates the smaller allocation sizes when the alignment
@@ -17,14 +19,8 @@
 
 #include "test_macros.h"
 
-// alignment of the string heap buffer is hardcoded to either 16 or 8
-
-const std::size_t alignment =
-#ifdef _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
-    8;
-#else
-    16;
-#endif
+// alignment of the string heap buffer is hardcoded to 8
+const std::size_t alignment = 8;
 
 int main(int, char**) {
   std::string input_string;
diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
index a3cb79522f2e1eb..726570beb6d1ae6 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -17,14 +17,8 @@
 
 #include "test_macros.h"
 
-// alignment of the string heap buffer is hardcoded to 16
-
-static const std::size_t alignment =
-#ifdef _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
-    8;
-#else
-    16;
-#endif
+// alignment of the string heap buffer is hardcoded to 8
+static const std::size_t alignment = 8;
 
 template <class = int>
 TEST_CONSTEXPR_CXX20 void full_size() {
diff --git a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
index 52dbde45dbb265d..32ce1c8bf617dcb 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/max_size.pass.cpp
@@ -7,6 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: no-exceptions
+
+// After changing the alignment of the allocated pointer from 16 to 8, the exception thrown is no longer `bad_alloc`
+// but instead length_error on systems using new headers but older dylibs.
+//
+// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx{{10.13|10.15|11.0}}
+
 // <string>
 
 // size_type max_size() const; // constexpr since C++20

@EricWF
Copy link
Member Author

EricWF commented Jan 25, 2024

@tstellar Please let me know if this isn't the correct way to use PR's for release cherry-picks.

@ldionne ldionne changed the title Cherry-pick Unconditionally lower std::string's alignment requirement from 16 to … Cherry-pick Unconditionally lower std::string's alignment requirement from 16 to 8 (#68925) Jan 25, 2024
@ldionne
Copy link
Member

ldionne commented Jan 25, 2024

This is the official way to do it: https://llvm.org/docs/GitHub.html#backporting-fixes-to-the-release-branches

@tstellar I do wonder if it wouldn't be simpler to allow people to open PRs against the release branch instead?

@tstellar
Copy link
Collaborator

This is the official way to do it: https://llvm.org/docs/GitHub.html#backporting-fixes-to-the-release-branches

@tstellar I do wonder if it wouldn't be simpler to allow people to open PRs against the release branch instead?

This is the plan. See #79481.

@ldionne
Copy link
Member

ldionne commented Jan 25, 2024

Oh, that's great! Then it looks like this PR is fine as-is.

@ldionne ldionne changed the title Cherry-pick Unconditionally lower std::string's alignment requirement from 16 to 8 (#68925) [🍒] Unconditionally lower std::string's alignment requirement from 16 to 8 (#68925) Jan 25, 2024
@tstellar tstellar merged commit 5de1bcb into llvm:release/18.x Feb 7, 2024
46 of 48 checks passed
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
… to 8 (llvm#68925) (llvm#79480)

This change saves memory by providing the allocator more freedom to
allocate the most
efficient size class by dropping the alignment requirements for
std::string's
pointer from 16 to 8. This changes the output of std::string::max_size,
which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI
break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value
of "max_size()" changes, which in turn changes whether `std::bad_alloc`
or `std::length_error` is thrown for large allocations.

This change is the child of PR llvm#68807, which enabled the change behind
an ABI flag.
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
… to 8 (llvm#68925) (llvm#79480)

This change saves memory by providing the allocator more freedom to
allocate the most
efficient size class by dropping the alignment requirements for
std::string's
pointer from 16 to 8. This changes the output of std::string::max_size,
which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI
break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value
of "max_size()" changes, which in turn changes whether `std::bad_alloc`
or `std::length_error` is thrown for large allocations.

This change is the child of PR llvm#68807, which enabled the change behind
an ABI flag.
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
… to 8 (llvm#68925) (llvm#79480)

This change saves memory by providing the allocator more freedom to
allocate the most
efficient size class by dropping the alignment requirements for
std::string's
pointer from 16 to 8. This changes the output of std::string::max_size,
which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI
break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value
of "max_size()" changes, which in turn changes whether `std::bad_alloc`
or `std::length_error` is thrown for large allocations.

This change is the child of PR llvm#68807, which enabled the change behind
an ABI flag.
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
… to 8 (llvm#68925) (llvm#79480)

This change saves memory by providing the allocator more freedom to
allocate the most
efficient size class by dropping the alignment requirements for
std::string's
pointer from 16 to 8. This changes the output of std::string::max_size,
which makes it ABI breaking.

That said, the discussion concluded that we don't care about this ABI
break. and would like this change enabled universally.

The ABI break isn't one of layout or "class size", but rather the value
of "max_size()" changes, which in turn changes whether `std::bad_alloc`
or `std::length_error` is thrown for large allocations.

This change is the child of PR llvm#68807, which enabled the change behind
an ABI flag.
@pointhex pointhex mentioned this pull request May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
Development

Successfully merging this pull request may close these issues.

4 participants