Commit 89bd17d8 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

FOLLY_KEEP for keeping function definitions

Summary: [Folly] `FOLLY_KEEP` for keeping function definitions when using function-sections even if the linker would remove them.

Reviewed By: alexshap

Differential Revision: D22575832

fbshipit-source-id: 08410b3c318e361b1f3efcbb8f168091faed86e8
parent f50f791e
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <folly/concurrency/UnboundedQueue.h> #include <folly/concurrency/UnboundedQueue.h>
#include <folly/MPMCQueue.h> #include <folly/MPMCQueue.h>
#include <folly/ProducerConsumerQueue.h> #include <folly/ProducerConsumerQueue.h>
#include <folly/lang/Keep.h>
#include <folly/portability/GFlags.h> #include <folly/portability/GFlags.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
...@@ -47,81 +48,85 @@ using UMPMC = folly::UMPMCQueue<T, MayBlock>; ...@@ -47,81 +48,85 @@ using UMPMC = folly::UMPMCQueue<T, MayBlock>;
FOLLY_ATTR_WEAK void noop(folly::Optional<int>&&) {} FOLLY_ATTR_WEAK void noop(folly::Optional<int>&&) {}
extern "C" void check_uspsc_mayblock_dequeue_ref( extern "C" FOLLY_KEEP void check_uspsc_mayblock_dequeue_ref(
USPSC<int, true>& queue, USPSC<int, true>& queue,
int& item) { int& item) {
queue.dequeue(item); queue.dequeue(item);
} }
extern "C" bool check_uspsc_mayblock_try_dequeue_ref( extern "C" FOLLY_KEEP bool check_uspsc_mayblock_try_dequeue_ref(
USPSC<int, true>& queue, USPSC<int, true>& queue,
int& item) { int& item) {
return queue.try_dequeue(item); return queue.try_dequeue(item);
} }
extern "C" bool check_uspsc_mayblock_try_dequeue_for_ref( extern "C" FOLLY_KEEP bool check_uspsc_mayblock_try_dequeue_for_ref(
USPSC<int, true>& queue, USPSC<int, true>& queue,
int& item, int& item,
std::chrono::milliseconds const& timeout) { std::chrono::milliseconds const& timeout) {
return queue.try_dequeue_for(item, timeout); return queue.try_dequeue_for(item, timeout);
} }
extern "C" bool check_uspsc_mayblock_try_dequeue_until_ref( extern "C" FOLLY_KEEP bool check_uspsc_mayblock_try_dequeue_until_ref(
USPSC<int, true>& queue, USPSC<int, true>& queue,
int& item, int& item,
std::chrono::steady_clock::time_point const& deadline) { std::chrono::steady_clock::time_point const& deadline) {
return queue.try_dequeue_until(item, deadline); return queue.try_dequeue_until(item, deadline);
} }
extern "C" int check_uspsc_mayblock_dequeue_ret(USPSC<int, true>& queue) { extern "C" FOLLY_KEEP int check_uspsc_mayblock_dequeue_ret(
USPSC<int, true>& queue) {
return queue.dequeue(); return queue.dequeue();
} }
extern "C" void check_uspsc_mayblock_try_dequeue_ret(USPSC<int, true>& queue) { extern "C" FOLLY_KEEP void check_uspsc_mayblock_try_dequeue_ret(
USPSC<int, true>& queue) {
noop(queue.try_dequeue()); noop(queue.try_dequeue());
} }
extern "C" void check_uspsc_mayblock_try_dequeue_for_ret( extern "C" FOLLY_KEEP void check_uspsc_mayblock_try_dequeue_for_ret(
USPSC<int, true>& queue, USPSC<int, true>& queue,
std::chrono::milliseconds const& timeout) { std::chrono::milliseconds const& timeout) {
noop(queue.try_dequeue_for(timeout)); noop(queue.try_dequeue_for(timeout));
} }
extern "C" void check_uspsc_mayblock_try_dequeue_until_ret( extern "C" FOLLY_KEEP void check_uspsc_mayblock_try_dequeue_until_ret(
USPSC<int, true>& queue, USPSC<int, true>& queue,
std::chrono::steady_clock::time_point const& deadline) { std::chrono::steady_clock::time_point const& deadline) {
noop(queue.try_dequeue_until(deadline)); noop(queue.try_dequeue_until(deadline));
} }
extern "C" void check_umpmc_mayblock_dequeue_ref( extern "C" FOLLY_KEEP void check_umpmc_mayblock_dequeue_ref(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
int& item) { int& item) {
queue.dequeue(item); queue.dequeue(item);
} }
extern "C" bool check_umpmc_mayblock_try_dequeue_ref( extern "C" FOLLY_KEEP bool check_umpmc_mayblock_try_dequeue_ref(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
int& item) { int& item) {
return queue.try_dequeue(item); return queue.try_dequeue(item);
} }
extern "C" bool check_umpmc_mayblock_try_dequeue_for_ref( extern "C" FOLLY_KEEP bool check_umpmc_mayblock_try_dequeue_for_ref(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
int& item, int& item,
std::chrono::milliseconds const& timeout) { std::chrono::milliseconds const& timeout) {
return queue.try_dequeue_for(item, timeout); return queue.try_dequeue_for(item, timeout);
} }
extern "C" bool check_umpmc_mayblock_try_dequeue_until_ref( extern "C" FOLLY_KEEP bool check_umpmc_mayblock_try_dequeue_until_ref(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
int& item, int& item,
std::chrono::steady_clock::time_point const& deadline) { std::chrono::steady_clock::time_point const& deadline) {
return queue.try_dequeue_until(item, deadline); return queue.try_dequeue_until(item, deadline);
} }
extern "C" int check_umpmc_mayblock_dequeue_ret(UMPMC<int, true>& queue) { extern "C" FOLLY_KEEP int check_umpmc_mayblock_dequeue_ret(
UMPMC<int, true>& queue) {
return queue.dequeue(); return queue.dequeue();
} }
extern "C" void check_umpmc_mayblock_try_dequeue_ret(UMPMC<int, true>& queue) { extern "C" FOLLY_KEEP void check_umpmc_mayblock_try_dequeue_ret(
UMPMC<int, true>& queue) {
noop(queue.try_dequeue()); noop(queue.try_dequeue());
} }
extern "C" void check_umpmc_mayblock_try_dequeue_for_ret( extern "C" FOLLY_KEEP void check_umpmc_mayblock_try_dequeue_for_ret(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
std::chrono::milliseconds const& timeout) { std::chrono::milliseconds const& timeout) {
noop(queue.try_dequeue_for(timeout)); noop(queue.try_dequeue_for(timeout));
} }
extern "C" void check_umpmc_mayblock_try_dequeue_until_ret( extern "C" FOLLY_KEEP void check_umpmc_mayblock_try_dequeue_until_ret(
UMPMC<int, true>& queue, UMPMC<int, true>& queue,
std::chrono::steady_clock::time_point const& deadline) { std::chrono::steady_clock::time_point const& deadline) {
noop(queue.try_dequeue_until(deadline)); noop(queue.try_dequeue_until(deadline));
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/detail/StaticSingletonManager.h> #include <folly/detail/StaticSingletonManager.h>
#include <folly/lang/Keep.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
namespace folly { namespace folly {
...@@ -35,16 +36,16 @@ struct MayThrow { ...@@ -35,16 +36,16 @@ struct MayThrow {
}; };
} // namespace } // namespace
extern "C" int* check() { extern "C" FOLLY_KEEP int* check() {
return &createGlobal<int, void>(); return &createGlobal<int, void>();
} }
extern "C" void* check_throw() { extern "C" FOLLY_KEEP void* check_throw() {
MayThrow<false> obj; MayThrow<false> obj;
return &createGlobal<MayThrow<false>, void>(); return &createGlobal<MayThrow<false>, void>();
} }
extern "C" void* check_nothrow() { extern "C" FOLLY_KEEP void* check_nothrow() {
MayThrow<false> obj; MayThrow<false> obj;
return &createGlobal<MayThrow<true>, void>(); return &createGlobal<MayThrow<true>, void>();
} }
......
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
// FOLLY_KEEP
//
// When applied to a function, prevents removal of the function.
//
// Functions may be removed when building with both function-sections and
// gc-sections. It is tricky to keep them; this utility captures the steps
// required.
//
// In order for this mechanism to work, this header must be included. This
// mechanism relies on the hidden global variable below.
//
// The linker, when asked to with --gc-sections, may throw out unreferenced
// sections. When the compiler emits each function into its own section, as it
// does when asked to with -ffunction-sections, the linker will throw out
// unreferenced functions. The key is to move all kept functions into a single
// section, avoiding the behavior of -ffunction-sections, and then force the
// compiler to emit some reference to at least one function in that section.
// This way, the linker will see at least one reference to the kept section,
// and so will not throw it out.
#if __GNUC__ && __linux__
#define FOLLY_KEEP [[gnu::section(".text.folly.keep")]]
#else
#define FOLLY_KEEP
#endif
#if __GNUC__ && __linux__
#define FOLLY_KEEP_DETAIL_ATTR_NAKED [[gnu::naked]]
#define FOLLY_KEEP_DETAIL_ATTR_NOINLINE [[gnu::noinline]]
#else
#define FOLLY_KEEP_DETAIL_ATTR_NAKED
#define FOLLY_KEEP_DETAIL_ATTR_NOINLINE
#endif
namespace folly {
namespace detail {
// marking this as [[gnu::naked]] gets clang not to emit any text for this
FOLLY_KEEP FOLLY_KEEP_DETAIL_ATTR_NAKED static void keep_anchor() {}
class keep {
public:
// must accept the anchor function as an argument
FOLLY_KEEP_DETAIL_ATTR_NOINLINE explicit keep(void (*)()) noexcept {}
};
// noinline ctor and trivial dtor minimize the text size of this
static keep keep_instance{keep_anchor};
} // namespace detail
} // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment