Skip to content

Commit

Permalink
WTF: Skip heap allocation for small objects in DEFINE_STATIC_LOCAL.
Browse files Browse the repository at this point in the history
Many of these are only one or two pointers large anyway (e.g. AtomicString,
Vector), so using the heap doesn't save memory, and just adds a pointer
indirection to each access.

Change-Id: If63b228bd0b5f8040c7b13134f063c1e26322f85
Reviewed-on: https://chromium-review.googlesource.com/519846
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Reviewed-by: Yuta Kitamura <yutak@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#476283}
  • Loading branch information
jeremyroman authored and Commit Bot committed Jun 1, 2017
1 parent 19fd249 commit feca33b
Showing 1 changed file with 43 additions and 12 deletions.
55 changes: 43 additions & 12 deletions third_party/WebKit/Source/platform/wtf/StdLibExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#define WTF_StdLibExtras_h

#include <cstddef>
#include "base/memory/aligned_memory.h"
#include "base/numerics/safe_conversions.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/CPU.h"
Expand All @@ -38,6 +39,14 @@
#include "platform/wtf/Threading.h"
#endif

#define DEFINE_STATIC_LOCAL_IMPL(Type, Name, Arguments, allow_cross_thread) \
static WTF::StaticSingleton<Type> s_##Name( \
[&]() { return new WTF::StaticSingleton<Type>::WrapperType Arguments; }, \
[&](void* leaked_ptr) { \
new (leaked_ptr) WTF::StaticSingleton<Type>::WrapperType Arguments; \
}); \
Type& Name = s_##Name.Get(allow_cross_thread)

// Use |DEFINE_STATIC_LOCAL()| to declare and define a static local variable
// (|static T;|) so that it is leaked and its destructors are not called at
// exit. T may also be a Blink garbage collected object, in which case it is
Expand All @@ -47,20 +56,16 @@
// A |DEFINE_STATIC_LOCAL()| static should only be used on the thread it was
// created on.
//
#define DEFINE_STATIC_LOCAL(Type, Name, Arguments) \
static WTF::StaticSingleton<Type> s_##Name( \
new WTF::StaticSingleton<Type>::WrapperType Arguments); \
Type& Name = s_##Name.Get(false)
#define DEFINE_STATIC_LOCAL(Type, Name, Arguments) \
DEFINE_STATIC_LOCAL_IMPL(Type, Name, Arguments, false)

// |DEFINE_THREAD_SAFE_STATIC_LOCAL()| is the cross-thread accessible variant
// of |DEFINE_STATIC_LOCAL()|; use it if the singleton can be accessed by
// multiple threads.
//
// TODO: rename as DEFINE_CROSS_THREAD_STATIC_LOCAL() ?
#define DEFINE_THREAD_SAFE_STATIC_LOCAL(Type, Name, Arguments) \
static WTF::StaticSingleton<Type> s_##Name( \
new WTF::StaticSingleton<Type>::WrapperType Arguments); \
Type& Name = s_##Name.Get(true)
DEFINE_STATIC_LOCAL_IMPL(Type, Name, Arguments, true)

namespace blink {
template <typename T>
Expand Down Expand Up @@ -108,22 +113,24 @@ class StaticSingleton final {
// LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy
// details.

explicit StaticSingleton(WrapperType* instance)
: instance_(LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance))
template <typename HeapNew, typename PlacementNew>
StaticSingleton(const HeapNew& heap_new, const PlacementNew& placement_new)
: instance_(heap_new, placement_new)
#if DCHECK_IS_ON()
,
safely_initialized_(WTF::IsBeforeThreadCreated()),
thread_(WTF::internal::CurrentThreadSyscall())
#endif
{
LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance_.Get());
}

Type& Get(bool allow_cross_thread_use) const {
Type& Get(bool allow_cross_thread_use) {
#if DCHECK_IS_ON()
DCHECK(IsNotRacy(allow_cross_thread_use));
#endif
ALLOW_UNUSED_LOCAL(allow_cross_thread_use);
return Wrapper<Type>::Unwrap(instance_);
return Wrapper<Type>::Unwrap(instance_.Get());
}

operator Type&() { return Get(); }
Expand All @@ -139,8 +146,32 @@ class StaticSingleton final {
thread_ == WTF::internal::CurrentThreadSyscall();
}
#endif
template <typename T, bool is_small = sizeof(T) <= 32>
class InstanceStorage {
public:
template <typename HeapNew, typename PlacementNew>
InstanceStorage(const HeapNew& heap_new, const PlacementNew&)
: pointer_(heap_new()) {}
T* Get() { return pointer_; }

private:
T* pointer_;
};

template <typename T>
class InstanceStorage<T, true> {
public:
template <typename HeapNew, typename PlacementNew>
InstanceStorage(const HeapNew&, const PlacementNew& placement_new) {
placement_new(object_.void_data());
}
T* Get() { return object_.template data_as<T>(); }

private:
base::AlignedMemory<sizeof(T), ALIGNOF(T)> object_;
};

WrapperType* instance_;
InstanceStorage<WrapperType> instance_;
#if DCHECK_IS_ON()
bool safely_initialized_;
ThreadIdentifier thread_;
Expand Down

0 comments on commit feca33b

Please sign in to comment.