diff --git a/folly/futures/detail/Core.cpp b/folly/futures/detail/Core.cpp index c3897fde9d1..b1b5dff4c01 100644 --- a/folly/futures/detail/Core.cpp +++ b/folly/futures/detail/Core.cpp @@ -670,6 +670,31 @@ void CoreBase::derefCallback() noexcept { } } +bool CoreBase::destroyDerived() noexcept { + DCHECK(attached_ == 0); + auto state = state_.load(std::memory_order_relaxed); + switch (state) { + case State::OnlyResult: + [[fallthrough]]; + + case State::Done: + return true; + + case State::Proxy: + proxy_->detachFuture(); + [[fallthrough]]; + + case State::Empty: + return false; + + case State::Start: + case State::OnlyCallback: + case State::OnlyCallbackAllowInline: + default: + terminate_with("~Core unexpected state"); + } +} + #if FOLLY_USE_EXTERN_FUTURE_UNIT template class Core; #endif diff --git a/folly/futures/detail/Core.h b/folly/futures/detail/Core.h index 78ee7c745ce..11127be5db9 100644 --- a/folly/futures/detail/Core.h +++ b/folly/futures/detail/Core.h @@ -524,6 +524,24 @@ class CoreBase { void derefCallback() noexcept; + template + FOLLY_ERASE static Self& walkProxyChainImpl(Self& self) noexcept { + DCHECK(self.hasResult()); + auto core = &self; + while (core->state_.load(std::memory_order_relaxed) == State::Proxy) { + core = core->proxy_; + } + return *core; + } + FOLLY_ERASE CoreBase& walkProxyChain() noexcept { + return walkProxyChainImpl(*this); + } + FOLLY_ERASE CoreBase const& walkProxyChain() const noexcept { + return walkProxyChainImpl(*this); + } + + bool destroyDerived() noexcept; + Callback callback_; std::atomic state_; std::atomic attached_; @@ -590,20 +608,10 @@ class Core final : private ResultHolder, public CoreBase { /// possibly moved-out, depending on what the callback did; some but not /// all callbacks modify (possibly move-out) the result.) Try& getTry() { - DCHECK(hasResult()); - auto core = this; - while (core->state_.load(std::memory_order_relaxed) == State::Proxy) { - core = static_cast(core->proxy_); - } - return core->result_; + return static_cast(walkProxyChain()).result_; } Try const& getTry() const { - DCHECK(hasResult()); - auto core = this; - while (core->state_.load(std::memory_order_relaxed) == State::Proxy) { - core = static_cast(core->proxy_); - } - return core->result_; + return static_cast(walkProxyChain()).result_; } /// Call only from consumer thread. @@ -682,28 +690,8 @@ class Core final : private ResultHolder, public CoreBase { } ~Core() override { - DCHECK(attached_ == 0); - auto state = state_.load(std::memory_order_relaxed); - switch (state) { - case State::OnlyResult: - [[fallthrough]]; - - case State::Done: - this->result_.~Result(); - break; - - case State::Proxy: - proxy_->detachFuture(); - break; - - case State::Empty: - break; - - case State::Start: - case State::OnlyCallback: - case State::OnlyCallbackAllowInline: - default: - terminate_with("~Core unexpected state"); + if (destroyDerived()) { + this->result_.~Result(); } }