Commit dbfe809c authored by Benoit Lize's avatar Benoit Lize Committed by Commit Bot

blink/wtf: Make FastMalloc() malloc() when PartitionAlloc is malloc().

There is no reason to use FastMalloc() when PartitionAlloc is
malloc(). Aside from increasing memory usage and heap fragmentation,
this reduces the number of pointers allocated out of the GigaCage, which
matters for CheckedPtr.

To address that, make USING_FAST_MALLOC() a no-op in this case, and
redirect the remaining callers of FastMalloc() to malloc().

Bug: 998048
Change-Id: I3bd04570cabc7c8e9d36908013bb1c82a65acddf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2310334
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarBartek Nowierski <bartekn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#829272}
parent 173b8417
include_rules = [ include_rules = [
# To only allow a subset of base/ in Blink, we explicitly list all # To only allow a subset of base/ in Blink, we explicitly list all
# directories and files instead of writing 'base/'. # directories and files instead of writing 'base/'.
"+base/allocator/buildflags.h",
"+base/allocator/partition_allocator", "+base/allocator/partition_allocator",
"+base/atomic_ref_count.h", "+base/atomic_ref_count.h",
"+base/auto_reset.h", "+base/auto_reset.h",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <atomic> #include <atomic>
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/check_op.h" #include "base/check_op.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
...@@ -108,6 +109,58 @@ class __thisIsHereToForceASemicolonAfterThisMacro; ...@@ -108,6 +109,58 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
// }; // };
// //
// In official builds, do not include type info string literals to avoid
// bloating the binary.
#if defined(OFFICIAL_BUILD)
#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr
#else
#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>()
#endif
// Both of these macros enable fast malloc and provide type info to the heap
// profiler. The regular macro does not provide type info in official builds,
// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME|
// variant provides type info unconditionally, so it should be used sparingly.
// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a
// template argument; |USING_FAST_MALLOC| does.
#define USING_FAST_MALLOC(type) \
USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type))
#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
USING_FAST_MALLOC_INTERNAL(type, #type)
// FastMalloc doesn't provide isolation, only a (hopefully fast) malloc(). When
// PartitionAlloc is already the malloc() implementation, there is nothing to
// do.
//
// Note that we could keep the two heaps separate, but each PartitionAlloc's
// root has a cost, both in used memory and in virtual address space. Don't pay
// it when we don't have to.
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// Still using operator overaloading to be closer to the other case, and not
// require code changes to DISALLOW_NEW() objects.
#define USING_FAST_MALLOC_INTERNAL(type, typeName) \
public: \
void* operator new(size_t, void* p) { return p; } \
void* operator new[](size_t, void* p) { return p; } \
\
void* operator new(size_t size) { return malloc(size); } \
\
void operator delete(void* p) { free(p); } \
\
void* operator new[](size_t size) { return malloc(size); } \
\
void operator delete[](void* p) { free(p); } \
void* operator new(size_t, NotNullTag, void* location) { \
DCHECK(location); \
return location; \
} \
\
private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
#else
#define USING_FAST_MALLOC_INTERNAL(type, typeName) \ #define USING_FAST_MALLOC_INTERNAL(type, typeName) \
public: \ public: \
void* operator new(size_t, void* p) { return p; } \ void* operator new(size_t, void* p) { return p; } \
...@@ -132,24 +185,7 @@ class __thisIsHereToForceASemicolonAfterThisMacro; ...@@ -132,24 +185,7 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
private: \ private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro
// In official builds, do not include type info string literals to avoid #endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// bloating the binary.
#if defined(OFFICIAL_BUILD)
#define WTF_HEAP_PROFILER_TYPE_NAME(T) nullptr
#else
#define WTF_HEAP_PROFILER_TYPE_NAME(T) ::WTF::GetStringWithTypeName<T>()
#endif
// Both of these macros enable fast malloc and provide type info to the heap
// profiler. The regular macro does not provide type info in official builds,
// to avoid bloating the binary with type name strings. The |WITH_TYPE_NAME|
// variant provides type info unconditionally, so it should be used sparingly.
// Furthermore, the |WITH_TYPE_NAME| variant does not work if |type| is a
// template argument; |USING_FAST_MALLOC| does.
#define USING_FAST_MALLOC(type) \
USING_FAST_MALLOC_INTERNAL(type, WTF_HEAP_PROFILER_TYPE_NAME(type))
#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
USING_FAST_MALLOC_INTERNAL(type, #type)
// TOOD(omerkatz): replace these casts with std::atomic_ref (C++20) once it // TOOD(omerkatz): replace these casts with std::atomic_ref (C++20) once it
// becomes available // becomes available
...@@ -359,4 +395,4 @@ inline void* operator new(size_t, NotNullTag, void* location) { ...@@ -359,4 +395,4 @@ inline void* operator new(size_t, NotNullTag, void* location) {
return location; return location;
} }
#endif /* WTF_Allocator_h */ #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ALLOCATOR_ALLOCATOR_H_
...@@ -54,7 +54,9 @@ bool Partitions::initialized_ = false; ...@@ -54,7 +54,9 @@ bool Partitions::initialized_ = false;
// These statics are inlined, so cannot be LazyInstances. We create the values, // These statics are inlined, so cannot be LazyInstances. We create the values,
// and then set the pointers correctly in Initialize(). // and then set the pointers correctly in Initialize().
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
base::ThreadSafePartitionRoot* Partitions::fast_malloc_root_ = nullptr; base::ThreadSafePartitionRoot* Partitions::fast_malloc_root_ = nullptr;
#endif
base::ThreadSafePartitionRoot* Partitions::array_buffer_root_ = nullptr; base::ThreadSafePartitionRoot* Partitions::array_buffer_root_ = nullptr;
base::ThreadSafePartitionRoot* Partitions::buffer_root_ = nullptr; base::ThreadSafePartitionRoot* Partitions::buffer_root_ = nullptr;
base::ThreadUnsafePartitionRoot* Partitions::layout_root_ = nullptr; base::ThreadUnsafePartitionRoot* Partitions::layout_root_ = nullptr;
...@@ -67,26 +69,22 @@ void Partitions::Initialize() { ...@@ -67,26 +69,22 @@ void Partitions::Initialize() {
// static // static
bool Partitions::InitializeOnce() { bool Partitions::InitializeOnce() {
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static base::PartitionAllocator fast_malloc_allocator{}; static base::PartitionAllocator fast_malloc_allocator{};
fast_malloc_allocator.init(
{base::PartitionOptions::Alignment::kRegular,
base::PartitionOptions::ThreadCache::kEnabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
fast_malloc_root_ = fast_malloc_allocator.root();
#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static base::PartitionAllocator array_buffer_allocator{}; static base::PartitionAllocator array_buffer_allocator{};
static base::PartitionAllocator buffer_allocator{}; static base::PartitionAllocator buffer_allocator{};
static base::ThreadUnsafePartitionAllocator layout_allocator{}; static base::ThreadUnsafePartitionAllocator layout_allocator{};
base::PartitionAllocGlobalInit(&Partitions::HandleOutOfMemory); base::PartitionAllocGlobalInit(&Partitions::HandleOutOfMemory);
// Only one thread cache at a time is supported, in this case it is already
// claimed by malloc().
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
fast_malloc_allocator.init(
{base::PartitionOptions::Alignment::kRegular,
base::PartitionOptions::ThreadCache::kDisabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
#else
fast_malloc_allocator.init(
{base::PartitionOptions::Alignment::kRegular,
base::PartitionOptions::ThreadCache::kEnabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
#endif
array_buffer_allocator.init( array_buffer_allocator.init(
{base::PartitionOptions::Alignment::kRegular, {base::PartitionOptions::Alignment::kRegular,
base::PartitionOptions::ThreadCache::kDisabled, base::PartitionOptions::ThreadCache::kDisabled,
...@@ -98,14 +96,15 @@ bool Partitions::InitializeOnce() { ...@@ -98,14 +96,15 @@ bool Partitions::InitializeOnce() {
base::PartitionOptions::ThreadCache::kDisabled, base::PartitionOptions::ThreadCache::kDisabled,
base::PartitionOptions::PCScan::kAlwaysDisabled}); base::PartitionOptions::PCScan::kAlwaysDisabled});
fast_malloc_root_ = fast_malloc_allocator.root();
array_buffer_root_ = array_buffer_allocator.root(); array_buffer_root_ = array_buffer_allocator.root();
buffer_root_ = buffer_allocator.root(); buffer_root_ = buffer_allocator.root();
layout_root_ = layout_allocator.root(); layout_root_ = layout_allocator.root();
if (base::features::IsPartitionAllocPCScanEnabled() || if (base::features::IsPartitionAllocPCScanEnabled() ||
base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) { base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) {
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
fast_malloc_root_->EnablePCScan(); fast_malloc_root_->EnablePCScan();
#endif
buffer_root_->EnablePCScan(); buffer_root_->EnablePCScan();
} }
...@@ -130,8 +129,10 @@ void Partitions::DumpMemoryStats( ...@@ -130,8 +129,10 @@ void Partitions::DumpMemoryStats(
// accessed only on the main thread. // accessed only on the main thread.
DCHECK(IsMainThread()); DCHECK(IsMainThread());
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
FastMallocPartition()->DumpStats("fast_malloc", is_light_dump, FastMallocPartition()->DumpStats("fast_malloc", is_light_dump,
partition_stats_dumper); partition_stats_dumper);
#endif
ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump, ArrayBufferPartition()->DumpStats("array_buffer", is_light_dump,
partition_stats_dumper); partition_stats_dumper);
BufferPartition()->DumpStats("buffer", is_light_dump, partition_stats_dumper); BufferPartition()->DumpStats("buffer", is_light_dump, partition_stats_dumper);
...@@ -167,8 +168,10 @@ size_t Partitions::TotalSizeOfCommittedPages() { ...@@ -167,8 +168,10 @@ size_t Partitions::TotalSizeOfCommittedPages() {
DCHECK(initialized_); DCHECK(initialized_);
size_t total_size = 0; size_t total_size = 0;
// Racy reads below: this is fine to collect statistics. // Racy reads below: this is fine to collect statistics.
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
total_size += total_size +=
TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages); TS_UNCHECKED_READ(FastMallocPartition()->total_size_of_committed_pages);
#endif
total_size += total_size +=
TS_UNCHECKED_READ(ArrayBufferPartition()->total_size_of_committed_pages); TS_UNCHECKED_READ(ArrayBufferPartition()->total_size_of_committed_pages);
total_size += total_size +=
...@@ -261,20 +264,36 @@ size_t Partitions::BufferActualSize(size_t n) { ...@@ -261,20 +264,36 @@ size_t Partitions::BufferActualSize(size_t n) {
return BufferPartition()->ActualSize(n); return BufferPartition()->ActualSize(n);
} }
// Ideally this would be removed when PartitionAlloc is malloc(), but there are
// quite a few callers. Just forward to the C functions instead. Most of the
// usual callers will never reach here though, as USING_FAST_MALLOC() becomes a
// no-op.
// static // static
void* Partitions::FastMalloc(size_t n, const char* type_name) { void* Partitions::FastMalloc(size_t n, const char* type_name) {
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
return FastMallocPartition()->Alloc(n, type_name); return FastMallocPartition()->Alloc(n, type_name);
#else
return malloc(n);
#endif
} }
// static // static
void* Partitions::FastZeroedMalloc(size_t n, const char* type_name) { void* Partitions::FastZeroedMalloc(size_t n, const char* type_name) {
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
return FastMallocPartition()->AllocFlags(base::PartitionAllocZeroFill, n, return FastMallocPartition()->AllocFlags(base::PartitionAllocZeroFill, n,
type_name); type_name);
#else
return calloc(n, 1);
#endif
} }
// static // static
void Partitions::FastFree(void* p) { void Partitions::FastFree(void* p) {
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
FastMallocPartition()->Free(p); FastMallocPartition()->Free(p);
#else
free(p);
#endif
} }
// static // static
......
...@@ -89,16 +89,20 @@ class WTF_EXPORT Partitions { ...@@ -89,16 +89,20 @@ class WTF_EXPORT Partitions {
static void HandleOutOfMemory(size_t size); static void HandleOutOfMemory(size_t size);
private: private:
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
ALWAYS_INLINE static base::ThreadSafePartitionRoot* FastMallocPartition() { ALWAYS_INLINE static base::ThreadSafePartitionRoot* FastMallocPartition() {
DCHECK(initialized_); DCHECK(initialized_);
return fast_malloc_root_; return fast_malloc_root_;
} }
#endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static bool InitializeOnce(); static bool InitializeOnce();
static bool initialized_; static bool initialized_;
// See Allocator.md for a description of these partitions. // See Allocator.md for a description of these partitions.
#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
static base::ThreadSafePartitionRoot* fast_malloc_root_; static base::ThreadSafePartitionRoot* fast_malloc_root_;
#endif
static base::ThreadSafePartitionRoot* array_buffer_root_; static base::ThreadSafePartitionRoot* array_buffer_root_;
static base::ThreadSafePartitionRoot* buffer_root_; static base::ThreadSafePartitionRoot* buffer_root_;
static base::ThreadUnsafePartitionRoot* layout_root_; static base::ThreadUnsafePartitionRoot* layout_root_;
......
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