[libcxx-commits] [libcxx] [libc++] Speed up classic locale (PR #72112)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Nov 23 11:30:30 PST 2023


================
@@ -537,55 +542,59 @@ locale::__imp::use_facet(long id) const
 
 // locale
 
-// This class basically implements __attribute__((no_destroy)), which isn't supported
-// by GCC as of writing this.
-template <class T>
-struct __no_destroy {
-    template <class... Args>
-    explicit __no_destroy(Args&&... args) {
-        T* obj = reinterpret_cast<T*>(&buf);
-        new (obj) T(std::forward<Args>(args)...);
-    }
-
-    T& get() { return *reinterpret_cast<T*>(&buf); }
-    T const& get() const { return *reinterpret_cast<T const*>(&buf); }
-
-  private:
-    alignas(T) byte buf[sizeof(T)];
-};
+// We don't do reference counting on the classic locale.
+// It's never destroyed anyway, but atomic reference counting may be very
+// expensive in parallel applications. The classic locale is used by default
+// in all streams. Note: if a new global locale is installed, then we lose
+// the benefit of no reference counting.
+__no_destroy<locale::__imp> locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
 
 const locale& locale::classic() {
-    static const __no_destroy<locale> c(__private_tag{}, &make<__imp>(1u));
-    return c.get();
+  static const __no_destroy<locale> classic_locale(__private_tag{}, [] {
+    // executed exactly once on first initialization of `classic_locale`
+    locale::__imp::classic_locale_imp_.__emplace(1u);
+    return &locale::__imp::classic_locale_imp_.__get();
+  }());
+  return classic_locale.__get();
 }
 
 locale& locale::__global() {
-    static __no_destroy<locale> g(locale::classic());
-    return g.get();
+  static __no_destroy<locale> g(locale::classic());
+  return g.__get();
+}
+
+void locale::__imp::acquire() {
+  if (this != &locale::__imp::classic_locale_imp_.__get())
----------------
ldionne wrote:

Ok, I think this is definitely legal regardless, this is just a reinterpret cast like http://eel.is/c++draft/expr.reinterpret.cast#7 and we're not accessing the object as a `locale::__imp` before it is initialized. But even better, I can switch to a `union` in `__no_destroy` instead of an aligned `char` buffer and it makes the code cleaner and clearly correct.

https://github.com/llvm/llvm-project/pull/72112


More information about the libcxx-commits mailing list