[libcxx-commits] [PATCH] D133661: [libc++] Improve binary size when using __transaction

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 15 08:55:58 PST 2022


ldionne added inline comments.


================
Comment at: libcxx/include/__utility/exception_guard.h:78
         __completed_ = true;
     }
 
----------------
ldionne wrote:
> philnik wrote:
> > Mordante wrote:
> > > When this class is intended to be an exception guard it doesn't need this function nor the `__completed_` member. Instead we can do something along the lines of:
> > > ```
> > > #ifndef _LIBCPP_NO_EXCEPTIONS
> > > #if _LIBCPP_STD_VER > 14
> > >   _LIBCPP_HIDE_FROM_ABI bool __need_rollback() { return uncaught_exceptions(); } 
> > > #else
> > >   _LIBCPP_HIDE_FROM_ABI bool __need_rollback() { return uncaught_exception(); } 
> > > #endif
> > > 
> > > 
> > >  _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__exception_guard() {
> > >     if(__need_rollback())
> > >       __rollback_();
> > >   }
> > > #endif 
> > > ```
> > > With some extra boilerplate to add `_LIBCPP_CONSTEXPR_SINCE_CXX20`.
> > > 
> > > Then we can even use most of this class when `_LIBCPP_NO_EXCEPTIONS` is defined. Then it just does an extra store of the never used `__rollback_` member.
> > This would break when running in a destructor though, right? Then `uncaught_exception()` might return true even if we don't actually want to roll back a transaction. That's the whole reason `uncaught_exceptions()` was added.
> IMO we should strive to keep the scope that the `__exception_guard` is guarding explicit. If you use `uncaught_exceptions` (or other) to detect whether an exception was thrown, then you'd have to use the class as
> 
> ```
> { // begin new scope
>   __exception_guard guard = ...;
>   // actions...
> } // end scope explicitly here
> ```
> 
> This may not always be convenient. Instead, being able to explicitly say "okay, here the thing I was guarding for exceptions is done" makes the code clearer.
> 
I just had a discussion with Mark where he explained why he wasn't a big fan of the current behavior, where `exception_guard` will behave differently whether exceptions are enabled or not. I think we should change the no-exceptions version to

```
template <class _Rollback>
struct __exception_guard {
  __exception_guard() = delete;
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG __exception_guard(_Rollback) {}
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG __exception_guard(__exception_guard&&)
      _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value) {}
  __exception_guard(__exception_guard const&) = delete;
  __exception_guard& operator=(__exception_guard const&) = delete;
  __exception_guard& operator=(__exception_guard&&) = delete;

  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG void __complete() _NOEXCEPT { __completed_ = true; }
  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard() { _LIBCPP_ASSERT(__completed_); }

private:
  bool __completed_;
};
```

This way, we enforce the intended usage of the class -- when exceptions are disabled, `__complete()` should always get called. And concretely this will get optimized away.

The reason I'm not a fan of depending on `uncaught_exceptions()` is that the function is defined in `libc++abi.dylib`. I am concerned about adding a call to a function hidden behind an ABI boundary that the optimizer doesn't know anything about, when instead we could just be setting and checking a bool visible to the optimizer in this very scope.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133661/new/

https://reviews.llvm.org/D133661



More information about the libcxx-commits mailing list