diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index 7c2a147bc88..dd703b53a4c 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -55,6 +55,131 @@ struct greater_ptr : public std::binary_function { } }; +/// An efficient, type-erasing, non-owning reference to a callable. This is +/// intended for use as the type of a function parameter that is not used +/// after the function in question returns. +/// +/// This class does not own the callable, so it is not in general safe to store +/// a function_ref. +template class function_ref; + +#if LLVM_HAS_VARIADIC_TEMPLATES + +template +class function_ref { + Ret (*callback)(void *callable, Params ...params); + void *callable; + + template + static Ret callback_fn(void *callable, Params ...params) { + return reinterpret_cast(*callable)( + std::forward(params)...); + } + +public: + template + function_ref(Callable &&callable) + : callback(callback_fn), + callable(reinterpret_cast(&callable)) {} + Ret operator()(Params ...params) const { + return callback(callable, std::forward(params)...); + } +}; + +#else + +template +class function_ref { + Ret (*callback)(void *callable); + void *callable; + + template + static Ret callback_fn(void *callable) { + return reinterpret_cast(*callable)(); + } + +public: + template + function_ref(Callable &&callable) + : callback(callback_fn), + callable(reinterpret_cast(&callable)) {} + Ret operator()() const { return callback(callable); } +}; + +template +class function_ref { + Ret (*callback)(void *callable, Param1 param1); + void *callable; + + template + static Ret callback_fn(void *callable, Param1 param1) { + return reinterpret_cast(*callable)( + std::forward(param1)); + } + +public: + template + function_ref(Callable &&callable) + : callback(callback_fn), + callable(reinterpret_cast(&callable)) {} + Ret operator()(Param1 param1) { + return callback(callable, std::forward(param1)); + } +}; + +template +class function_ref { + Ret (*callback)(void *callable, Param1 param1, Param2 param2); + void *callable; + + template + static Ret callback_fn(void *callable, Param1 param1, Param2 param2) { + return reinterpret_cast(*callable)( + std::forward(param1), + std::forward(param2)); + } + +public: + template + function_ref(Callable &&callable) + : callback(callback_fn), + callable(reinterpret_cast(&callable)) {} + Ret operator()(Param1 param1, Param2 param2) { + return callback(callable, + std::forward(param1), + std::forward(param2)); + } +}; + +template +class function_ref { + Ret (*callback)(void *callable, Param1 param1, Param2 param2, Param3 param3); + void *callable; + + template + static Ret callback_fn(void *callable, Param1 param1, Param2 param2, + Param3 param3) { + return reinterpret_cast(*callable)( + std::forward(param1), + std::forward(param2), + std::forward(param3)); + } + +public: + template + function_ref(Callable &&callable) + : callback(callback_fn), + callable(reinterpret_cast(&callable)) {} + Ret operator()(Param1 param1, Param2 param2, Param3 param3) { + return callback(callable, + std::forward(param1), + std::forward(param2), + std::forward(param3)); + } +}; + +#endif + // deleter - Very very very simple method that is used to invoke operator // delete on something. It is used like this: // diff --git a/include/llvm/Support/CrashRecoveryContext.h b/include/llvm/Support/CrashRecoveryContext.h index 6b9e0439790..c132373e91d 100644 --- a/include/llvm/Support/CrashRecoveryContext.h +++ b/include/llvm/Support/CrashRecoveryContext.h @@ -12,11 +12,13 @@ #include +#include "llvm/ADT/STLExtras.h" + namespace llvm { class StringRef; class CrashRecoveryContextCleanup; - + /// \brief Crash recovery helper object. /// /// This class implements support for running operations in a safe context so @@ -46,21 +48,10 @@ class CrashRecoveryContext { void *Impl; CrashRecoveryContextCleanup *head; - /// An adaptor to convert an arbitrary functor into a void(void*), void* pair. - template struct FunctorAdaptor { - T Fn; - static void invoke(void *Data) { - return static_cast*>(Data)->Fn(); - } - typedef void Callback(void*); - Callback *fn() { return &invoke; } - void *arg() { return this; } - }; - public: CrashRecoveryContext() : Impl(nullptr), head(nullptr) {} ~CrashRecoveryContext(); - + void registerCleanup(CrashRecoveryContextCleanup *cleanup); void unregisterCleanup(CrashRecoveryContextCleanup *cleanup); @@ -86,11 +77,9 @@ public: /// make as little assumptions as possible about the program state when /// RunSafely has returned false. Clients can use getBacktrace() to retrieve /// the backtrace of the crash on failures. - bool RunSafely(void (*Fn)(void*), void *UserData); - template - bool RunSafely(Functor Fn) { - FunctorAdaptor Adaptor = { Fn }; - return RunSafely(Adaptor.fn(), Adaptor.arg()); + bool RunSafely(function_ref Fn); + bool RunSafely(void (*Fn)(void*), void *UserData) { + return RunSafely([&]() { Fn(UserData); }); } /// \brief Execute the provide callback function (with the given arguments) in @@ -98,12 +87,10 @@ public: /// requested stack size). /// /// See RunSafely() and llvm_execute_on_thread(). + bool RunSafelyOnThread(function_ref, unsigned RequestedStackSize = 0); bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, - unsigned RequestedStackSize = 0); - template - bool RunSafelyOnThread(Functor Fn, unsigned RequestedStackSize = 0) { - FunctorAdaptor Adaptor = { Fn }; - return RunSafelyOnThread(Adaptor.fn(), Adaptor.arg(), RequestedStackSize); + unsigned RequestedStackSize = 0) { + return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize); } /// \brief Explicitly trigger a crash recovery in the current process, and diff --git a/include/llvm/Transforms/Utils/CtorUtils.h b/include/llvm/Transforms/Utils/CtorUtils.h index a96ba2b8458..81e7b951c25 100644 --- a/include/llvm/Transforms/Utils/CtorUtils.h +++ b/include/llvm/Transforms/Utils/CtorUtils.h @@ -14,8 +14,7 @@ #ifndef LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H #define LLVM_TRANSFORMS_UTILS_CTOR_UTILS_H -#include -#include +#include "llvm/ADT/STLExtras.h" namespace llvm { @@ -23,12 +22,10 @@ class GlobalVariable; class Function; class Module; -typedef bool (*ShouldRemoveCtor)(void *, Function *); - /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the /// entries for which it returns true. Return true if anything changed. -bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove, - void *Context); +bool optimizeGlobalCtorsList(Module &M, + function_ref ShouldRemove); } // End llvm namespace diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index 513875d4de4..a426377042d 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -301,7 +301,7 @@ void CrashRecoveryContext::Disable() { #endif -bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) { +bool CrashRecoveryContext::RunSafely(function_ref Fn) { // If crash recovery is disabled, do nothing. if (gCrashRecoveryEnabled) { assert(!Impl && "Crash recovery context already initialized!"); @@ -313,7 +313,7 @@ bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) { } } - Fn(UserData); + Fn(); return true; } @@ -334,8 +334,7 @@ const std::string &CrashRecoveryContext::getBacktrace() const { namespace { struct RunSafelyOnThreadInfo { - void (*Fn)(void*); - void *Data; + function_ref Fn; CrashRecoveryContext *CRC; bool Result; }; @@ -344,11 +343,11 @@ struct RunSafelyOnThreadInfo { static void RunSafelyOnThread_Dispatch(void *UserData) { RunSafelyOnThreadInfo *Info = reinterpret_cast(UserData); - Info->Result = Info->CRC->RunSafely(Info->Fn, Info->Data); + Info->Result = Info->CRC->RunSafely(Info->Fn); } -bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData, +bool CrashRecoveryContext::RunSafelyOnThread(function_ref Fn, unsigned RequestedStackSize) { - RunSafelyOnThreadInfo Info = { Fn, UserData, this, false }; + RunSafelyOnThreadInfo Info = { Fn, this, false }; llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) CRC->setSwitchedThread(); diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 03b17d52386..9decddcff80 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -54,16 +54,16 @@ namespace { bool RemoveUnusedGlobalValue(GlobalValue &GV); }; +} /// Returns true if F contains only a single "ret" instruction. -bool isEmptyFunction(void *Context, Function *F) { +static bool isEmptyFunction(Function *F) { BasicBlock &Entry = F->getEntryBlock(); if (Entry.size() != 1 || !isa(Entry.front())) return false; ReturnInst &RI = cast(Entry.front()); return RI.getReturnValue() == NULL; } -} char GlobalDCE::ID = 0; INITIALIZE_PASS(GlobalDCE, "globaldce", @@ -75,7 +75,7 @@ bool GlobalDCE::runOnModule(Module &M) { bool Changed = false; // Remove empty functions from the global ctors list. - Changed |= optimizeGlobalCtorsList(M, isEmptyFunction, nullptr); + Changed |= optimizeGlobalCtorsList(M, isEmptyFunction); // Loop over the module, adding globals which are obviously necessary. for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 3db0abf89f5..a8471bacb49 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -3022,10 +3022,9 @@ bool GlobalOpt::runOnModule(Module &M) { LocalChange |= OptimizeFunctions(M); // Optimize global_ctors list. - LocalChange |= optimizeGlobalCtorsList(M, [](void *C, Function *F) -> bool { - GlobalOpt *self = static_cast(C); - return EvaluateStaticConstructor(F, self->DL, self->TLI); - }, this); + LocalChange |= optimizeGlobalCtorsList(M, [&](Function *F) { + return EvaluateStaticConstructor(F, DL, TLI); + }); // Optimize non-address-taken globals. LocalChange |= OptimizeGlobalVars(M); diff --git a/lib/Transforms/Utils/CtorUtils.cpp b/lib/Transforms/Utils/CtorUtils.cpp index 0082df01214..7cf793f6266 100644 --- a/lib/Transforms/Utils/CtorUtils.cpp +++ b/lib/Transforms/Utils/CtorUtils.cpp @@ -132,8 +132,8 @@ GlobalVariable *findGlobalCtors(Module &M) { /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the /// entries for which it returns true. Return true if anything changed. -bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove, - void *Context) { +bool optimizeGlobalCtorsList(Module &M, + function_ref ShouldRemove) { GlobalVariable *GlobalCtors = findGlobalCtors(M); if (!GlobalCtors) return false; @@ -163,7 +163,7 @@ bool optimizeGlobalCtorsList(Module &M, ShouldRemoveCtor ShouldRemove, continue; // If we can evaluate the ctor at compile time, do. - if (ShouldRemove(Context, F)) { + if (ShouldRemove(F)) { Ctors.erase(Ctors.begin() + i); MadeChange = true; --i;