mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 01:07:15 +03:00
a338113719
Summary: `folly::cold_detail::ColdClass` was marking things (like `folly::Unexpected`) cold, but at the cost of inhibiting the inliner from doing its job. This is leading to bad codegen, which offsets any small wins we mind get for the `cold` attribute. Reviewed By: yfeldblum Differential Revision: D19324159 fbshipit-source-id: 7ed431b6c9d6e963c3bf438c707fa6cf6a38bf9d
162 lines
4.4 KiB
C++
162 lines
4.4 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <folly/Conv.h>
|
|
#include <folly/CppAttributes.h>
|
|
#include <folly/futures/Future.h>
|
|
#include <atomic>
|
|
#include <string>
|
|
|
|
/**
|
|
* EDEN_BUG() should be used to log logic errors that should not happen unless
|
|
* there is a bug in the code.
|
|
*
|
|
* In debug builds this macro will cause the program to crash.
|
|
* However, in production builds crashing the program is fairly harsh, as this
|
|
* will destroy the client mount points, causing problems for any open programs
|
|
* or shells the user had that were using eden mounts. Therefore in production
|
|
* builds EDEN_BUG() just logs the error and then throws an exception that can
|
|
* be handled by the calling code.
|
|
*
|
|
* Use XLOG(FATAL) if you want to crash the program even in production builds.
|
|
*/
|
|
#define EDEN_BUG() \
|
|
::facebook::eden::EdenBugThrow() & \
|
|
::facebook::eden::EdenBug(__FILE__, __LINE__)
|
|
|
|
/**
|
|
* EDEN_BUG_FUTURE() is similar to EDEN_BUG() but should be used in context
|
|
* where a Future should be returned.
|
|
*
|
|
* In debug builds this will crash, but in production builds this will return a
|
|
* folly::Future<Type> containing an exception.
|
|
*/
|
|
#define EDEN_BUG_FUTURE(Type) \
|
|
::facebook::eden::EdenBugFuture<Type>() & \
|
|
::facebook::eden::EdenBug(__FILE__, __LINE__)
|
|
|
|
/**
|
|
* EDEN_BUG_EXCEPTION() is similar to EDEN_BUG() but returns an exception.
|
|
*/
|
|
#define EDEN_BUG_EXCEPTION() \
|
|
::facebook::eden::EdenBugException() & \
|
|
::facebook::eden::EdenBug(__FILE__, __LINE__)
|
|
|
|
namespace folly {
|
|
class exception_wrapper;
|
|
}
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
/**
|
|
* A helper class returned by the EDEN_BUG() macro.
|
|
*
|
|
* toException() can be called to convert it to a folly::exception_wrapper
|
|
* If toException() has not been called, it will throw an exception when it is
|
|
* destroyed.
|
|
*
|
|
* In debug builds EdenBug causes the program to abort rather than throwing or
|
|
* returning an exception.
|
|
*/
|
|
class EdenBug {
|
|
public:
|
|
FOLLY_COLD EdenBug(const char* file, int lineNumber);
|
|
FOLLY_COLD EdenBug(EdenBug&& other) noexcept;
|
|
EdenBug& operator=(EdenBug&& other) = delete;
|
|
~EdenBug();
|
|
|
|
/**
|
|
* Append to the bug message.
|
|
*/
|
|
template <typename T>
|
|
EdenBug&& operator<<(T&& t) && {
|
|
using folly::toAppend;
|
|
toAppend(std::forward<T>(t), &message_);
|
|
return std::move(*this);
|
|
}
|
|
|
|
/**
|
|
* Convert this EdenBug object to a folly::exception_wrapper
|
|
*
|
|
* If toException() is never called on an EdenBug object, it will throw on
|
|
* destruction.
|
|
*/
|
|
folly::exception_wrapper toException();
|
|
|
|
/**
|
|
* A wrapper for toException().throw_exception(). A typical use of EDEN_BUG()
|
|
* where the bug is captured is actually noreturn, but the compiler can't see
|
|
* that because moved-from EdenBug doesn't throw.
|
|
*
|
|
* To avoid compiler warnings, write:
|
|
* auto bug = EDEN_BUG() << "...";
|
|
* bug.throwException();
|
|
*/
|
|
[[noreturn]] void throwException();
|
|
|
|
/**
|
|
* Prevent EDEN_BUG() from crashing the program, even in debug builds.
|
|
*
|
|
* This is intended to allow unit tests to disable crashing.
|
|
* This generally shouldn't ever be called from normal production code.
|
|
*/
|
|
static void acquireDisableCrashLease();
|
|
static void releaseDisableCrashLease();
|
|
|
|
private:
|
|
void logError();
|
|
|
|
const char* file_;
|
|
int lineNumber_;
|
|
bool processed_{false};
|
|
std::string message_;
|
|
};
|
|
|
|
class EdenBugThrow {
|
|
public:
|
|
// We use operator&() here since it binds with lower precedence than the <<
|
|
// operator used to construct the EdenBug message.
|
|
[[noreturn]] void operator&(EdenBug&& bug) const {
|
|
bug.throwException();
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class EdenBugFuture {
|
|
public:
|
|
FOLLY_NODISCARD
|
|
folly::Future<T> operator&(EdenBug&& bug) const {
|
|
return folly::makeFuture<T>(bug.toException());
|
|
}
|
|
};
|
|
|
|
class EdenBugException {
|
|
public:
|
|
FOLLY_NODISCARD
|
|
folly::exception_wrapper operator&(EdenBug&& bug) const {
|
|
return bug.toException();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* EdenBugDisabler temporarily disables crashing on EDEN_BUG as long as it
|
|
* exists.
|
|
*/
|
|
class EdenBugDisabler {
|
|
public:
|
|
EdenBugDisabler();
|
|
~EdenBugDisabler();
|
|
|
|
EdenBugDisabler(const EdenBugDisabler&) = delete;
|
|
EdenBugDisabler operator=(const EdenBugDisabler&) = delete;
|
|
};
|
|
} // namespace eden
|
|
} // namespace facebook
|