Remove PDFium's private copy of Partition Alloc.
Change-Id: Ieeefa949b28440fbaa910a3da55e655846b1b1a0
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/96530
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn
index e24ea0a..5045662 100644
--- a/third_party/BUILD.gn
+++ b/third_party/BUILD.gn
@@ -623,57 +623,6 @@
}
}
-if (pdf_use_partition_alloc) {
- source_set("pdfium_partition_alloc") {
- configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [
- "//build/config/compiler:no_chromium_code",
- ":pdfium_third_party_config",
- ]
- sources = [
- "base/allocator/partition_allocator/address_space_randomization.cc",
- "base/allocator/partition_allocator/address_space_randomization.h",
- "base/allocator/partition_allocator/oom.h",
- "base/allocator/partition_allocator/oom_callback.cc",
- "base/allocator/partition_allocator/oom_callback.h",
- "base/allocator/partition_allocator/page_allocator.cc",
- "base/allocator/partition_allocator/page_allocator.h",
- "base/allocator/partition_allocator/page_allocator_constants.h",
- "base/allocator/partition_allocator/page_allocator_internal.h",
- "base/allocator/partition_allocator/partition_alloc.cc",
- "base/allocator/partition_allocator/partition_alloc.h",
- "base/allocator/partition_allocator/partition_alloc_check.h",
- "base/allocator/partition_allocator/partition_alloc_constants.h",
- "base/allocator/partition_allocator/partition_bucket.cc",
- "base/allocator/partition_allocator/partition_bucket.h",
- "base/allocator/partition_allocator/partition_cookie.h",
- "base/allocator/partition_allocator/partition_direct_map_extent.h",
- "base/allocator/partition_allocator/partition_freelist_entry.h",
- "base/allocator/partition_allocator/partition_oom.cc",
- "base/allocator/partition_allocator/partition_oom.h",
- "base/allocator/partition_allocator/partition_page.cc",
- "base/allocator/partition_allocator/partition_page.h",
- "base/allocator/partition_allocator/partition_root_base.cc",
- "base/allocator/partition_allocator/partition_root_base.h",
- "base/allocator/partition_allocator/random.cc",
- "base/allocator/partition_allocator/random.h",
- "base/allocator/partition_allocator/spin_lock.cc",
- "base/allocator/partition_allocator/spin_lock.h",
- ]
- deps = [ ":pdfium_base" ]
- if (is_win) {
- sources += [
- "base/allocator/partition_allocator/page_allocator_internals_win.h",
- ]
- }
- if (is_posix) {
- sources += [
- "base/allocator/partition_allocator/page_allocator_internals_posix.h",
- ]
- }
- }
-}
-
source_set("pdfium_base_test_support") {
testonly = true
sources = []
diff --git a/third_party/base/allocator/partition_allocator/DIR_METADATA b/third_party/base/allocator/partition_allocator/DIR_METADATA
deleted file mode 100644
index 97f4529..0000000
--- a/third_party/base/allocator/partition_allocator/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
- component: "Blink>MemoryAllocator>Partition"
-}
-# Also: security-dev@chromium.org
-team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/base/allocator/partition_allocator/OWNERS b/third_party/base/allocator/partition_allocator/OWNERS
deleted file mode 100644
index 95d9982..0000000
--- a/third_party/base/allocator/partition_allocator/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-palmer@chromium.org
-tsepez@chromium.org
diff --git a/third_party/base/allocator/partition_allocator/address_space_randomization.cc b/third_party/base/allocator/partition_allocator/address_space_randomization.cc
deleted file mode 100644
index a738c34..0000000
--- a/third_party/base/allocator/partition_allocator/address_space_randomization.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/address_space_randomization.h"
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/allocator/partition_allocator/random.h"
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-#include "third_party/base/check_op.h"
-
-#if BUILDFLAG(IS_WIN)
-#include <windows.h> // Must be in front of other Windows header files.
-
-#include <VersionHelpers.h>
-#endif
-
-namespace pdfium {
-namespace base {
-
-void* GetRandomPageBase() {
- uintptr_t random = static_cast<uintptr_t>(RandomValue());
-
-#if defined(ARCH_CPU_64_BITS)
- random <<= 32ULL;
- random |= static_cast<uintptr_t>(RandomValue());
-
-// The kASLRMask and kASLROffset constants will be suitable for the
-// OS and build configuration.
-#if BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- // Windows >= 8.1 has the full 47 bits. Use them where available.
- static bool windows_81 = false;
- static bool windows_81_initialized = false;
- if (!windows_81_initialized) {
- windows_81 = IsWindows8Point1OrGreater();
- windows_81_initialized = true;
- }
- if (!windows_81) {
- random &= internal::ASLRMaskBefore8_10();
- } else {
- random &= internal::ASLRMask();
- }
- random += internal::ASLROffset();
-#else
- random &= internal::ASLRMask();
- random += internal::ASLROffset();
-#endif // BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-#else // defined(ARCH_CPU_32_BITS)
-#if BUILDFLAG(IS_WIN)
- // On win32 host systems the randomization plus huge alignment causes
- // excessive fragmentation. Plus most of these systems lack ASLR, so the
- // randomization isn't buying anything. In that case we just skip it.
- // TODO(palmer): Just dump the randomization when HE-ASLR is present.
- static BOOL is_wow64 = -1;
- if (is_wow64 == -1 && !IsWow64Process(GetCurrentProcess(), &is_wow64))
- is_wow64 = FALSE;
- if (!is_wow64)
- return nullptr;
-#endif // BUILDFLAG(IS_WIN)
- random &= internal::ASLRMask();
- random += internal::ASLROffset();
-#endif // defined(ARCH_CPU_32_BITS)
-
- DCHECK_EQ(0ULL, (random & PageAllocationGranularityOffsetMask()));
- return reinterpret_cast<void*>(random);
-}
-
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/address_space_randomization.h b/third_party/base/allocator/partition_allocator/address_space_randomization.h
deleted file mode 100644
index 7ab4cb2..0000000
--- a/third_party/base/allocator/partition_allocator/address_space_randomization.h
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/base_export.h"
-#include "third_party/base/compiler_specific.h"
-
-namespace pdfium {
-namespace base {
-
-// Calculates a random preferred mapping address. In calculating an address, we
-// balance good ASLR against not fragmenting the address space too badly.
-BASE_EXPORT void* GetRandomPageBase();
-
-namespace internal {
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-AslrAddress(uintptr_t mask) {
- return mask & PageAllocationGranularity();
-}
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-AslrMask(uintptr_t bits) {
- return AslrAddress((1ULL << bits) - 1ULL);
-}
-
-// Turn off formatting, because the thicket of nested ifdefs below is
-// incomprehensible without indentation. It is also incomprehensible with
-// indentation, but the only other option is a combinatorial explosion of
-// *_{win,linux,mac,foo}_{32,64}.h files.
-//
-// clang-format off
-
-#if defined(ARCH_CPU_64_BITS)
-
- #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-
- // We shouldn't allocate system pages at all for sanitizer builds. However,
- // we do, and if random hint addresses interfere with address ranges
- // hard-coded in those tools, bad things happen. This address range is
- // copied from TSAN source but works with all tools. See
- // https://crbug.com/539863.
- PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
- ASLRMask() {
- return AslrAddress(0x007fffffffffULL);
- }
- PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
- ASLROffset() {
- return AslrAddress(0x7e8000000000ULL);
- }
-
- #elif BUILDFLAG(IS_WIN)
-
- // Windows 8.10 and newer support the full 48 bit address range. Older
- // versions of Windows only support 44 bits. Since ASLROffset() is non-zero
- // and may cause a carry, use 47 and 43 bit masks. See
- // http://www.alex-ionescu.com/?p=246
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(47);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLRMaskBefore8_10() {
- return AslrMask(43);
- }
- // Try not to map pages into the range where Windows loads DLLs by default.
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return 0x80000000ULL;
- }
-
- #elif BUILDFLAG(IS_APPLE)
-
- // macOS as of 10.12.5 does not clean up entries in page map levels 3/4
- // [PDP/PML4] created from mmap or mach_vm_allocate, even after the region
- // is destroyed. Using a virtual address space that is too large causes a
- // leak of about 1 wired [can never be paged out] page per call to mmap. The
- // page is only reclaimed when the process is killed. Confine the hint to a
- // 39-bit section of the virtual address space.
- //
- // This implementation adapted from
- // https://chromium-review.googlesource.com/c/v8/v8/+/557958. The difference
- // is that here we clamp to 39 bits, not 32.
- //
- // TODO(crbug.com/738925): Remove this limitation if/when the macOS behavior
- // changes.
- PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
- ASLRMask() {
- return AslrMask(38);
- }
- PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
- ASLROffset() {
- return AslrAddress(0x1000000000ULL);
- }
-
- #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-
- #if defined(ARCH_CPU_X86_64)
-
- // Linux (and macOS) support the full 47-bit user space of x64 processors.
- // Use only 46 to allow the kernel a chance to fulfill the request.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(46);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0);
- }
-
- #elif defined(ARCH_CPU_ARM64)
-
- #if BUILDFLAG(IS_ANDROID)
-
- // Restrict the address range on Android to avoid a large performance
- // regression in single-process WebViews. See https://crbug.com/837640.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(30);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x20000000ULL);
- }
-
- #else
-
- // ARM64 on Linux has 39-bit user space. Use 38 bits since kASLROffset
- // could cause a carry.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(38);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x1000000000ULL);
- }
-
- #endif
-
- #elif defined(ARCH_CPU_PPC64)
-
- #if defined(OS_AIX)
-
- // AIX has 64 bits of virtual addressing, but we limit the address range
- // to (a) minimize segment lookaside buffer (SLB) misses; and (b) use
- // extra address space to isolate the mmap regions.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(30);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x400000000000ULL);
- }
-
- #elif defined(ARCH_CPU_BIG_ENDIAN)
-
- // Big-endian Linux PPC has 44 bits of virtual addressing. Use 42.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(42);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0);
- }
-
- #else // !defined(OS_AIX) && !defined(ARCH_CPU_BIG_ENDIAN)
-
- // Little-endian Linux PPC has 48 bits of virtual addressing. Use 46.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(46);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0);
- }
-
- #endif // !defined(OS_AIX) && !defined(ARCH_CPU_BIG_ENDIAN)
-
- #elif defined(ARCH_CPU_S390X)
-
- // Linux on Z uses bits 22 - 32 for Region Indexing, which translates to
- // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel a
- // chance to fulfill the request.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(40);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0);
- }
-
- #elif defined(ARCH_CPU_S390)
-
- // 31 bits of virtual addressing. Truncate to 29 bits to allow the kernel
- // a chance to fulfill the request.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(29);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0);
- }
-
- #else // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC64) &&
- // !defined(ARCH_CPU_S390X) && !defined(ARCH_CPU_S390)
-
- // For all other POSIX variants, use 30 bits.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(30);
- }
-
- #if defined(OS_SOLARIS)
-
- // For our Solaris/illumos mmap hint, we pick a random address in the
- // bottom half of the top half of the address space (that is, the third
- // quarter). Because we do not MAP_FIXED, this will be treated only as a
- // hint -- the system will not fail to mmap because something else
- // happens to already be mapped at our random address. We deliberately
- // set the hint high enough to get well above the system's break (that
- // is, the heap); Solaris and illumos will try the hint and if that
- // fails allocate as if there were no hint at all. The high hint
- // prevents the break from getting hemmed in at low values, ceding half
- // of the address space to the system heap.
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x80000000ULL);
- }
-
- #elif defined(OS_AIX)
-
- // The range 0x30000000 - 0xD0000000 is available on AIX; choose the
- // upper range.
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x90000000ULL);
- }
-
- #else // !defined(OS_SOLARIS) && !defined(OS_AIX)
-
- // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
- // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macOS
- // 10.6 and 10.7.
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x20000000ULL);
- }
-
- #endif // !defined(OS_SOLARIS) && !defined(OS_AIX)
-
- #endif // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC64) &&
- // !defined(ARCH_CPU_S390X) && !defined(ARCH_CPU_S390)
-
- #endif // BUILDFLAG(IS_POSIX)
-
-#elif defined(ARCH_CPU_32_BITS)
-
- // This is a good range on 32-bit Windows and Android (the only platforms on
- // which we support 32-bitness). Allocates in the 0.5 - 1.5 GiB region. There
- // is no issue with carries here.
- constexpr ALWAYS_INLINE uintptr_t ASLRMask() {
- return AslrMask(30);
- }
- constexpr ALWAYS_INLINE uintptr_t ASLROffset() {
- return AslrAddress(0x20000000ULL);
- }
-
-#else
-
- #error Please tell us about your exotic hardware! Sounds interesting.
-
-#endif // defined(ARCH_CPU_32_BITS)
-
-// clang-format on
-
-} // namespace internal
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_
diff --git a/third_party/base/allocator/partition_allocator/oom.h b/third_party/base/allocator/partition_allocator/oom.h
deleted file mode 100644
index f3d8974..0000000
--- a/third_party/base/allocator/partition_allocator/oom.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_H_
-
-#include "third_party/base/allocator/partition_allocator/oom_callback.h"
-#include "third_party/base/immediate_crash.h"
-
-#if BUILDFLAG(IS_WIN)
-#include <windows.h>
-#endif
-
-// Do not want trivial entry points just calling OOM_CRASH() to be
-// commoned up by linker icf/comdat folding.
-#define OOM_CRASH_PREVENT_ICF() \
- volatile int oom_crash_inhibit_icf = __LINE__; \
- ALLOW_UNUSED_LOCAL(oom_crash_inhibit_icf)
-
-// OOM_CRASH() - Specialization of IMMEDIATE_CRASH which will raise a custom
-// exception on Windows to signal this is OOM and not a normal assert.
-#if BUILDFLAG(IS_WIN)
-#define OOM_CRASH(size) \
- do { \
- OOM_CRASH_PREVENT_ICF(); \
- base::internal::RunPartitionAllocOomCallback(); \
- ::RaiseException(0xE0000008, EXCEPTION_NONCONTINUABLE, 0, nullptr); \
- IMMEDIATE_CRASH(); \
- } while (0)
-#else
-#define OOM_CRASH(size) \
- do { \
- base::internal::RunPartitionAllocOomCallback(); \
- OOM_CRASH_PREVENT_ICF(); \
- IMMEDIATE_CRASH(); \
- } while (0)
-#endif
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_H_
diff --git a/third_party/base/allocator/partition_allocator/oom_callback.cc b/third_party/base/allocator/partition_allocator/oom_callback.cc
deleted file mode 100644
index 0272f07..0000000
--- a/third_party/base/allocator/partition_allocator/oom_callback.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/oom_callback.h"
-
-#include "third_party/base/check.h"
-
-namespace pdfium {
-namespace base {
-
-namespace {
-PartitionAllocOomCallback g_oom_callback;
-} // namespace
-
-void SetPartitionAllocOomCallback(PartitionAllocOomCallback callback) {
- DCHECK(!g_oom_callback);
- g_oom_callback = callback;
-}
-
-namespace internal {
-void RunPartitionAllocOomCallback() {
- if (g_oom_callback)
- g_oom_callback();
-}
-} // namespace internal
-
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/oom_callback.h b/third_party/base/allocator/partition_allocator/oom_callback.h
deleted file mode 100644
index 044b167..0000000
--- a/third_party/base/allocator/partition_allocator/oom_callback.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_CALLBACK_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_CALLBACK_H_
-
-#include "third_party/base/base_export.h"
-
-namespace pdfium {
-namespace base {
-typedef void (*PartitionAllocOomCallback)();
-// Registers a callback to be invoked during an OOM_CRASH(). OOM_CRASH is
-// invoked by users of PageAllocator (including PartitionAlloc) to signify an
-// allocation failure from the platform.
-BASE_EXPORT void SetPartitionAllocOomCallback(
- PartitionAllocOomCallback callback);
-
-namespace internal {
-BASE_EXPORT void RunPartitionAllocOomCallback();
-} // namespace internal
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_CALLBACK_H_
diff --git a/third_party/base/allocator/partition_allocator/page_allocator.cc b/third_party/base/allocator/partition_allocator/page_allocator.cc
deleted file mode 100644
index 32094f9..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-
-#include <limits.h>
-
-#include <atomic>
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/address_space_randomization.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator_internal.h"
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-#include "third_party/base/bits.h"
-#include "third_party/base/check_op.h"
-#include "third_party/base/numerics/safe_math.h"
-
-#if BUILDFLAG(IS_WIN)
-#include <windows.h>
-#endif
-
-#if BUILDFLAG(IS_WIN)
-#include "third_party/base/allocator/partition_allocator/page_allocator_internals_win.h"
-#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-#include "third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h"
-#else
-#error Platform not supported.
-#endif
-
-namespace pdfium {
-namespace base {
-
-namespace {
-
-// We may reserve/release address space on different threads.
-subtle::SpinLock* GetReserveLock() {
- static subtle::SpinLock* s_reserveLock = nullptr;
- if (!s_reserveLock)
- s_reserveLock = new subtle::SpinLock();
- return s_reserveLock;
-}
-
-// We only support a single block of reserved address space.
-void* s_reservation_address = nullptr;
-size_t s_reservation_size = 0;
-
-void* AllocPagesIncludingReserved(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit) {
- void* ret =
- SystemAllocPages(address, length, accessibility, page_tag, commit);
- if (ret == nullptr) {
- const bool cant_alloc_length = kHintIsAdvisory || address == nullptr;
- if (cant_alloc_length) {
- // The system cannot allocate |length| bytes. Release any reserved address
- // space and try once more.
- ReleaseReservation();
- ret = SystemAllocPages(address, length, accessibility, page_tag, commit);
- }
- }
- return ret;
-}
-
-// Trims |base| to given |trim_length| and |alignment|.
-//
-// On failure, on Windows, this function returns nullptr and frees |base|.
-void* TrimMapping(void* base,
- size_t base_length,
- size_t trim_length,
- uintptr_t alignment,
- PageAccessibilityConfiguration accessibility,
- bool commit) {
- size_t pre_slack = reinterpret_cast<uintptr_t>(base) & (alignment - 1);
- if (pre_slack) {
- pre_slack = alignment - pre_slack;
- }
- size_t post_slack = base_length - pre_slack - trim_length;
- DCHECK(base_length >= trim_length || pre_slack || post_slack);
- DCHECK(pre_slack < base_length);
- DCHECK(post_slack < base_length);
- return TrimMappingInternal(base, base_length, trim_length, accessibility,
- commit, pre_slack, post_slack);
-}
-
-} // namespace
-
-void* SystemAllocPages(void* hint,
- size_t length,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit) {
- DCHECK(!(length & PageAllocationGranularityOffsetMask()));
- DCHECK(!(reinterpret_cast<uintptr_t>(hint) &
- PageAllocationGranularityOffsetMask()));
- DCHECK(commit || accessibility == PageInaccessible);
- return SystemAllocPagesInternal(hint, length, accessibility, page_tag,
- commit);
-}
-
-void* AllocPages(void* address,
- size_t length,
- size_t align,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit) {
- DCHECK(length >= PageAllocationGranularity());
- DCHECK(!(length & PageAllocationGranularityOffsetMask()));
- DCHECK(align >= PageAllocationGranularity());
- // Alignment must be power of 2 for masking math to work.
- DCHECK(pdfium::base::bits::IsPowerOfTwo(align));
- DCHECK(!(reinterpret_cast<uintptr_t>(address) &
- PageAllocationGranularityOffsetMask()));
- uintptr_t align_offset_mask = align - 1;
- uintptr_t align_base_mask = ~align_offset_mask;
- DCHECK(!(reinterpret_cast<uintptr_t>(address) & align_offset_mask));
-
- // If the client passed null as the address, choose a good one.
- if (address == nullptr) {
- address = GetRandomPageBase();
- address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) &
- align_base_mask);
- }
-
- // First try to force an exact-size, aligned allocation from our random base.
-#if defined(ARCH_CPU_32_BITS)
- // On 32 bit systems, first try one random aligned address, and then try an
- // aligned address derived from the value of |ret|.
- constexpr int kExactSizeTries = 2;
-#else
- // On 64 bit systems, try 3 random aligned addresses.
- constexpr int kExactSizeTries = 3;
-#endif
-
- for (int i = 0; i < kExactSizeTries; ++i) {
- void* ret = AllocPagesIncludingReserved(address, length, accessibility,
- page_tag, commit);
- if (ret != nullptr) {
- // If the alignment is to our liking, we're done.
- if (!(reinterpret_cast<uintptr_t>(ret) & align_offset_mask))
- return ret;
- // Free the memory and try again.
- FreePages(ret, length);
- } else {
- // |ret| is null; if this try was unhinted, we're OOM.
- if (kHintIsAdvisory || address == nullptr)
- return nullptr;
- }
-
-#if defined(ARCH_CPU_32_BITS)
- // For small address spaces, try the first aligned address >= |ret|. Note
- // |ret| may be null, in which case |address| becomes null.
- address = reinterpret_cast<void*>(
- (reinterpret_cast<uintptr_t>(ret) + align_offset_mask) &
- align_base_mask);
-#else // defined(ARCH_CPU_64_BITS)
- // Keep trying random addresses on systems that have a large address space.
- address = GetRandomPageBase();
- address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) &
- align_base_mask);
-#endif
- }
-
- // Make a larger allocation so we can force alignment.
- size_t try_length = length + (align - PageAllocationGranularity());
- CHECK(try_length >= length);
- void* ret;
-
- do {
- // Continue randomizing only on POSIX.
- address = kHintIsAdvisory ? GetRandomPageBase() : nullptr;
- ret = AllocPagesIncludingReserved(address, try_length, accessibility,
- page_tag, commit);
- // The retries are for Windows, where a race can steal our mapping on
- // resize.
- } while (ret != nullptr &&
- (ret = TrimMapping(ret, try_length, length, align, accessibility,
- commit)) == nullptr);
-
- return ret;
-}
-
-void FreePages(void* address, size_t length) {
- DCHECK(!(reinterpret_cast<uintptr_t>(address) &
- PageAllocationGranularityOffsetMask()));
- DCHECK(!(length & PageAllocationGranularityOffsetMask()));
- FreePagesInternal(address, length);
-}
-
-bool TrySetSystemPagesAccess(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- DCHECK(!(length & SystemPageOffsetMask()));
- return TrySetSystemPagesAccessInternal(address, length, accessibility);
-}
-
-void SetSystemPagesAccess(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- DCHECK(!(length & SystemPageOffsetMask()));
- SetSystemPagesAccessInternal(address, length, accessibility);
-}
-
-void DecommitSystemPages(void* address, size_t length) {
- DCHECK_EQ(0UL, length & SystemPageOffsetMask());
- DecommitSystemPagesInternal(address, length);
-}
-
-bool RecommitSystemPages(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- DCHECK_EQ(0UL, length & SystemPageOffsetMask());
- DCHECK(PageInaccessible != accessibility);
- return RecommitSystemPagesInternal(address, length, accessibility);
-}
-
-void DiscardSystemPages(void* address, size_t length) {
- DCHECK_EQ(0UL, length & SystemPageOffsetMask());
- DiscardSystemPagesInternal(address, length);
-}
-
-bool ReserveAddressSpace(size_t size) {
- // To avoid deadlock, call only SystemAllocPages.
- subtle::SpinLock::Guard guard(*GetReserveLock());
- if (s_reservation_address == nullptr) {
- void* mem = SystemAllocPages(nullptr, size, PageInaccessible,
- PageTag::kChromium, false);
- if (mem != nullptr) {
- // We guarantee this alignment when reserving address space.
- DCHECK(!(reinterpret_cast<uintptr_t>(mem) &
- PageAllocationGranularityOffsetMask()));
- s_reservation_address = mem;
- s_reservation_size = size;
- return true;
- }
- }
- return false;
-}
-
-bool ReleaseReservation() {
- // To avoid deadlock, call only FreePages.
- subtle::SpinLock::Guard guard(*GetReserveLock());
- if (!s_reservation_address)
- return false;
-
- FreePages(s_reservation_address, s_reservation_size);
- s_reservation_address = nullptr;
- s_reservation_size = 0;
- return true;
-}
-
-uint32_t GetAllocPageErrorCode() {
- return s_allocPageErrorCode;
-}
-
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/page_allocator.h b/third_party/base/allocator/partition_allocator/page_allocator.h
deleted file mode 100644
index bb3da8e..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
-
-#include <stdint.h>
-
-#include <cstddef>
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator_constants.h"
-#include "third_party/base/base_export.h"
-#include "third_party/base/compiler_specific.h"
-
-namespace pdfium {
-namespace base {
-
-enum PageAccessibilityConfiguration {
- PageInaccessible,
- PageRead,
- PageReadWrite,
- PageReadExecute,
- // This flag is deprecated and will go away soon.
- // TODO(bbudge) Remove this as soon as V8 doesn't need RWX pages.
- PageReadWriteExecute,
-};
-
-// macOS supports tagged memory regions, to help in debugging. On Android,
-// these tags are used to name anonymous mappings.
-enum class PageTag {
- kFirst = 240, // Minimum tag value.
- kBlinkGC = 252, // Blink GC pages.
- kPartitionAlloc = 253, // PartitionAlloc, no matter the partition.
- kChromium = 254, // Chromium page.
- kV8 = 255, // V8 heap pages.
- kLast = kV8 // Maximum tag value.
-};
-
-// Allocate one or more pages.
-//
-// The requested |address| is just a hint; the actual address returned may
-// differ. The returned address will be aligned at least to |align| bytes.
-// |length| is in bytes, and must be a multiple of
-// |PageAllocationGranularity()|. |align| is in bytes, and must be a
-// power-of-two multiple of |PageAllocationGranularity()|.
-//
-// If |address| is null, then a suitable and randomized address will be chosen
-// automatically.
-//
-// |page_accessibility| controls the permission of the allocated pages.
-// |page_tag| is used on some platforms to identify the source of the
-// allocation. Use PageTag::kChromium as a catch-all category.
-//
-// This call will return null if the allocation cannot be satisfied.
-BASE_EXPORT void* AllocPages(void* address,
- size_t length,
- size_t align,
- PageAccessibilityConfiguration page_accessibility,
- PageTag tag,
- bool commit = true);
-
-// Free one or more pages starting at |address| and continuing for |length|
-// bytes.
-//
-// |address| and |length| must match a previous call to |AllocPages|. Therefore,
-// |address| must be aligned to |PageAllocationGranularity()| bytes, and
-// |length| must be a multiple of |PageAllocationGranularity()|.
-BASE_EXPORT void FreePages(void* address, size_t length);
-
-// Mark one or more system pages, starting at |address| with the given
-// |page_accessibility|. |length| must be a multiple of |SystemPageSize()|
-// bytes.
-//
-// Returns true if the permission change succeeded. In most cases you must
-// |CHECK| the result.
-[[nodiscard]] BASE_EXPORT bool TrySetSystemPagesAccess(
- void* address,
- size_t length,
- PageAccessibilityConfiguration page_accessibility);
-
-// Mark one or more system pages, starting at |address| with the given
-// |page_accessibility|. |length| must be a multiple of |SystemPageSize()|
-// bytes.
-//
-// Performs a CHECK that the operation succeeds.
-BASE_EXPORT void SetSystemPagesAccess(
- void* address,
- size_t length,
- PageAccessibilityConfiguration page_accessibility);
-
-// Decommit one or more system pages starting at |address| and continuing for
-// |length| bytes. |length| must be a multiple of |SystemPageSize()|.
-//
-// Decommitted means that physical resources (RAM or swap) backing the allocated
-// virtual address range are released back to the system, but the address space
-// is still allocated to the process (possibly using up page table entries or
-// other accounting resources). Any access to a decommitted region of memory
-// is an error and will generate a fault.
-//
-// This operation is not atomic on all platforms.
-//
-// Note: "Committed memory" is a Windows Memory Subsystem concept that ensures
-// processes will not fault when touching a committed memory region. There is
-// no analogue in the POSIX memory API where virtual memory pages are
-// best-effort allocated resources on the first touch. To create a
-// platform-agnostic abstraction, this API simulates the Windows "decommit"
-// state by both discarding the region (allowing the OS to avoid swap
-// operations) and changing the page protections so accesses fault.
-//
-// TODO(ajwong): This currently does not change page protections on POSIX
-// systems due to a perf regression. Tracked at http://crbug.com/766882.
-BASE_EXPORT void DecommitSystemPages(void* address, size_t length);
-
-// Recommit one or more system pages, starting at |address| and continuing for
-// |length| bytes with the given |page_accessibility|. |length| must be a
-// multiple of |SystemPageSize()|.
-//
-// Decommitted system pages must be recommitted with their original permissions
-// before they are used again.
-//
-// Returns true if the recommit change succeeded. In most cases you must |CHECK|
-// the result.
-[[nodiscard]] BASE_EXPORT bool RecommitSystemPages(
- void* address,
- size_t length,
- PageAccessibilityConfiguration page_accessibility);
-
-// Discard one or more system pages starting at |address| and continuing for
-// |length| bytes. |length| must be a multiple of |SystemPageSize()|.
-//
-// Discarding is a hint to the system that the page is no longer required. The
-// hint may:
-// - Do nothing.
-// - Discard the page immediately, freeing up physical pages.
-// - Discard the page at some time in the future in response to memory
-// pressure.
-//
-// Only committed pages should be discarded. Discarding a page does not decommit
-// it, and it is valid to discard an already-discarded page. A read or write to
-// a discarded page will not fault.
-//
-// Reading from a discarded page may return the original page content, or a page
-// full of zeroes.
-//
-// Writing to a discarded page is the only guaranteed way to tell the system
-// that the page is required again. Once written to, the content of the page is
-// guaranteed stable once more. After being written to, the page content may be
-// based on the original page content, or a page of zeroes.
-BASE_EXPORT void DiscardSystemPages(void* address, size_t length);
-
-// Rounds up |address| to the next multiple of |SystemPageSize()|. Returns
-// 0 for an |address| of 0.
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-RoundUpToSystemPage(uintptr_t address) {
- return (address + SystemPageOffsetMask()) & SystemPageBaseMask();
-}
-
-// Rounds down |address| to the previous multiple of |SystemPageSize()|. Returns
-// 0 for an |address| of 0.
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-RoundDownToSystemPage(uintptr_t address) {
- return address & SystemPageBaseMask();
-}
-
-// Rounds up |address| to the next multiple of |PageAllocationGranularity()|.
-// Returns 0 for an |address| of 0.
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-RoundUpToPageAllocationGranularity(uintptr_t address) {
- return (address + PageAllocationGranularityOffsetMask()) &
- PageAllocationGranularityBaseMask();
-}
-
-// Rounds down |address| to the previous multiple of
-// |PageAllocationGranularity()|. Returns 0 for an |address| of 0.
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE uintptr_t
-RoundDownToPageAllocationGranularity(uintptr_t address) {
- return address & PageAllocationGranularityBaseMask();
-}
-
-// Reserves (at least) |size| bytes of address space, aligned to
-// |PageAllocationGranularity()|. This can be called early on to make it more
-// likely that large allocations will succeed. Returns true if the reservation
-// succeeded, false if the reservation failed or a reservation was already made.
-BASE_EXPORT bool ReserveAddressSpace(size_t size);
-
-// Releases any reserved address space. |AllocPages| calls this automatically on
-// an allocation failure. External allocators may also call this on failure.
-//
-// Returns true when an existing reservation was released.
-BASE_EXPORT bool ReleaseReservation();
-
-// Returns |errno| (POSIX) or the result of |GetLastError| (Windows) when |mmap|
-// (POSIX) or |VirtualAlloc| (Windows) fails.
-BASE_EXPORT uint32_t GetAllocPageErrorCode();
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
diff --git a/third_party/base/allocator/partition_allocator/page_allocator_constants.h b/third_party/base/allocator/partition_allocator/page_allocator_constants.h
deleted file mode 100644
index f13e518..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator_constants.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_
-
-#include <stddef.h>
-
-#include "build/build_config.h"
-#include "third_party/base/compiler_specific.h"
-
-#if BUILDFLAG(IS_APPLE)
-
-#include <mach/vm_page_size.h>
-
-// Although page allocator constants are not constexpr, they are run-time
-// constant. Because the underlying variables they access, such as vm_page_size,
-// are not marked const, the compiler normally has no way to know that they
-// don’t change and must obtain their values whenever it can't prove that they
-// haven't been modified, even if they had already been obtained previously.
-// Attaching __attribute__((const)) to these declarations allows these redundant
-// accesses to be omitted under optimization such as common subexpression
-// elimination.
-#define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR __attribute__((const))
-
-#else
-
-// When defined, page size constants are fixed at compile time. When not
-// defined, they may vary at run time.
-#define PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR 1
-
-// Use this macro to declare a function as constexpr or not based on whether
-// PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR is defined.
-#define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR constexpr
-
-#endif
-
-namespace pdfium {
-namespace {
-
-#if !BUILDFLAG(IS_APPLE)
-
-constexpr ALWAYS_INLINE int PageAllocationGranularityShift() {
-#if BUILDFLAG(IS_WIN) || defined(ARCH_CPU_PPC64)
- // Modern ppc64 systems support 4kB (shift = 12) and 64kB (shift = 16) page
- // sizes. Since 64kB is the de facto standard on the platform and binaries
- // compiled for 64kB are likely to work on 4kB systems, 64kB is a good choice
- // here.
- return 16; // 64kB
-#elif defined(_MIPS_ARCH_LOONGSON)
- return 14; // 16kB
-#else
- return 12; // 4kB
-#endif
-}
-
-#endif
-
-} // namespace
-
-namespace base {
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PageAllocationGranularity() {
-#if BUILDFLAG(IS_APPLE)
- return vm_page_size;
-#else
- return 1ULL << PageAllocationGranularityShift();
-#endif
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PageAllocationGranularityOffsetMask() {
- return PageAllocationGranularity() - 1;
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PageAllocationGranularityBaseMask() {
- return ~PageAllocationGranularityOffsetMask();
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-SystemPageSize() {
-#if BUILDFLAG(IS_WIN)
- return 4096;
-#else
- return PageAllocationGranularity();
-#endif
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-SystemPageOffsetMask() {
- return SystemPageSize() - 1;
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-SystemPageBaseMask() {
- return ~SystemPageOffsetMask();
-}
-
-static constexpr size_t kPageMetadataShift = 5; // 32 bytes per partition page.
-static constexpr size_t kPageMetadataSize = 1 << kPageMetadataShift;
-
-// See DecommitSystemPages(), this is not guaranteed to be synchronous on all
-// platforms.
-static constexpr bool kDecommittedPagesAreAlwaysZeroed =
-#if BUILDFLAG(IS_APPLE)
- false;
-#else
- true;
-#endif
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_
diff --git a/third_party/base/allocator/partition_allocator/page_allocator_internal.h b/third_party/base/allocator/partition_allocator/page_allocator_internal.h
deleted file mode 100644
index 2284314..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator_internal.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNAL_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNAL_H_
-
-namespace pdfium {
-namespace base {
-
-void* SystemAllocPages(void* hint,
- size_t length,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit);
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNAL_H_
diff --git a/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h b/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h
deleted file mode 100644
index 0e5e328..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_
-
-#include <errno.h>
-#include <sys/mman.h>
-
-#include "build/build_config.h"
-
-#if BUILDFLAG(IS_APPLE)
-#include <mach/mach.h>
-#endif
-#if BUILDFLAG(IS_ANDROID)
-#include <sys/prctl.h>
-#endif
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#include <sys/resource.h>
-
-#include <algorithm>
-#endif
-
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/check.h"
-#include "third_party/base/notreached.h"
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-namespace pdfium {
-namespace base {
-
-#if BUILDFLAG(IS_ANDROID)
-namespace {
-const char* PageTagToName(PageTag tag) {
- // Important: All the names should be string literals. As per prctl.h in
- // //third_party/android_ndk the kernel keeps a pointer to the name instead
- // of copying it.
- //
- // Having the name in .rodata ensures that the pointer remains valid as
- // long as the mapping is alive.
- switch (tag) {
- case PageTag::kBlinkGC:
- return "blink_gc";
- case PageTag::kPartitionAlloc:
- return "partition_alloc";
- case PageTag::kChromium:
- return "chromium";
- case PageTag::kV8:
- return "v8";
- default:
- DCHECK(false);
- return "";
- }
-}
-} // namespace
-#endif // BUILDFLAG(IS_ANDROID)
-
-// |mmap| uses a nearby address if the hint address is blocked.
-constexpr bool kHintIsAdvisory = true;
-std::atomic<int32_t> s_allocPageErrorCode{0};
-
-int GetAccessFlags(PageAccessibilityConfiguration accessibility) {
- switch (accessibility) {
- case PageRead:
- return PROT_READ;
- case PageReadWrite:
- return PROT_READ | PROT_WRITE;
- case PageReadExecute:
- return PROT_READ | PROT_EXEC;
- case PageReadWriteExecute:
- return PROT_READ | PROT_WRITE | PROT_EXEC;
- default:
- NOTREACHED();
- [[fallthrough]];
- case PageInaccessible:
- return PROT_NONE;
- }
-}
-
-void* SystemAllocPagesInternal(void* hint,
- size_t length,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit) {
-#if BUILDFLAG(IS_APPLE)
- // Use a custom tag to make it easier to distinguish Partition Alloc regions
- // in vmmap(1). Tags between 240-255 are supported.
- DCHECK(PageTag::kFirst <= page_tag);
- DCHECK(PageTag::kLast >= page_tag);
- int fd = VM_MAKE_TAG(static_cast<int>(page_tag));
-#else
- int fd = -1;
-#endif
-
- int access_flag = GetAccessFlags(accessibility);
- int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
-
- // TODO(https://crbug.com/927411): Remove once Fuchsia uses a native page
- // allocator, rather than relying on POSIX compatibility.
-#if BUILDFLAG(IS_FUCHSIA)
- if (page_tag == PageTag::kV8) {
- map_flags |= MAP_JIT;
- }
-#endif
-
- void* ret = mmap(hint, length, access_flag, map_flags, fd, 0);
- if (ret == MAP_FAILED) {
- s_allocPageErrorCode = errno;
- ret = nullptr;
- }
-
-#if BUILDFLAG(IS_ANDROID)
- // On Android, anonymous mappings can have a name attached to them. This is
- // useful for debugging, and double-checking memory attribution.
- if (ret) {
- // No error checking on purpose, testing only.
- prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ret, length,
- PageTagToName(page_tag));
- }
-#endif
-
- return ret;
-}
-
-void* TrimMappingInternal(void* base,
- size_t base_length,
- size_t trim_length,
- PageAccessibilityConfiguration accessibility,
- bool commit,
- size_t pre_slack,
- size_t post_slack) {
- void* ret = base;
- // We can resize the allocation run. Release unneeded memory before and after
- // the aligned range.
- if (pre_slack) {
- int res = munmap(base, pre_slack);
- CHECK(!res);
- ret = reinterpret_cast<char*>(base) + pre_slack;
- }
- if (post_slack) {
- int res = munmap(reinterpret_cast<char*>(ret) + trim_length, post_slack);
- CHECK(!res);
- }
- return ret;
-}
-
-bool TrySetSystemPagesAccessInternal(
- void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- return 0 == mprotect(address, length, GetAccessFlags(accessibility));
-}
-
-void SetSystemPagesAccessInternal(
- void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- CHECK_EQ(0, mprotect(address, length, GetAccessFlags(accessibility)));
-}
-
-void FreePagesInternal(void* address, size_t length) {
- CHECK(!munmap(address, length));
-}
-
-void DecommitSystemPagesInternal(void* address, size_t length) {
- // In POSIX, there is no decommit concept. Discarding is an effective way of
- // implementing the Windows semantics where the OS is allowed to not swap the
- // pages in the region.
- //
- // TODO(ajwong): Also explore setting PageInaccessible to make the protection
- // semantics consistent between Windows and POSIX. This might have a perf cost
- // though as both decommit and recommit would incur an extra syscall.
- // http://crbug.com/766882
- DiscardSystemPages(address, length);
-}
-
-bool RecommitSystemPagesInternal(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
-#if BUILDFLAG(IS_APPLE)
- // On macOS, to update accounting, we need to make another syscall. For more
- // details, see https://crbug.com/823915.
- madvise(address, length, MADV_FREE_REUSE);
-#endif
-
- // On POSIX systems, the caller need simply read the memory to recommit it.
- // This has the correct behavior because the API requires the permissions to
- // be the same as before decommitting and all configurations can read.
- return true;
-}
-
-void DiscardSystemPagesInternal(void* address, size_t length) {
-#if BUILDFLAG(IS_APPLE)
- int ret = madvise(address, length, MADV_FREE_REUSABLE);
- if (ret) {
- // MADV_FREE_REUSABLE sometimes fails, so fall back to MADV_DONTNEED.
- ret = madvise(address, length, MADV_DONTNEED);
- }
- CHECK(0 == ret);
-#else
- // We have experimented with other flags, but with suboptimal results.
- //
- // MADV_FREE (Linux): Makes our memory measurements less predictable;
- // performance benefits unclear.
- //
- // Therefore, we just do the simple thing: MADV_DONTNEED.
- CHECK(!madvise(address, length, MADV_DONTNEED));
-#endif
-}
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_
diff --git a/third_party/base/allocator/partition_allocator/page_allocator_internals_win.h b/third_party/base/allocator/partition_allocator/page_allocator_internals_win.h
deleted file mode 100644
index f3e698c..0000000
--- a/third_party/base/allocator/partition_allocator/page_allocator_internals_win.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
-
-#include "third_party/base/allocator/partition_allocator/oom.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator_internal.h"
-#include "third_party/base/check_op.h"
-#include "third_party/base/notreached.h"
-
-namespace pdfium {
-namespace base {
-
-// |VirtualAlloc| will fail if allocation at the hint address is blocked.
-constexpr bool kHintIsAdvisory = false;
-std::atomic<int32_t> s_allocPageErrorCode{ERROR_SUCCESS};
-
-int GetAccessFlags(PageAccessibilityConfiguration accessibility) {
- switch (accessibility) {
- case PageRead:
- return PAGE_READONLY;
- case PageReadWrite:
- return PAGE_READWRITE;
- case PageReadExecute:
- return PAGE_EXECUTE_READ;
- case PageReadWriteExecute:
- return PAGE_EXECUTE_READWRITE;
- default:
- NOTREACHED();
- [[fallthrough]];
- case PageInaccessible:
- return PAGE_NOACCESS;
- }
-}
-
-void* SystemAllocPagesInternal(void* hint,
- size_t length,
- PageAccessibilityConfiguration accessibility,
- PageTag page_tag,
- bool commit) {
- DWORD access_flag = GetAccessFlags(accessibility);
- const DWORD type_flags = commit ? (MEM_RESERVE | MEM_COMMIT) : MEM_RESERVE;
- void* ret = VirtualAlloc(hint, length, type_flags, access_flag);
- if (ret == nullptr) {
- s_allocPageErrorCode = GetLastError();
- }
- return ret;
-}
-
-void* TrimMappingInternal(void* base,
- size_t base_length,
- size_t trim_length,
- PageAccessibilityConfiguration accessibility,
- bool commit,
- size_t pre_slack,
- size_t post_slack) {
- void* ret = base;
- if (pre_slack || post_slack) {
- // We cannot resize the allocation run. Free it and retry at the aligned
- // address within the freed range.
- ret = reinterpret_cast<char*>(base) + pre_slack;
- FreePages(base, base_length);
- ret = SystemAllocPages(ret, trim_length, accessibility, PageTag::kChromium,
- commit);
- }
- return ret;
-}
-
-bool TrySetSystemPagesAccessInternal(
- void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- if (accessibility == PageInaccessible)
- return VirtualFree(address, length, MEM_DECOMMIT) != 0;
- return nullptr != VirtualAlloc(address, length, MEM_COMMIT,
- GetAccessFlags(accessibility));
-}
-
-void SetSystemPagesAccessInternal(
- void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- if (accessibility == PageInaccessible) {
- if (!VirtualFree(address, length, MEM_DECOMMIT)) {
- // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
- // report we get the error number.
- CHECK_EQ(static_cast<uint32_t>(ERROR_SUCCESS), GetLastError());
- }
- } else {
- if (!VirtualAlloc(address, length, MEM_COMMIT,
- GetAccessFlags(accessibility))) {
- int32_t error = GetLastError();
- if (error == ERROR_COMMITMENT_LIMIT)
- OOM_CRASH(length);
- // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
- // report we get the error number.
- CHECK_EQ(ERROR_SUCCESS, error);
- }
- }
-}
-
-void FreePagesInternal(void* address, size_t length) {
- CHECK(VirtualFree(address, 0, MEM_RELEASE));
-}
-
-void DecommitSystemPagesInternal(void* address, size_t length) {
- SetSystemPagesAccess(address, length, PageInaccessible);
-}
-
-bool RecommitSystemPagesInternal(void* address,
- size_t length,
- PageAccessibilityConfiguration accessibility) {
- return TrySetSystemPagesAccess(address, length, accessibility);
-}
-
-void DiscardSystemPagesInternal(void* address, size_t length) {
- // On Windows, discarded pages are not returned to the system immediately and
- // not guaranteed to be zeroed when returned to the application.
- using DiscardVirtualMemoryFunction =
- DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size);
- static DiscardVirtualMemoryFunction discard_virtual_memory =
- reinterpret_cast<DiscardVirtualMemoryFunction>(-1);
- if (discard_virtual_memory ==
- reinterpret_cast<DiscardVirtualMemoryFunction>(-1))
- discard_virtual_memory =
- reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress(
- GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
- // Use DiscardVirtualMemory when available because it releases faster than
- // MEM_RESET.
- DWORD ret = 1;
- if (discard_virtual_memory) {
- ret = discard_virtual_memory(address, length);
- }
- // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
- // failure.
- if (ret) {
- void* ptr = VirtualAlloc(address, length, MEM_RESET, PAGE_READWRITE);
- CHECK(ptr);
- }
-}
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_alloc.cc b/third_party/base/allocator/partition_allocator/partition_alloc.cc
deleted file mode 100644
index 6891275..0000000
--- a/third_party/base/allocator/partition_allocator/partition_alloc.cc
+++ /dev/null
@@ -1,865 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/partition_alloc.h"
-
-#include <string.h>
-
-#include <memory>
-#include <type_traits>
-
-#include "third_party/base/allocator/partition_allocator/partition_alloc_check.h"
-#include "third_party/base/allocator/partition_allocator/partition_direct_map_extent.h"
-#include "third_party/base/allocator/partition_allocator/partition_oom.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-
-namespace pdfium {
-namespace base {
-
-namespace {
-
-bool InitializeOnce() {
- // We mark the sentinel bucket/page as free to make sure it is skipped by our
- // logic to find a new active page.
- internal::PartitionBucket::get_sentinel_bucket()->active_pages_head =
- internal::PartitionPage::get_sentinel_page();
- return true;
-}
-
-} // namespace
-
-internal::PartitionRootBase::PartitionRootBase() = default;
-internal::PartitionRootBase::~PartitionRootBase() = default;
-PartitionRoot::PartitionRoot() = default;
-PartitionRoot::~PartitionRoot() = default;
-PartitionRootGeneric::PartitionRootGeneric() = default;
-PartitionRootGeneric::~PartitionRootGeneric() = default;
-PartitionAllocatorGeneric::PartitionAllocatorGeneric() = default;
-PartitionAllocatorGeneric::~PartitionAllocatorGeneric() = default;
-
-subtle::SpinLock* GetLock() {
- static subtle::SpinLock* s_initialized_lock = nullptr;
- if (!s_initialized_lock)
- s_initialized_lock = new subtle::SpinLock();
- return s_initialized_lock;
-}
-
-OomFunction internal::PartitionRootBase::g_oom_handling_function = nullptr;
-std::atomic<bool> PartitionAllocHooks::hooks_enabled_(false);
-subtle::SpinLock PartitionAllocHooks::set_hooks_lock_;
-std::atomic<PartitionAllocHooks::AllocationObserverHook*>
- PartitionAllocHooks::allocation_observer_hook_(nullptr);
-std::atomic<PartitionAllocHooks::FreeObserverHook*>
- PartitionAllocHooks::free_observer_hook_(nullptr);
-std::atomic<PartitionAllocHooks::AllocationOverrideHook*>
- PartitionAllocHooks::allocation_override_hook_(nullptr);
-std::atomic<PartitionAllocHooks::FreeOverrideHook*>
- PartitionAllocHooks::free_override_hook_(nullptr);
-std::atomic<PartitionAllocHooks::ReallocOverrideHook*>
- PartitionAllocHooks::realloc_override_hook_(nullptr);
-
-void PartitionAllocHooks::SetObserverHooks(AllocationObserverHook* alloc_hook,
- FreeObserverHook* free_hook) {
- subtle::SpinLock::Guard guard(set_hooks_lock_);
-
- // Chained hooks are not supported. Registering a non-null hook when a
- // non-null hook is already registered indicates somebody is trying to
- // overwrite a hook.
- CHECK((!allocation_observer_hook_ && !free_observer_hook_) ||
- (!alloc_hook && !free_hook));
- allocation_observer_hook_ = alloc_hook;
- free_observer_hook_ = free_hook;
-
- hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
-}
-
-void PartitionAllocHooks::SetOverrideHooks(AllocationOverrideHook* alloc_hook,
- FreeOverrideHook* free_hook,
- ReallocOverrideHook realloc_hook) {
- subtle::SpinLock::Guard guard(set_hooks_lock_);
-
- CHECK((!allocation_override_hook_ && !free_override_hook_ &&
- !realloc_override_hook_) ||
- (!alloc_hook && !free_hook && !realloc_hook));
- allocation_override_hook_ = alloc_hook;
- free_override_hook_ = free_hook;
- realloc_override_hook_ = realloc_hook;
-
- hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
-}
-
-void PartitionAllocHooks::AllocationObserverHookIfEnabled(
- void* address,
- size_t size,
- const char* type_name) {
- if (AllocationObserverHook* hook =
- allocation_observer_hook_.load(std::memory_order_relaxed)) {
- hook(address, size, type_name);
- }
-}
-
-bool PartitionAllocHooks::AllocationOverrideHookIfEnabled(
- void** out,
- int flags,
- size_t size,
- const char* type_name) {
- if (AllocationOverrideHook* hook =
- allocation_override_hook_.load(std::memory_order_relaxed)) {
- return hook(out, flags, size, type_name);
- }
- return false;
-}
-
-void PartitionAllocHooks::FreeObserverHookIfEnabled(void* address) {
- if (FreeObserverHook* hook =
- free_observer_hook_.load(std::memory_order_relaxed)) {
- hook(address);
- }
-}
-
-bool PartitionAllocHooks::FreeOverrideHookIfEnabled(void* address) {
- if (FreeOverrideHook* hook =
- free_override_hook_.load(std::memory_order_relaxed)) {
- return hook(address);
- }
- return false;
-}
-
-void PartitionAllocHooks::ReallocObserverHookIfEnabled(void* old_address,
- void* new_address,
- size_t size,
- const char* type_name) {
- // Report a reallocation as a free followed by an allocation.
- AllocationObserverHook* allocation_hook =
- allocation_observer_hook_.load(std::memory_order_relaxed);
- FreeObserverHook* free_hook =
- free_observer_hook_.load(std::memory_order_relaxed);
- if (allocation_hook && free_hook) {
- free_hook(old_address);
- allocation_hook(new_address, size, type_name);
- }
-}
-bool PartitionAllocHooks::ReallocOverrideHookIfEnabled(size_t* out,
- void* address) {
- if (ReallocOverrideHook* hook =
- realloc_override_hook_.load(std::memory_order_relaxed)) {
- return hook(out, address);
- }
- return false;
-}
-
-static void PartitionAllocBaseInit(internal::PartitionRootBase* root) {
- DCHECK(!root->initialized);
- static bool initialized = InitializeOnce();
- static_cast<void>(initialized);
-
- // This is a "magic" value so we can test if a root pointer is valid.
- root->inverted_self = ~reinterpret_cast<uintptr_t>(root);
- root->initialized = true;
-}
-
-void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
- // Two partition pages are used as guard / metadata page so make sure the
- // super page size is bigger.
- STATIC_ASSERT_OR_CHECK(PartitionPageSize() * 4 <= kSuperPageSize,
- "ok super page size");
- STATIC_ASSERT_OR_CHECK(!(kSuperPageSize % PartitionPageSize()),
- "ok super page multiple");
- // Four system pages gives us room to hack out a still-guard-paged piece
- // of metadata in the middle of a guard partition page.
- STATIC_ASSERT_OR_CHECK(SystemPageSize() * 4 <= PartitionPageSize(),
- "ok partition page size");
- STATIC_ASSERT_OR_CHECK(!(PartitionPageSize() % SystemPageSize()),
- "ok partition page multiple");
- static_assert(sizeof(internal::PartitionPage) <= kPageMetadataSize,
- "PartitionPage should not be too big");
- static_assert(sizeof(internal::PartitionBucket) <= kPageMetadataSize,
- "PartitionBucket should not be too big");
- static_assert(
- sizeof(internal::PartitionSuperPageExtentEntry) <= kPageMetadataSize,
- "PartitionSuperPageExtentEntry should not be too big");
- STATIC_ASSERT_OR_CHECK(
- kPageMetadataSize * NumPartitionPagesPerSuperPage() <= SystemPageSize(),
- "page metadata fits in hole");
- // Limit to prevent callers accidentally overflowing an int size.
- STATIC_ASSERT_OR_CHECK(
- GenericMaxDirectMapped() <= (1UL << 31) + PageAllocationGranularity(),
- "maximum direct mapped allocation");
- // Check that some of our zanier calculations worked out as expected.
- static_assert(kGenericSmallestBucket == 8, "generic smallest bucket");
- static_assert(kGenericMaxBucketed == 983040, "generic max bucketed");
- STATIC_ASSERT_OR_CHECK(MaxSystemPagesPerSlotSpan() < (1 << 8),
- "System pages per slot span must be less than 128.");
-
- DCHECK(on_out_of_memory);
- internal::PartitionRootBase::g_oom_handling_function = on_out_of_memory;
-}
-
-void PartitionRoot::Init(size_t bucket_count, size_t maximum_allocation) {
- PartitionAllocBaseInit(this);
-
- num_buckets = bucket_count;
- max_allocation = maximum_allocation;
- for (size_t i = 0; i < num_buckets; ++i) {
- internal::PartitionBucket& bucket = buckets()[i];
- bucket.Init(i == 0 ? kAllocationGranularity : (i << kBucketShift));
- }
-}
-
-void PartitionRootGeneric::Init() {
- subtle::SpinLock::Guard guard(lock);
-
- PartitionAllocBaseInit(this);
-
- // Precalculate some shift and mask constants used in the hot path.
- // Example: malloc(41) == 101001 binary.
- // Order is 6 (1 << 6-1) == 32 is highest bit set.
- // order_index is the next three MSB == 010 == 2.
- // sub_order_index_mask is a mask for the remaining bits == 11 (masking to 01
- // for
- // the sub_order_index).
- size_t order;
- for (order = 0; order <= kBitsPerSizeT; ++order) {
- size_t order_index_shift;
- if (order < kGenericNumBucketsPerOrderBits + 1)
- order_index_shift = 0;
- else
- order_index_shift = order - (kGenericNumBucketsPerOrderBits + 1);
- order_index_shifts[order] = order_index_shift;
- size_t sub_order_index_mask;
- if (order == kBitsPerSizeT) {
- // This avoids invoking undefined behavior for an excessive shift.
- sub_order_index_mask =
- static_cast<size_t>(-1) >> (kGenericNumBucketsPerOrderBits + 1);
- } else {
- sub_order_index_mask = ((static_cast<size_t>(1) << order) - 1) >>
- (kGenericNumBucketsPerOrderBits + 1);
- }
- order_sub_index_masks[order] = sub_order_index_mask;
- }
-
- // Set up the actual usable buckets first.
- // Note that typical values (i.e. min allocation size of 8) will result in
- // pseudo buckets (size==9 etc. or more generally, size is not a multiple
- // of the smallest allocation granularity).
- // We avoid them in the bucket lookup map, but we tolerate them to keep the
- // code simpler and the structures more generic.
- size_t i, j;
- size_t current_size = kGenericSmallestBucket;
- size_t current_increment =
- kGenericSmallestBucket >> kGenericNumBucketsPerOrderBits;
- internal::PartitionBucket* bucket = &buckets[0];
- for (i = 0; i < kGenericNumBucketedOrders; ++i) {
- for (j = 0; j < kGenericNumBucketsPerOrder; ++j) {
- bucket->Init(current_size);
- // Disable psuedo buckets so that touching them faults.
- if (current_size % kGenericSmallestBucket)
- bucket->active_pages_head = nullptr;
- current_size += current_increment;
- ++bucket;
- }
- current_increment <<= 1;
- }
- DCHECK(current_size == 1 << kGenericMaxBucketedOrder);
- DCHECK(bucket == &buckets[0] + kGenericNumBuckets);
-
- // Then set up the fast size -> bucket lookup table.
- bucket = &buckets[0];
- internal::PartitionBucket** bucket_ptr = &bucket_lookups[0];
- for (order = 0; order <= kBitsPerSizeT; ++order) {
- for (j = 0; j < kGenericNumBucketsPerOrder; ++j) {
- if (order < kGenericMinBucketedOrder) {
- // Use the bucket of the finest granularity for malloc(0) etc.
- *bucket_ptr++ = &buckets[0];
- } else if (order > kGenericMaxBucketedOrder) {
- *bucket_ptr++ = internal::PartitionBucket::get_sentinel_bucket();
- } else {
- internal::PartitionBucket* valid_bucket = bucket;
- // Skip over invalid buckets.
- while (valid_bucket->slot_size % kGenericSmallestBucket)
- valid_bucket++;
- *bucket_ptr++ = valid_bucket;
- bucket++;
- }
- }
- }
- DCHECK(bucket == &buckets[0] + kGenericNumBuckets);
- DCHECK(bucket_ptr == &bucket_lookups[0] +
- ((kBitsPerSizeT + 1) * kGenericNumBucketsPerOrder));
- // And there's one last bucket lookup that will be hit for e.g. malloc(-1),
- // which tries to overflow to a non-existant order.
- *bucket_ptr = internal::PartitionBucket::get_sentinel_bucket();
-}
-
-bool PartitionReallocDirectMappedInPlace(PartitionRootGeneric* root,
- internal::PartitionPage* page,
- size_t raw_size) {
- DCHECK(page->bucket->is_direct_mapped());
-
- raw_size = internal::PartitionCookieSizeAdjustAdd(raw_size);
-
- // Note that the new size might be a bucketed size; this function is called
- // whenever we're reallocating a direct mapped allocation.
- size_t new_size = internal::PartitionBucket::get_direct_map_size(raw_size);
- if (new_size < kGenericMinDirectMappedDownsize)
- return false;
-
- // bucket->slot_size is the current size of the allocation.
- size_t current_size = page->bucket->slot_size;
- char* char_ptr = static_cast<char*>(internal::PartitionPage::ToPointer(page));
- if (new_size == current_size) {
- // No need to move any memory around, but update size and cookie below.
- } else if (new_size < current_size) {
- size_t map_size =
- internal::PartitionDirectMapExtent::FromPage(page)->map_size;
-
- // Don't reallocate in-place if new size is less than 80 % of the full
- // map size, to avoid holding on to too much unused address space.
- if ((new_size / SystemPageSize()) * 5 < (map_size / SystemPageSize()) * 4)
- return false;
-
- // Shrink by decommitting unneeded pages and making them inaccessible.
- size_t decommit_size = current_size - new_size;
- root->DecommitSystemPages(char_ptr + new_size, decommit_size);
- SetSystemPagesAccess(char_ptr + new_size, decommit_size, PageInaccessible);
- } else if (new_size <=
- internal::PartitionDirectMapExtent::FromPage(page)->map_size) {
- // Grow within the actually allocated memory. Just need to make the
- // pages accessible again.
- size_t recommit_size = new_size - current_size;
- SetSystemPagesAccess(char_ptr + current_size, recommit_size, PageReadWrite);
- root->RecommitSystemPages(char_ptr + current_size, recommit_size);
-
-#if DCHECK_IS_ON()
- memset(char_ptr + current_size, kUninitializedByte, recommit_size);
-#endif
- } else {
- // We can't perform the realloc in-place.
- // TODO: support this too when possible.
- return false;
- }
-
-#if DCHECK_IS_ON()
- // Write a new trailing cookie.
- internal::PartitionCookieWriteValue(char_ptr + raw_size -
- internal::kCookieSize);
-#endif
-
- page->set_raw_size(raw_size);
- DCHECK(page->get_raw_size() == raw_size);
-
- page->bucket->slot_size = new_size;
- return true;
-}
-
-void* PartitionReallocGenericFlags(PartitionRootGeneric* root,
- int flags,
- void* ptr,
- size_t new_size,
- const char* type_name) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- CHECK_MAX_SIZE_OR_RETURN_NULLPTR(new_size, flags);
- void* result = realloc(ptr, new_size);
- CHECK(result || flags & PartitionAllocReturnNull);
- return result;
-#else
- if (UNLIKELY(!ptr))
- return PartitionAllocGenericFlags(root, flags, new_size, type_name);
- if (UNLIKELY(!new_size)) {
- root->Free(ptr);
- return nullptr;
- }
-
- if (new_size > GenericMaxDirectMapped()) {
- if (flags & PartitionAllocReturnNull)
- return nullptr;
- internal::PartitionExcessiveAllocationSize(new_size);
- }
-
- const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
- bool overridden = false;
- size_t actual_old_size;
- if (UNLIKELY(hooks_enabled)) {
- overridden = PartitionAllocHooks::ReallocOverrideHookIfEnabled(
- &actual_old_size, ptr);
- }
- if (LIKELY(!overridden)) {
- internal::PartitionPage* page = internal::PartitionPage::FromPointer(
- internal::PartitionCookieFreePointerAdjust(ptr));
- bool success = false;
- {
- subtle::SpinLock::Guard guard{root->lock};
- // TODO(palmer): See if we can afford to make this a CHECK.
- DCHECK(root->IsValidPage(page));
-
- if (UNLIKELY(page->bucket->is_direct_mapped())) {
- // We may be able to perform the realloc in place by changing the
- // accessibility of memory pages and, if reducing the size, decommitting
- // them.
- success = PartitionReallocDirectMappedInPlace(root, page, new_size);
- }
- }
- if (success) {
- if (UNLIKELY(hooks_enabled)) {
- PartitionAllocHooks::ReallocObserverHookIfEnabled(ptr, ptr, new_size,
- type_name);
- }
- return ptr;
- }
-
- const size_t actual_new_size = root->ActualSize(new_size);
- actual_old_size = PartitionAllocGetSize(ptr);
-
- // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the
- // new size is a significant percentage smaller. We could do the same if we
- // determine it is a win.
- if (actual_new_size == actual_old_size) {
- // Trying to allocate a block of size |new_size| would give us a block of
- // the same size as the one we've already got, so re-use the allocation
- // after updating statistics (and cookies, if present).
- page->set_raw_size(internal::PartitionCookieSizeAdjustAdd(new_size));
-#if DCHECK_IS_ON()
- // Write a new trailing cookie when it is possible to keep track of
- // |new_size| via the raw size pointer.
- if (page->get_raw_size_ptr())
- internal::PartitionCookieWriteValue(static_cast<char*>(ptr) + new_size);
-#endif
- return ptr;
- }
- }
-
- // This realloc cannot be resized in-place. Sadness.
- void* ret = PartitionAllocGenericFlags(root, flags, new_size, type_name);
- if (!ret) {
- if (flags & PartitionAllocReturnNull)
- return nullptr;
- internal::PartitionExcessiveAllocationSize(new_size);
- }
-
- size_t copy_size = actual_old_size;
- if (new_size < copy_size)
- copy_size = new_size;
-
- memcpy(ret, ptr, copy_size);
- root->Free(ptr);
- return ret;
-#endif
-}
-
-void* PartitionRootGeneric::Realloc(void* ptr,
- size_t new_size,
- const char* type_name) {
- return PartitionReallocGenericFlags(this, 0, ptr, new_size, type_name);
-}
-
-void* PartitionRootGeneric::TryRealloc(void* ptr,
- size_t new_size,
- const char* type_name) {
- return PartitionReallocGenericFlags(this, PartitionAllocReturnNull, ptr,
- new_size, type_name);
-}
-
-static size_t PartitionPurgePage(internal::PartitionPage* page, bool discard) {
- const internal::PartitionBucket* bucket = page->bucket;
- size_t slot_size = bucket->slot_size;
- if (slot_size < SystemPageSize() || !page->num_allocated_slots)
- return 0;
-
- size_t bucket_num_slots = bucket->get_slots_per_span();
- size_t discardable_bytes = 0;
-
- size_t raw_size = page->get_raw_size();
- if (raw_size) {
- uint32_t used_bytes = static_cast<uint32_t>(RoundUpToSystemPage(raw_size));
- discardable_bytes = bucket->slot_size - used_bytes;
- if (discardable_bytes && discard) {
- char* ptr =
- reinterpret_cast<char*>(internal::PartitionPage::ToPointer(page));
- ptr += used_bytes;
- DiscardSystemPages(ptr, discardable_bytes);
- }
- return discardable_bytes;
- }
-
-#if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR)
- constexpr size_t kMaxSlotCount =
- (PartitionPageSize() * kMaxPartitionPagesPerSlotSpan) / SystemPageSize();
-#elif BUILDFLAG(IS_APPLE)
- // It's better for slot_usage to be stack-allocated and fixed-size, which
- // demands that its size be constexpr. On OS_APPLE, PartitionPageSize() is
- // always SystemPageSize() << 2, so regardless of what the run time page size
- // is, kMaxSlotCount can always be simplified to this expression.
- constexpr size_t kMaxSlotCount = 4 * kMaxPartitionPagesPerSlotSpan;
- CHECK(kMaxSlotCount == (PartitionPageSize() * kMaxPartitionPagesPerSlotSpan) /
- SystemPageSize());
-#endif
- DCHECK(bucket_num_slots <= kMaxSlotCount);
- DCHECK(page->num_unprovisioned_slots < bucket_num_slots);
- size_t num_slots = bucket_num_slots - page->num_unprovisioned_slots;
- char slot_usage[kMaxSlotCount];
-#if !BUILDFLAG(IS_WIN)
- // The last freelist entry should not be discarded when using OS_WIN.
- // DiscardVirtualMemory makes the contents of discarded memory undefined.
- size_t last_slot = static_cast<size_t>(-1);
-#endif
- memset(slot_usage, 1, num_slots);
- char* ptr = reinterpret_cast<char*>(internal::PartitionPage::ToPointer(page));
- // First, walk the freelist for this page and make a bitmap of which slots
- // are not in use.
- for (internal::PartitionFreelistEntry* entry = page->freelist_head; entry;
- /**/) {
- size_t slot_index = (reinterpret_cast<char*>(entry) - ptr) / slot_size;
- DCHECK(slot_index < num_slots);
- slot_usage[slot_index] = 0;
- entry = internal::EncodedPartitionFreelistEntry::Decode(entry->next);
-#if !BUILDFLAG(IS_WIN)
- // If we have a slot where the masked freelist entry is 0, we can actually
- // discard that freelist entry because touching a discarded page is
- // guaranteed to return original content or 0. (Note that this optimization
- // won't fire on big-endian machines because the masking function is
- // negation.)
- if (!internal::PartitionFreelistEntry::Encode(entry))
- last_slot = slot_index;
-#endif
- }
-
- // If the slot(s) at the end of the slot span are not in used, we can truncate
- // them entirely and rewrite the freelist.
- size_t truncated_slots = 0;
- while (!slot_usage[num_slots - 1]) {
- truncated_slots++;
- num_slots--;
- DCHECK(num_slots);
- }
- // First, do the work of calculating the discardable bytes. Don't actually
- // discard anything unless the discard flag was passed in.
- if (truncated_slots) {
- size_t unprovisioned_bytes = 0;
- char* begin_ptr = ptr + (num_slots * slot_size);
- char* end_ptr = begin_ptr + (slot_size * truncated_slots);
- begin_ptr = reinterpret_cast<char*>(
- RoundUpToSystemPage(reinterpret_cast<size_t>(begin_ptr)));
- // We round the end pointer here up and not down because we're at the end of
- // a slot span, so we "own" all the way up the page boundary.
- end_ptr = reinterpret_cast<char*>(
- RoundUpToSystemPage(reinterpret_cast<size_t>(end_ptr)));
- DCHECK(end_ptr <= ptr + bucket->get_bytes_per_span());
- if (begin_ptr < end_ptr) {
- unprovisioned_bytes = end_ptr - begin_ptr;
- discardable_bytes += unprovisioned_bytes;
- }
- if (unprovisioned_bytes && discard) {
- DCHECK(truncated_slots > 0);
- size_t num_new_entries = 0;
- page->num_unprovisioned_slots += static_cast<uint16_t>(truncated_slots);
-
- // Rewrite the freelist.
- internal::PartitionFreelistEntry* head = nullptr;
- internal::PartitionFreelistEntry* back = head;
- for (size_t slot_index = 0; slot_index < num_slots; ++slot_index) {
- if (slot_usage[slot_index])
- continue;
-
- auto* entry = reinterpret_cast<internal::PartitionFreelistEntry*>(
- ptr + (slot_size * slot_index));
- if (!head) {
- head = entry;
- back = entry;
- } else {
- back->next = internal::PartitionFreelistEntry::Encode(entry);
- back = entry;
- }
- num_new_entries++;
-#if !BUILDFLAG(IS_WIN)
- last_slot = slot_index;
-#endif
- }
-
- page->freelist_head = head;
- if (back)
- back->next = internal::PartitionFreelistEntry::Encode(nullptr);
-
- DCHECK(num_new_entries == num_slots - page->num_allocated_slots);
- // Discard the memory.
- DiscardSystemPages(begin_ptr, unprovisioned_bytes);
- }
- }
-
- // Next, walk the slots and for any not in use, consider where the system page
- // boundaries occur. We can release any system pages back to the system as
- // long as we don't interfere with a freelist pointer or an adjacent slot.
- for (size_t i = 0; i < num_slots; ++i) {
- if (slot_usage[i])
- continue;
- // The first address we can safely discard is just after the freelist
- // pointer. There's one quirk: if the freelist pointer is actually NULL, we
- // can discard that pointer value too.
- char* begin_ptr = ptr + (i * slot_size);
- char* end_ptr = begin_ptr + slot_size;
-#if !BUILDFLAG(IS_WIN)
- if (i != last_slot)
- begin_ptr += sizeof(internal::PartitionFreelistEntry);
-#else
- begin_ptr += sizeof(internal::PartitionFreelistEntry);
-#endif
- begin_ptr = reinterpret_cast<char*>(
- RoundUpToSystemPage(reinterpret_cast<size_t>(begin_ptr)));
- end_ptr = reinterpret_cast<char*>(
- RoundDownToSystemPage(reinterpret_cast<size_t>(end_ptr)));
- if (begin_ptr < end_ptr) {
- size_t partial_slot_bytes = end_ptr - begin_ptr;
- discardable_bytes += partial_slot_bytes;
- if (discard)
- DiscardSystemPages(begin_ptr, partial_slot_bytes);
- }
- }
- return discardable_bytes;
-}
-
-static void PartitionPurgeBucket(internal::PartitionBucket* bucket) {
- if (bucket->active_pages_head !=
- internal::PartitionPage::get_sentinel_page()) {
- for (internal::PartitionPage* page = bucket->active_pages_head; page;
- page = page->next_page) {
- DCHECK(page != internal::PartitionPage::get_sentinel_page());
- PartitionPurgePage(page, true);
- }
- }
-}
-
-void PartitionRoot::PurgeMemory(int flags) {
- if (flags & PartitionPurgeDecommitEmptyPages)
- DecommitEmptyPages();
- // We don't currently do anything for PartitionPurgeDiscardUnusedSystemPages
- // here because that flag is only useful for allocations >= system page size.
- // We only have allocations that large inside generic partitions at the
- // moment.
-}
-
-void PartitionRootGeneric::PurgeMemory(int flags) {
- subtle::SpinLock::Guard guard(lock);
- if (flags & PartitionPurgeDecommitEmptyPages)
- DecommitEmptyPages();
- if (flags & PartitionPurgeDiscardUnusedSystemPages) {
- for (size_t i = 0; i < kGenericNumBuckets; ++i) {
- internal::PartitionBucket* bucket = &buckets[i];
- if (bucket->slot_size >= SystemPageSize())
- PartitionPurgeBucket(bucket);
- }
- }
-}
-
-static void PartitionDumpPageStats(PartitionBucketMemoryStats* stats_out,
- internal::PartitionPage* page) {
- uint16_t bucket_num_slots = page->bucket->get_slots_per_span();
-
- if (page->is_decommitted()) {
- ++stats_out->num_decommitted_pages;
- return;
- }
-
- stats_out->discardable_bytes += PartitionPurgePage(page, false);
-
- size_t raw_size = page->get_raw_size();
- if (raw_size) {
- stats_out->active_bytes += static_cast<uint32_t>(raw_size);
- } else {
- stats_out->active_bytes +=
- (page->num_allocated_slots * stats_out->bucket_slot_size);
- }
-
- size_t page_bytes_resident =
- RoundUpToSystemPage((bucket_num_slots - page->num_unprovisioned_slots) *
- stats_out->bucket_slot_size);
- stats_out->resident_bytes += page_bytes_resident;
- if (page->is_empty()) {
- stats_out->decommittable_bytes += page_bytes_resident;
- ++stats_out->num_empty_pages;
- } else if (page->is_full()) {
- ++stats_out->num_full_pages;
- } else {
- DCHECK(page->is_active());
- ++stats_out->num_active_pages;
- }
-}
-
-static void PartitionDumpBucketStats(PartitionBucketMemoryStats* stats_out,
- const internal::PartitionBucket* bucket) {
- DCHECK(!bucket->is_direct_mapped());
- stats_out->is_valid = false;
- // If the active page list is empty (==
- // internal::PartitionPage::get_sentinel_page()), the bucket might still need
- // to be reported if it has a list of empty, decommitted or full pages.
- if (bucket->active_pages_head ==
- internal::PartitionPage::get_sentinel_page() &&
- !bucket->empty_pages_head && !bucket->decommitted_pages_head &&
- !bucket->num_full_pages)
- return;
-
- memset(stats_out, '\0', sizeof(*stats_out));
- stats_out->is_valid = true;
- stats_out->is_direct_map = false;
- stats_out->num_full_pages = static_cast<size_t>(bucket->num_full_pages);
- stats_out->bucket_slot_size = bucket->slot_size;
- uint16_t bucket_num_slots = bucket->get_slots_per_span();
- size_t bucket_useful_storage = stats_out->bucket_slot_size * bucket_num_slots;
- stats_out->allocated_page_size = bucket->get_bytes_per_span();
- stats_out->active_bytes = bucket->num_full_pages * bucket_useful_storage;
- stats_out->resident_bytes =
- bucket->num_full_pages * stats_out->allocated_page_size;
-
- for (internal::PartitionPage* page = bucket->empty_pages_head; page;
- page = page->next_page) {
- DCHECK(page->is_empty() || page->is_decommitted());
- PartitionDumpPageStats(stats_out, page);
- }
- for (internal::PartitionPage* page = bucket->decommitted_pages_head; page;
- page = page->next_page) {
- DCHECK(page->is_decommitted());
- PartitionDumpPageStats(stats_out, page);
- }
-
- if (bucket->active_pages_head !=
- internal::PartitionPage::get_sentinel_page()) {
- for (internal::PartitionPage* page = bucket->active_pages_head; page;
- page = page->next_page) {
- DCHECK(page != internal::PartitionPage::get_sentinel_page());
- PartitionDumpPageStats(stats_out, page);
- }
- }
-}
-
-void PartitionRootGeneric::DumpStats(const char* partition_name,
- bool is_light_dump,
- PartitionStatsDumper* dumper) {
- PartitionMemoryStats stats = {0};
- stats.total_mmapped_bytes =
- total_size_of_super_pages + total_size_of_direct_mapped_pages;
- stats.total_committed_bytes = total_size_of_committed_pages;
-
- size_t direct_mapped_allocations_total_size = 0;
-
- static const size_t kMaxReportableDirectMaps = 4096;
-
- // Allocate on the heap rather than on the stack to avoid stack overflow
- // skirmishes (on Windows, in particular).
- std::unique_ptr<uint32_t[]> direct_map_lengths = nullptr;
- if (!is_light_dump) {
- direct_map_lengths =
- std::unique_ptr<uint32_t[]>(new uint32_t[kMaxReportableDirectMaps]);
- }
-
- PartitionBucketMemoryStats bucket_stats[kGenericNumBuckets];
- size_t num_direct_mapped_allocations = 0;
- {
- subtle::SpinLock::Guard guard(lock);
-
- for (size_t i = 0; i < kGenericNumBuckets; ++i) {
- const internal::PartitionBucket* bucket = &buckets[i];
- // Don't report the pseudo buckets that the generic allocator sets up in
- // order to preserve a fast size->bucket map (see
- // PartitionRootGeneric::Init() for details).
- if (!bucket->active_pages_head)
- bucket_stats[i].is_valid = false;
- else
- PartitionDumpBucketStats(&bucket_stats[i], bucket);
- if (bucket_stats[i].is_valid) {
- stats.total_resident_bytes += bucket_stats[i].resident_bytes;
- stats.total_active_bytes += bucket_stats[i].active_bytes;
- stats.total_decommittable_bytes += bucket_stats[i].decommittable_bytes;
- stats.total_discardable_bytes += bucket_stats[i].discardable_bytes;
- }
- }
-
- for (internal::PartitionDirectMapExtent* extent = direct_map_list;
- extent && num_direct_mapped_allocations < kMaxReportableDirectMaps;
- extent = extent->next_extent, ++num_direct_mapped_allocations) {
- DCHECK(!extent->next_extent ||
- extent->next_extent->prev_extent == extent);
- size_t slot_size = extent->bucket->slot_size;
- direct_mapped_allocations_total_size += slot_size;
- if (is_light_dump)
- continue;
- direct_map_lengths[num_direct_mapped_allocations] = slot_size;
- }
- }
-
- if (!is_light_dump) {
- // Call |PartitionsDumpBucketStats| after collecting stats because it can
- // try to allocate using |PartitionRootGeneric::Alloc()| and it can't
- // obtain the lock.
- for (size_t i = 0; i < kGenericNumBuckets; ++i) {
- if (bucket_stats[i].is_valid)
- dumper->PartitionsDumpBucketStats(partition_name, &bucket_stats[i]);
- }
-
- for (size_t i = 0; i < num_direct_mapped_allocations; ++i) {
- uint32_t size = direct_map_lengths[i];
-
- PartitionBucketMemoryStats mapped_stats = {};
- mapped_stats.is_valid = true;
- mapped_stats.is_direct_map = true;
- mapped_stats.num_full_pages = 1;
- mapped_stats.allocated_page_size = size;
- mapped_stats.bucket_slot_size = size;
- mapped_stats.active_bytes = size;
- mapped_stats.resident_bytes = size;
- dumper->PartitionsDumpBucketStats(partition_name, &mapped_stats);
- }
- }
-
- stats.total_resident_bytes += direct_mapped_allocations_total_size;
- stats.total_active_bytes += direct_mapped_allocations_total_size;
- dumper->PartitionDumpTotals(partition_name, &stats);
-}
-
-void PartitionRoot::DumpStats(const char* partition_name,
- bool is_light_dump,
- PartitionStatsDumper* dumper) {
- PartitionMemoryStats stats = {0};
- stats.total_mmapped_bytes = total_size_of_super_pages;
- stats.total_committed_bytes = total_size_of_committed_pages;
- DCHECK(!total_size_of_direct_mapped_pages);
-
- static constexpr size_t kMaxReportableBuckets = 4096 / sizeof(void*);
- std::unique_ptr<PartitionBucketMemoryStats[]> memory_stats;
- if (!is_light_dump) {
- memory_stats = std::unique_ptr<PartitionBucketMemoryStats[]>(
- new PartitionBucketMemoryStats[kMaxReportableBuckets]);
- }
-
- const size_t partition_num_buckets = num_buckets;
- DCHECK(partition_num_buckets <= kMaxReportableBuckets);
-
- for (size_t i = 0; i < partition_num_buckets; ++i) {
- PartitionBucketMemoryStats bucket_stats = {0};
- PartitionDumpBucketStats(&bucket_stats, &buckets()[i]);
- if (bucket_stats.is_valid) {
- stats.total_resident_bytes += bucket_stats.resident_bytes;
- stats.total_active_bytes += bucket_stats.active_bytes;
- stats.total_decommittable_bytes += bucket_stats.decommittable_bytes;
- stats.total_discardable_bytes += bucket_stats.discardable_bytes;
- }
- if (!is_light_dump) {
- if (bucket_stats.is_valid)
- memory_stats[i] = bucket_stats;
- else
- memory_stats[i].is_valid = false;
- }
- }
- if (!is_light_dump) {
- // PartitionsDumpBucketStats is called after collecting stats because it
- // can use PartitionRoot::Alloc() to allocate and this can affect the
- // statistics.
- for (size_t i = 0; i < partition_num_buckets; ++i) {
- if (memory_stats[i].is_valid)
- dumper->PartitionsDumpBucketStats(partition_name, &memory_stats[i]);
- }
- }
- dumper->PartitionDumpTotals(partition_name, &stats);
-}
-
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/partition_alloc.h b/third_party/base/allocator/partition_allocator/partition_alloc.h
deleted file mode 100644
index 0f4f83a..0000000
--- a/third_party/base/allocator/partition_allocator/partition_alloc.h
+++ /dev/null
@@ -1,533 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_H_
-
-// DESCRIPTION
-// PartitionRoot::Alloc() / PartitionRootGeneric::Alloc() and PartitionFree() /
-// PartitionRootGeneric::Free() are approximately analagous to malloc() and
-// free().
-//
-// The main difference is that a PartitionRoot / PartitionRootGeneric object
-// must be supplied to these functions, representing a specific "heap partition"
-// that will be used to satisfy the allocation. Different partitions are
-// guaranteed to exist in separate address spaces, including being separate from
-// the main system heap. If the contained objects are all freed, physical memory
-// is returned to the system but the address space remains reserved.
-// See PartitionAlloc.md for other security properties PartitionAlloc provides.
-//
-// THE ONLY LEGITIMATE WAY TO OBTAIN A PartitionRoot IS THROUGH THE
-// SizeSpecificPartitionAllocator / PartitionAllocatorGeneric classes. To
-// minimize the instruction count to the fullest extent possible, the
-// PartitionRoot is really just a header adjacent to other data areas provided
-// by the allocator class.
-//
-// The PartitionRoot::Alloc() variant of the API has the following caveats:
-// - Allocations and frees against a single partition must be single threaded.
-// - Allocations must not exceed a max size, chosen at compile-time via a
-// templated parameter to PartitionAllocator.
-// - Allocation sizes must be aligned to the system pointer size.
-// - Allocations are bucketed exactly according to size.
-//
-// And for PartitionRootGeneric::Alloc():
-// - Multi-threaded use against a single partition is ok; locking is handled.
-// - Allocations of any arbitrary size can be handled (subject to a limit of
-// INT_MAX bytes for security reasons).
-// - Bucketing is by approximate size, for example an allocation of 4000 bytes
-// might be placed into a 4096-byte bucket. Bucket sizes are chosen to try and
-// keep worst-case waste to ~10%.
-//
-// The allocators are designed to be extremely fast, thanks to the following
-// properties and design:
-// - Just two single (reasonably predicatable) branches in the hot / fast path
-// for both allocating and (significantly) freeing.
-// - A minimal number of operations in the hot / fast path, with the slow paths
-// in separate functions, leading to the possibility of inlining.
-// - Each partition page (which is usually multiple physical pages) has a
-// metadata structure which allows fast mapping of free() address to an
-// underlying bucket.
-// - Supports a lock-free API for fast performance in single-threaded cases.
-// - The freelist for a given bucket is split across a number of partition
-// pages, enabling various simple tricks to try and minimize fragmentation.
-// - Fine-grained bucket sizes leading to less waste and better packing.
-//
-// The following security properties could be investigated in the future:
-// - Per-object bucketing (instead of per-size) is mostly available at the API,
-// but not used yet.
-// - No randomness of freelist entries or bucket position.
-// - Better checking for wild pointers in free().
-// - Better freelist masking function to guarantee fault on 32-bit.
-
-#include <limits.h>
-#include <string.h>
-
-#include <iterator>
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/allocator/partition_allocator/partition_bucket.h"
-#include "third_party/base/allocator/partition_allocator/partition_cookie.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-#include "third_party/base/allocator/partition_allocator/partition_root_base.h"
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-#include "third_party/base/base_export.h"
-#include "third_party/base/bits.h"
-#include "third_party/base/check.h"
-#include "third_party/base/compiler_specific.h"
-#include "third_party/base/sys_byteorder.h"
-
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-#include <stdlib.h>
-#endif
-
-// We use this to make MEMORY_TOOL_REPLACES_ALLOCATOR behave the same for max
-// size as other alloc code.
-#define CHECK_MAX_SIZE_OR_RETURN_NULLPTR(size, flags) \
- if (size > GenericMaxDirectMapped()) { \
- if (flags & PartitionAllocReturnNull) { \
- return nullptr; \
- } \
- CHECK(false); \
- }
-
-namespace pdfium {
-namespace base {
-
-class PartitionStatsDumper;
-
-enum PartitionPurgeFlags {
- // Decommitting the ring list of empty pages is reasonably fast.
- PartitionPurgeDecommitEmptyPages = 1 << 0,
- // Discarding unused system pages is slower, because it involves walking all
- // freelists in all active partition pages of all buckets >= system page
- // size. It often frees a similar amount of memory to decommitting the empty
- // pages, though.
- PartitionPurgeDiscardUnusedSystemPages = 1 << 1,
-};
-
-// Never instantiate a PartitionRoot directly, instead use PartitionAlloc.
-struct BASE_EXPORT PartitionRoot : public internal::PartitionRootBase {
- PartitionRoot();
- ~PartitionRoot() override;
- // This references the buckets OFF the edge of this struct. All uses of
- // PartitionRoot must have the bucket array come right after.
- //
- // The PartitionAlloc templated class ensures the following is correct.
- ALWAYS_INLINE internal::PartitionBucket* buckets() {
- return reinterpret_cast<internal::PartitionBucket*>(this + 1);
- }
- ALWAYS_INLINE const internal::PartitionBucket* buckets() const {
- return reinterpret_cast<const internal::PartitionBucket*>(this + 1);
- }
-
- void Init(size_t bucket_count, size_t maximum_allocation);
-
- ALWAYS_INLINE void* Alloc(size_t size, const char* type_name);
- ALWAYS_INLINE void* AllocFlags(int flags, size_t size, const char* type_name);
-
- void PurgeMemory(int flags) override;
-
- void DumpStats(const char* partition_name,
- bool is_light_dump,
- PartitionStatsDumper* dumper);
-};
-
-// Never instantiate a PartitionRootGeneric directly, instead use
-// PartitionAllocatorGeneric.
-struct BASE_EXPORT PartitionRootGeneric : public internal::PartitionRootBase {
- PartitionRootGeneric();
- ~PartitionRootGeneric() override;
- subtle::SpinLock lock;
- // Some pre-computed constants.
- size_t order_index_shifts[kBitsPerSizeT + 1] = {};
- size_t order_sub_index_masks[kBitsPerSizeT + 1] = {};
- // The bucket lookup table lets us map a size_t to a bucket quickly.
- // The trailing +1 caters for the overflow case for very large allocation
- // sizes. It is one flat array instead of a 2D array because in the 2D
- // world, we'd need to index array[blah][max+1] which risks undefined
- // behavior.
- internal::PartitionBucket*
- bucket_lookups[((kBitsPerSizeT + 1) * kGenericNumBucketsPerOrder) + 1] =
- {};
- internal::PartitionBucket buckets[kGenericNumBuckets] = {};
-
- // Public API.
- void Init();
-
- ALWAYS_INLINE void* Alloc(size_t size, const char* type_name);
- ALWAYS_INLINE void* AllocFlags(int flags, size_t size, const char* type_name);
- ALWAYS_INLINE void Free(void* ptr);
-
- NOINLINE void* Realloc(void* ptr, size_t new_size, const char* type_name);
- // Overload that may return nullptr if reallocation isn't possible. In this
- // case, |ptr| remains valid.
- NOINLINE void* TryRealloc(void* ptr, size_t new_size, const char* type_name);
-
- ALWAYS_INLINE size_t ActualSize(size_t size);
-
- void PurgeMemory(int flags) override;
-
- void DumpStats(const char* partition_name,
- bool is_light_dump,
- PartitionStatsDumper* partition_stats_dumper);
-};
-
-// Struct used to retrieve total memory usage of a partition. Used by
-// PartitionStatsDumper implementation.
-struct PartitionMemoryStats {
- size_t total_mmapped_bytes; // Total bytes mmaped from the system.
- size_t total_committed_bytes; // Total size of commmitted pages.
- size_t total_resident_bytes; // Total bytes provisioned by the partition.
- size_t total_active_bytes; // Total active bytes in the partition.
- size_t total_decommittable_bytes; // Total bytes that could be decommitted.
- size_t total_discardable_bytes; // Total bytes that could be discarded.
-};
-
-// Struct used to retrieve memory statistics about a partition bucket. Used by
-// PartitionStatsDumper implementation.
-struct PartitionBucketMemoryStats {
- bool is_valid; // Used to check if the stats is valid.
- bool is_direct_map; // True if this is a direct mapping; size will not be
- // unique.
- uint32_t bucket_slot_size; // The size of the slot in bytes.
- uint32_t allocated_page_size; // Total size the partition page allocated from
- // the system.
- uint32_t active_bytes; // Total active bytes used in the bucket.
- uint32_t resident_bytes; // Total bytes provisioned in the bucket.
- uint32_t decommittable_bytes; // Total bytes that could be decommitted.
- uint32_t discardable_bytes; // Total bytes that could be discarded.
- uint32_t num_full_pages; // Number of pages with all slots allocated.
- uint32_t num_active_pages; // Number of pages that have at least one
- // provisioned slot.
- uint32_t num_empty_pages; // Number of pages that are empty
- // but not decommitted.
- uint32_t num_decommitted_pages; // Number of pages that are empty
- // and decommitted.
-};
-
-// Interface that is passed to PartitionDumpStats and
-// PartitionDumpStatsGeneric for using the memory statistics.
-class BASE_EXPORT PartitionStatsDumper {
- public:
- // Called to dump total memory used by partition, once per partition.
- virtual void PartitionDumpTotals(const char* partition_name,
- const PartitionMemoryStats*) = 0;
-
- // Called to dump stats about buckets, for each bucket.
- virtual void PartitionsDumpBucketStats(const char* partition_name,
- const PartitionBucketMemoryStats*) = 0;
-};
-
-BASE_EXPORT void PartitionAllocGlobalInit(OomFunction on_out_of_memory);
-
-// PartitionAlloc supports setting hooks to observe allocations/frees as they
-// occur as well as 'override' hooks that allow overriding those operations.
-class BASE_EXPORT PartitionAllocHooks {
- public:
- // Log allocation and free events.
- typedef void AllocationObserverHook(void* address,
- size_t size,
- const char* type_name);
- typedef void FreeObserverHook(void* address);
-
- // If it returns true, the allocation has been overridden with the pointer in
- // *out.
- typedef bool AllocationOverrideHook(void** out,
- int flags,
- size_t size,
- const char* type_name);
- // If it returns true, then the allocation was overridden and has been freed.
- typedef bool FreeOverrideHook(void* address);
- // If it returns true, the underlying allocation is overridden and *out holds
- // the size of the underlying allocation.
- typedef bool ReallocOverrideHook(size_t* out, void* address);
-
- // To unhook, call Set*Hooks with nullptrs.
- static void SetObserverHooks(AllocationObserverHook* alloc_hook,
- FreeObserverHook* free_hook);
- static void SetOverrideHooks(AllocationOverrideHook* alloc_hook,
- FreeOverrideHook* free_hook,
- ReallocOverrideHook realloc_hook);
-
- // Helper method to check whether hooks are enabled. This is an optimization
- // so that if a function needs to call observer and override hooks in two
- // different places this value can be cached and only loaded once.
- static bool AreHooksEnabled() {
- return hooks_enabled_.load(std::memory_order_relaxed);
- }
-
- static void AllocationObserverHookIfEnabled(void* address,
- size_t size,
- const char* type_name);
- static bool AllocationOverrideHookIfEnabled(void** out,
- int flags,
- size_t size,
- const char* type_name);
-
- static void FreeObserverHookIfEnabled(void* address);
- static bool FreeOverrideHookIfEnabled(void* address);
-
- static void ReallocObserverHookIfEnabled(void* old_address,
- void* new_address,
- size_t size,
- const char* type_name);
- static bool ReallocOverrideHookIfEnabled(size_t* out, void* address);
-
- private:
- // Single bool that is used to indicate whether observer or allocation hooks
- // are set to reduce the numbers of loads required to check whether hooking is
- // enabled.
- static std::atomic<bool> hooks_enabled_;
-
- // Lock used to synchronize Set*Hooks calls.
- static subtle::SpinLock set_hooks_lock_;
-
- static std::atomic<AllocationObserverHook*> allocation_observer_hook_;
- static std::atomic<FreeObserverHook*> free_observer_hook_;
-
- static std::atomic<AllocationOverrideHook*> allocation_override_hook_;
- static std::atomic<FreeOverrideHook*> free_override_hook_;
- static std::atomic<ReallocOverrideHook*> realloc_override_hook_;
-};
-
-ALWAYS_INLINE void* PartitionRoot::Alloc(size_t size, const char* type_name) {
- return AllocFlags(0, size, type_name);
-}
-
-ALWAYS_INLINE void* PartitionRoot::AllocFlags(int flags,
- size_t size,
- const char* type_name) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- CHECK_MAX_SIZE_OR_RETURN_NULLPTR(size, flags);
- void* result = malloc(size);
- CHECK(result);
- return result;
-#else
- DCHECK(max_allocation == 0 || size <= max_allocation);
- void* result;
- const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
- if (UNLIKELY(hooks_enabled)) {
- if (PartitionAllocHooks::AllocationOverrideHookIfEnabled(&result, flags,
- size, type_name)) {
- PartitionAllocHooks::AllocationObserverHookIfEnabled(result, size,
- type_name);
- return result;
- }
- }
- size_t requested_size = size;
- size = internal::PartitionCookieSizeAdjustAdd(size);
- DCHECK(initialized);
- size_t index = size >> kBucketShift;
- DCHECK(index < num_buckets);
- DCHECK(size == index << kBucketShift);
- internal::PartitionBucket* bucket = &buckets()[index];
- result = AllocFromBucket(bucket, flags, size);
- if (UNLIKELY(hooks_enabled)) {
- PartitionAllocHooks::AllocationObserverHookIfEnabled(result, requested_size,
- type_name);
- }
- return result;
-#endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-}
-
-ALWAYS_INLINE bool PartitionAllocSupportsGetSize() {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- return false;
-#else
- return true;
-#endif
-}
-
-ALWAYS_INLINE size_t PartitionAllocGetSize(void* ptr) {
- // No need to lock here. Only |ptr| being freed by another thread could
- // cause trouble, and the caller is responsible for that not happening.
- DCHECK(PartitionAllocSupportsGetSize());
- ptr = internal::PartitionCookieFreePointerAdjust(ptr);
- internal::PartitionPage* page = internal::PartitionPage::FromPointer(ptr);
- // TODO(palmer): See if we can afford to make this a CHECK.
- DCHECK(internal::PartitionRootBase::IsValidPage(page));
- size_t size = page->bucket->slot_size;
- return internal::PartitionCookieSizeAdjustSubtract(size);
-}
-
-ALWAYS_INLINE void PartitionFree(void* ptr) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- free(ptr);
-#else
- // TODO(palmer): Check ptr alignment before continuing. Shall we do the check
- // inside PartitionCookieFreePointerAdjust?
- if (PartitionAllocHooks::AreHooksEnabled()) {
- PartitionAllocHooks::FreeObserverHookIfEnabled(ptr);
- if (PartitionAllocHooks::FreeOverrideHookIfEnabled(ptr))
- return;
- }
-
- ptr = internal::PartitionCookieFreePointerAdjust(ptr);
- internal::PartitionPage* page = internal::PartitionPage::FromPointer(ptr);
- // TODO(palmer): See if we can afford to make this a CHECK.
- DCHECK(internal::PartitionRootBase::IsValidPage(page));
- internal::DeferredUnmap deferred_unmap = page->Free(ptr);
- deferred_unmap.Run();
-#endif
-}
-
-ALWAYS_INLINE internal::PartitionBucket* PartitionGenericSizeToBucket(
- PartitionRootGeneric* root,
- size_t size) {
- size_t order = kBitsPerSizeT - bits::CountLeadingZeroBitsSizeT(size);
- // The order index is simply the next few bits after the most significant bit.
- size_t order_index = (size >> root->order_index_shifts[order]) &
- (kGenericNumBucketsPerOrder - 1);
- // And if the remaining bits are non-zero we must bump the bucket up.
- size_t sub_order_index = size & root->order_sub_index_masks[order];
- internal::PartitionBucket* bucket =
- root->bucket_lookups[(order << kGenericNumBucketsPerOrderBits) +
- order_index + !!sub_order_index];
- CHECK(bucket);
- DCHECK(!bucket->slot_size || bucket->slot_size >= size);
- DCHECK(!(bucket->slot_size % kGenericSmallestBucket));
- return bucket;
-}
-
-ALWAYS_INLINE void* PartitionAllocGenericFlags(PartitionRootGeneric* root,
- int flags,
- size_t size,
- const char* type_name) {
- DCHECK(flags < PartitionAllocLastFlag << 1);
-
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- CHECK_MAX_SIZE_OR_RETURN_NULLPTR(size, flags);
- const bool zero_fill = flags & PartitionAllocZeroFill;
- void* result = zero_fill ? calloc(1, size) : malloc(size);
- CHECK(result || flags & PartitionAllocReturnNull);
- return result;
-#else
- DCHECK(root->initialized);
- // Only SizeSpecificPartitionAllocator should use max_allocation.
- DCHECK(root->max_allocation == 0);
- void* result;
- const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
- if (UNLIKELY(hooks_enabled)) {
- if (PartitionAllocHooks::AllocationOverrideHookIfEnabled(&result, flags,
- size, type_name)) {
- PartitionAllocHooks::AllocationObserverHookIfEnabled(result, size,
- type_name);
- return result;
- }
- }
- size_t requested_size = size;
- size = internal::PartitionCookieSizeAdjustAdd(size);
- internal::PartitionBucket* bucket = PartitionGenericSizeToBucket(root, size);
- {
- subtle::SpinLock::Guard guard(root->lock);
- result = root->AllocFromBucket(bucket, flags, size);
- }
- if (UNLIKELY(hooks_enabled)) {
- PartitionAllocHooks::AllocationObserverHookIfEnabled(result, requested_size,
- type_name);
- }
-
- return result;
-#endif
-}
-
-ALWAYS_INLINE void* PartitionRootGeneric::Alloc(size_t size,
- const char* type_name) {
- return PartitionAllocGenericFlags(this, 0, size, type_name);
-}
-
-ALWAYS_INLINE void* PartitionRootGeneric::AllocFlags(int flags,
- size_t size,
- const char* type_name) {
- return PartitionAllocGenericFlags(this, flags, size, type_name);
-}
-
-ALWAYS_INLINE void PartitionRootGeneric::Free(void* ptr) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- free(ptr);
-#else
- DCHECK(initialized);
-
- if (UNLIKELY(!ptr))
- return;
-
- if (PartitionAllocHooks::AreHooksEnabled()) {
- PartitionAllocHooks::FreeObserverHookIfEnabled(ptr);
- if (PartitionAllocHooks::FreeOverrideHookIfEnabled(ptr))
- return;
- }
-
- ptr = internal::PartitionCookieFreePointerAdjust(ptr);
- internal::PartitionPage* page = internal::PartitionPage::FromPointer(ptr);
- // TODO(palmer): See if we can afford to make this a CHECK.
- DCHECK(IsValidPage(page));
- internal::DeferredUnmap deferred_unmap;
- {
- subtle::SpinLock::Guard guard(lock);
- deferred_unmap = page->Free(ptr);
- }
- deferred_unmap.Run();
-#endif
-}
-
-BASE_EXPORT void* PartitionReallocGenericFlags(PartitionRootGeneric* root,
- int flags,
- void* ptr,
- size_t new_size,
- const char* type_name);
-
-ALWAYS_INLINE size_t PartitionRootGeneric::ActualSize(size_t size) {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
- return size;
-#else
- DCHECK(initialized);
- size = internal::PartitionCookieSizeAdjustAdd(size);
- internal::PartitionBucket* bucket = PartitionGenericSizeToBucket(this, size);
- if (LIKELY(!bucket->is_direct_mapped())) {
- size = bucket->slot_size;
- } else if (size > GenericMaxDirectMapped()) {
- // Too large to allocate => return the size unchanged.
- } else {
- size = internal::PartitionBucket::get_direct_map_size(size);
- }
- return internal::PartitionCookieSizeAdjustSubtract(size);
-#endif
-}
-
-template <size_t N>
-class SizeSpecificPartitionAllocator {
- public:
- SizeSpecificPartitionAllocator() {
- memset(actual_buckets_, 0,
- sizeof(internal::PartitionBucket) * std::size(actual_buckets_));
- }
- ~SizeSpecificPartitionAllocator() = default;
- static const size_t kMaxAllocation = N - kAllocationGranularity;
- static const size_t kNumBuckets = N / kAllocationGranularity;
- void init() { partition_root_.Init(kNumBuckets, kMaxAllocation); }
- ALWAYS_INLINE PartitionRoot* root() { return &partition_root_; }
-
- private:
- PartitionRoot partition_root_;
- internal::PartitionBucket actual_buckets_[kNumBuckets];
-};
-
-class BASE_EXPORT PartitionAllocatorGeneric {
- public:
- PartitionAllocatorGeneric();
- ~PartitionAllocatorGeneric();
-
- void init() { partition_root_.Init(); }
- ALWAYS_INLINE PartitionRootGeneric* root() { return &partition_root_; }
-
- private:
- PartitionRootGeneric partition_root_;
-};
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_alloc_check.h b/third_party/base/allocator/partition_allocator/partition_alloc_check.h
deleted file mode 100644
index 26002b6..0000000
--- a/third_party/base/allocator/partition_allocator/partition_alloc_check.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CHECK_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CHECK_H_
-
-#include "third_party/base/allocator/partition_allocator/page_allocator_constants.h"
-#include "third_party/base/check.h"
-
-#if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR)
-
-// Use this macro to assert on things that are conditionally constexpr as
-// determined by PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR or
-// PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR. Where fixed at compile time, this
-// is a static_assert. Where determined at run time, this is a CHECK.
-// Therefore, this macro must only be used where both a static_assert and a
-// CHECK would be viable, that is, within a function, and ideally a function
-// that executes only once, early in the program, such as during initialization.
-#define STATIC_ASSERT_OR_CHECK(condition, message) \
- static_assert(condition, message)
-
-#else
-
-#define STATIC_ASSERT_OR_CHECK(condition, message) \
- do { \
- CHECK(condition); \
- } while (false)
-
-#endif
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CHECK_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_alloc_constants.h b/third_party/base/allocator/partition_allocator/partition_alloc_constants.h
deleted file mode 100644
index d0280ce..0000000
--- a/third_party/base/allocator/partition_allocator/partition_alloc_constants.h
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONSTANTS_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONSTANTS_H_
-
-#include <limits.h>
-#include <stddef.h>
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator_constants.h"
-
-#if BUILDFLAG(IS_APPLE)
-#include <mach/vm_page_size.h>
-#endif
-
-namespace pdfium {
-namespace base {
-
-// Allocation granularity of sizeof(void*) bytes.
-static const size_t kAllocationGranularity = sizeof(void*);
-static const size_t kAllocationGranularityMask = kAllocationGranularity - 1;
-static const size_t kBucketShift = (kAllocationGranularity == 8) ? 3 : 2;
-
-// Underlying partition storage pages (`PartitionPage`s) are a power-of-2 size.
-// It is typical for a `PartitionPage` to be based on multiple system pages.
-// Most references to "page" refer to `PartitionPage`s.
-//
-// *Super pages* are the underlying system allocations we make. Super pages
-// contain multiple partition pages and include space for a small amount of
-// metadata per partition page.
-//
-// Inside super pages, we store *slot spans*. A slot span is a continguous range
-// of one or more `PartitionPage`s that stores allocations of the same size.
-// Slot span sizes are adjusted depending on the allocation size, to make sure
-// the packing does not lead to unused (wasted) space at the end of the last
-// system page of the span. For our current maximum slot span size of 64 KiB and
-// other constant values, we pack _all_ `PartitionRootGeneric::Alloc` sizes
-// perfectly up against the end of a system page.
-
-#if defined(_MIPS_ARCH_LOONGSON)
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE int
-PartitionPageShift() {
- return 16; // 64 KiB
-}
-#elif defined(ARCH_CPU_PPC64)
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE int
-PartitionPageShift() {
- return 18; // 256 KiB
-}
-#elif BUILDFLAG(IS_APPLE)
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE int
-PartitionPageShift() {
- return vm_page_shift + 2;
-}
-#else
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE int
-PartitionPageShift() {
- return 14; // 16 KiB
-}
-#endif
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PartitionPageSize() {
- return 1ULL << PartitionPageShift();
-}
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PartitionPageOffsetMask() {
- return PartitionPageSize() - 1;
-}
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-PartitionPageBaseMask() {
- return ~PartitionPageOffsetMask();
-}
-// TODO: Should this be 1 if defined(_MIPS_ARCH_LOONGSON)?
-static const size_t kMaxPartitionPagesPerSlotSpan = 4;
-
-// To avoid fragmentation via never-used freelist entries, we hand out partition
-// freelist sections gradually, in units of the dominant system page size. What
-// we're actually doing is avoiding filling the full `PartitionPage` (16 KiB)
-// with freelist pointers right away. Writing freelist pointers will fault and
-// dirty a private page, which is very wasteful if we never actually store
-// objects there.
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-NumSystemPagesPerPartitionPage() {
- return PartitionPageSize() / SystemPageSize();
-}
-
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-MaxSystemPagesPerSlotSpan() {
- return NumSystemPagesPerPartitionPage() * kMaxPartitionPagesPerSlotSpan;
-}
-
-// We reserve virtual address space in 2 MiB chunks (aligned to 2 MiB as well).
-// These chunks are called *super pages*. We do this so that we can store
-// metadata in the first few pages of each 2 MiB-aligned section. This makes
-// freeing memory very fast. We specifically choose 2 MiB because this virtual
-// address block represents a full but single PTE allocation on ARM, ia32 and
-// x64.
-//
-// The layout of the super page is as follows. The sizes below are the same for
-// 32- and 64-bit platforms.
-//
-// +-----------------------+
-// | Guard page (4 KiB) |
-// | Metadata page (4 KiB) |
-// | Guard pages (8 KiB) |
-// | Slot span |
-// | Slot span |
-// | ... |
-// | Slot span |
-// | Guard page (4 KiB) |
-// +-----------------------+
-//
-// Each slot span is a contiguous range of one or more `PartitionPage`s.
-//
-// The metadata page has the following format. Note that the `PartitionPage`
-// that is not at the head of a slot span is "unused". In other words, the
-// metadata for the slot span is stored only in the first `PartitionPage` of the
-// slot span. Metadata accesses to other `PartitionPage`s are redirected to the
-// first `PartitionPage`.
-//
-// +---------------------------------------------+
-// | SuperPageExtentEntry (32 B) |
-// | PartitionPage of slot span 1 (32 B, used) |
-// | PartitionPage of slot span 1 (32 B, unused) |
-// | PartitionPage of slot span 1 (32 B, unused) |
-// | PartitionPage of slot span 2 (32 B, used) |
-// | PartitionPage of slot span 3 (32 B, used) |
-// | ... |
-// | PartitionPage of slot span N (32 B, unused) |
-// +---------------------------------------------+
-//
-// A direct-mapped page has a similar layout to fake it looking like a super
-// page:
-//
-// +-----------------------+
-// | Guard page (4 KiB) |
-// | Metadata page (4 KiB) |
-// | Guard pages (8 KiB) |
-// | Direct mapped object |
-// | Guard page (4 KiB) |
-// +-----------------------+
-//
-// A direct-mapped page's metadata page has the following layout:
-//
-// +--------------------------------+
-// | SuperPageExtentEntry (32 B) |
-// | PartitionPage (32 B) |
-// | PartitionBucket (32 B) |
-// | PartitionDirectMapExtent (8 B) |
-// +--------------------------------+
-
-static const size_t kSuperPageShift = 21; // 2 MiB
-static const size_t kSuperPageSize = 1 << kSuperPageShift;
-static const size_t kSuperPageOffsetMask = kSuperPageSize - 1;
-static const size_t kSuperPageBaseMask = ~kSuperPageOffsetMask;
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-NumPartitionPagesPerSuperPage() {
- return kSuperPageSize / PartitionPageSize();
-}
-
-// The following kGeneric* constants apply to the generic variants of the API.
-// The "order" of an allocation is closely related to the power-of-1 size of the
-// allocation. More precisely, the order is the bit index of the
-// most-significant-bit in the allocation size, where the bit numbers starts at
-// index 1 for the least-significant-bit.
-//
-// In terms of allocation sizes, order 0 covers 0, order 1 covers 1, order 2
-// covers 2->3, order 3 covers 4->7, order 4 covers 8->15.
-
-static const size_t kGenericMinBucketedOrder = 4; // 8 bytes.
-// The largest bucketed order is 1 << (20 - 1), storing [512 KiB, 1 MiB):
-static const size_t kGenericMaxBucketedOrder = 20;
-static const size_t kGenericNumBucketedOrders =
- (kGenericMaxBucketedOrder - kGenericMinBucketedOrder) + 1;
-// Eight buckets per order (for the higher orders), e.g. order 8 is 128, 144,
-// 160, ..., 240:
-static const size_t kGenericNumBucketsPerOrderBits = 3;
-static const size_t kGenericNumBucketsPerOrder =
- 1 << kGenericNumBucketsPerOrderBits;
-static const size_t kGenericNumBuckets =
- kGenericNumBucketedOrders * kGenericNumBucketsPerOrder;
-static const size_t kGenericSmallestBucket = 1
- << (kGenericMinBucketedOrder - 1);
-static const size_t kGenericMaxBucketSpacing =
- 1 << ((kGenericMaxBucketedOrder - 1) - kGenericNumBucketsPerOrderBits);
-static const size_t kGenericMaxBucketed =
- (1 << (kGenericMaxBucketedOrder - 1)) +
- ((kGenericNumBucketsPerOrder - 1) * kGenericMaxBucketSpacing);
-// Limit when downsizing a direct mapping using `realloc`:
-static const size_t kGenericMinDirectMappedDownsize = kGenericMaxBucketed + 1;
-PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t
-GenericMaxDirectMapped() {
- return (1UL << 31) + PageAllocationGranularity(); // 2 GiB plus 1 more page.
-}
-static const size_t kBitsPerSizeT = sizeof(void*) * CHAR_BIT;
-
-// Constant for the memory reclaim logic.
-static const size_t kMaxFreeableSpans = 16;
-
-// If the total size in bytes of allocated but not committed pages exceeds this
-// value (probably it is a "out of virtual address space" crash), a special
-// crash stack trace is generated at
-// `PartitionOutOfMemoryWithLotsOfUncommitedPages`. This is to distinguish "out
-// of virtual address space" from "out of physical memory" in crash reports.
-static const size_t kReasonableSizeOfUnusedPages = 1024 * 1024 * 1024; // 1 GiB
-
-// These byte values match tcmalloc.
-static const unsigned char kUninitializedByte = 0xAB;
-static const unsigned char kFreedByte = 0xCD;
-
-// Flags for `PartitionAllocGenericFlags`.
-enum PartitionAllocFlags {
- PartitionAllocReturnNull = 1 << 0,
- PartitionAllocZeroFill = 1 << 1,
-
- PartitionAllocLastFlag = PartitionAllocZeroFill
-};
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONSTANTS_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_bucket.cc b/third_party/base/allocator/partition_allocator/partition_bucket.cc
deleted file mode 100644
index 4a02d4b..0000000
--- a/third_party/base/allocator/partition_allocator/partition_bucket.cc
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/partition_bucket.h"
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/oom.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/allocator/partition_allocator/partition_direct_map_extent.h"
-#include "third_party/base/allocator/partition_allocator/partition_oom.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-#include "third_party/base/allocator/partition_allocator/partition_root_base.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-namespace {
-
-ALWAYS_INLINE PartitionPage* PartitionDirectMap(PartitionRootBase* root,
- int flags,
- size_t raw_size) {
- size_t size = PartitionBucket::get_direct_map_size(raw_size);
-
- // Because we need to fake looking like a super page, we need to allocate
- // a bunch of system pages more than "size":
- // - The first few system pages are the partition page in which the super
- // page metadata is stored. We fault just one system page out of a partition
- // page sized clump.
- // - We add a trailing guard page on 32-bit (on 64-bit we rely on the
- // massive address space plus randomization instead).
- size_t map_size = size + PartitionPageSize();
-#if !defined(ARCH_CPU_64_BITS)
- map_size += SystemPageSize();
-#endif
- // Round up to the allocation granularity.
- map_size += PageAllocationGranularityOffsetMask();
- map_size &= PageAllocationGranularityBaseMask();
-
- char* ptr = reinterpret_cast<char*>(AllocPages(nullptr, map_size,
- kSuperPageSize, PageReadWrite,
- PageTag::kPartitionAlloc));
- if (UNLIKELY(!ptr))
- return nullptr;
-
- size_t committed_page_size = size + SystemPageSize();
- root->total_size_of_direct_mapped_pages += committed_page_size;
- root->IncreaseCommittedPages(committed_page_size);
-
- char* slot = ptr + PartitionPageSize();
- SetSystemPagesAccess(ptr + (SystemPageSize() * 2),
- PartitionPageSize() - (SystemPageSize() * 2),
- PageInaccessible);
-#if !defined(ARCH_CPU_64_BITS)
- SetSystemPagesAccess(ptr, SystemPageSize(), PageInaccessible);
- SetSystemPagesAccess(slot + size, SystemPageSize(), PageInaccessible);
-#endif
-
- PartitionSuperPageExtentEntry* extent =
- reinterpret_cast<PartitionSuperPageExtentEntry*>(
- PartitionSuperPageToMetadataArea(ptr));
- extent->root = root;
- // The new structures are all located inside a fresh system page so they
- // will all be zeroed out. These DCHECKs are for documentation.
- DCHECK(!extent->super_page_base);
- DCHECK(!extent->super_pages_end);
- DCHECK(!extent->next);
- PartitionPage* page = PartitionPage::FromPointerNoAlignmentCheck(slot);
- PartitionBucket* bucket = reinterpret_cast<PartitionBucket*>(
- reinterpret_cast<char*>(page) + (kPageMetadataSize * 2));
- DCHECK(!page->next_page);
- DCHECK(!page->num_allocated_slots);
- DCHECK(!page->num_unprovisioned_slots);
- DCHECK(!page->page_offset);
- DCHECK(!page->empty_cache_index);
- page->bucket = bucket;
- page->freelist_head = reinterpret_cast<PartitionFreelistEntry*>(slot);
- PartitionFreelistEntry* next_entry =
- reinterpret_cast<PartitionFreelistEntry*>(slot);
- next_entry->next = PartitionFreelistEntry::Encode(nullptr);
-
- DCHECK(!bucket->active_pages_head);
- DCHECK(!bucket->empty_pages_head);
- DCHECK(!bucket->decommitted_pages_head);
- DCHECK(!bucket->num_system_pages_per_slot_span);
- DCHECK(!bucket->num_full_pages);
- bucket->slot_size = size;
-
- PartitionDirectMapExtent* map_extent =
- PartitionDirectMapExtent::FromPage(page);
- map_extent->map_size = map_size - PartitionPageSize() - SystemPageSize();
- map_extent->bucket = bucket;
-
- // Maintain the doubly-linked list of all direct mappings.
- map_extent->next_extent = root->direct_map_list;
- if (map_extent->next_extent)
- map_extent->next_extent->prev_extent = map_extent;
- map_extent->prev_extent = nullptr;
- root->direct_map_list = map_extent;
-
- return page;
-}
-
-} // namespace
-
-// static
-PartitionBucket PartitionBucket::sentinel_bucket_;
-
-PartitionBucket* PartitionBucket::get_sentinel_bucket() {
- return &sentinel_bucket_;
-}
-
-// TODO(ajwong): This seems to interact badly with
-// get_pages_per_slot_span() which rounds the value from this up to a
-// multiple of NumSystemPagesPerPartitionPage() (aka 4) anyways.
-// http://crbug.com/776537
-//
-// TODO(ajwong): The waste calculation seems wrong. The PTE usage should cover
-// both used and unsed pages.
-// http://crbug.com/776537
-uint8_t PartitionBucket::get_system_pages_per_slot_span() {
- // This works out reasonably for the current bucket sizes of the generic
- // allocator, and the current values of partition page size and constants.
- // Specifically, we have enough room to always pack the slots perfectly into
- // some number of system pages. The only waste is the waste associated with
- // unfaulted pages (i.e. wasted address space).
- // TODO: we end up using a lot of system pages for very small sizes. For
- // example, we'll use 12 system pages for slot size 24. The slot size is
- // so small that the waste would be tiny with just 4, or 1, system pages.
- // Later, we can investigate whether there are anti-fragmentation benefits
- // to using fewer system pages.
- double best_waste_ratio = 1.0f;
- uint16_t best_pages = 0;
- if (slot_size > MaxSystemPagesPerSlotSpan() * SystemPageSize()) {
- // TODO(ajwong): Why is there a DCHECK here for this?
- // http://crbug.com/776537
- DCHECK(!(slot_size % SystemPageSize()));
- best_pages = static_cast<uint16_t>(slot_size / SystemPageSize());
- // TODO(ajwong): Should this be checking against
- // MaxSystemPagesPerSlotSpan() or numeric_limits<uint8_t>::max?
- // http://crbug.com/776537
- CHECK(best_pages < (1 << 8));
- return static_cast<uint8_t>(best_pages);
- }
- DCHECK(slot_size <= MaxSystemPagesPerSlotSpan() * SystemPageSize());
- for (uint16_t i = NumSystemPagesPerPartitionPage() - 1;
- i <= MaxSystemPagesPerSlotSpan(); ++i) {
- size_t page_size = SystemPageSize() * i;
- size_t num_slots = page_size / slot_size;
- size_t waste = page_size - (num_slots * slot_size);
- // Leaving a page unfaulted is not free; the page will occupy an empty page
- // table entry. Make a simple attempt to account for that.
- //
- // TODO(ajwong): This looks wrong. PTEs are allocated for all pages
- // regardless of whether or not they are wasted. Should it just
- // be waste += i * sizeof(void*)?
- // http://crbug.com/776537
- size_t num_remainder_pages = i & (NumSystemPagesPerPartitionPage() - 1);
- size_t num_unfaulted_pages =
- num_remainder_pages
- ? (NumSystemPagesPerPartitionPage() - num_remainder_pages)
- : 0;
- waste += sizeof(void*) * num_unfaulted_pages;
- double waste_ratio =
- static_cast<double>(waste) / static_cast<double>(page_size);
- if (waste_ratio < best_waste_ratio) {
- best_waste_ratio = waste_ratio;
- best_pages = i;
- }
- }
- DCHECK(best_pages > 0);
- CHECK(best_pages <= MaxSystemPagesPerSlotSpan());
- return static_cast<uint8_t>(best_pages);
-}
-
-void PartitionBucket::Init(uint32_t new_slot_size) {
- slot_size = new_slot_size;
- active_pages_head = PartitionPage::get_sentinel_page();
- empty_pages_head = nullptr;
- decommitted_pages_head = nullptr;
- num_full_pages = 0;
- num_system_pages_per_slot_span = get_system_pages_per_slot_span();
-}
-
-NOINLINE void PartitionBucket::OnFull() {
- OOM_CRASH(0);
-}
-
-ALWAYS_INLINE void* PartitionBucket::AllocNewSlotSpan(
- PartitionRootBase* root,
- int flags,
- uint16_t num_partition_pages) {
- DCHECK(!(reinterpret_cast<uintptr_t>(root->next_partition_page) %
- PartitionPageSize()));
- DCHECK(!(reinterpret_cast<uintptr_t>(root->next_partition_page_end) %
- PartitionPageSize()));
- DCHECK(num_partition_pages <= NumPartitionPagesPerSuperPage());
- size_t total_size = PartitionPageSize() * num_partition_pages;
- size_t num_partition_pages_left =
- (root->next_partition_page_end - root->next_partition_page) >>
- PartitionPageShift();
- if (LIKELY(num_partition_pages_left >= num_partition_pages)) {
- // In this case, we can still hand out pages from the current super page
- // allocation.
- char* ret = root->next_partition_page;
-
- // Fresh System Pages in the SuperPages are decommited. Commit them
- // before vending them back.
- SetSystemPagesAccess(ret, total_size, PageReadWrite);
-
- root->next_partition_page += total_size;
- root->IncreaseCommittedPages(total_size);
- return ret;
- }
-
- // Need a new super page. We want to allocate super pages in a continguous
- // address region as much as possible. This is important for not causing
- // page table bloat and not fragmenting address spaces in 32 bit
- // architectures.
- char* requested_address = root->next_super_page;
- char* super_page = reinterpret_cast<char*>(
- AllocPages(requested_address, kSuperPageSize, kSuperPageSize,
- PageReadWrite, PageTag::kPartitionAlloc));
- if (UNLIKELY(!super_page))
- return nullptr;
-
- root->total_size_of_super_pages += kSuperPageSize;
- root->IncreaseCommittedPages(total_size);
-
- // |total_size| MUST be less than kSuperPageSize - (PartitionPageSize()*2).
- // This is a trustworthy value because num_partition_pages is not user
- // controlled.
- //
- // TODO(ajwong): Introduce a DCHECK.
- root->next_super_page = super_page + kSuperPageSize;
- char* ret = super_page + PartitionPageSize();
- root->next_partition_page = ret + total_size;
- root->next_partition_page_end = root->next_super_page - PartitionPageSize();
- // Make the first partition page in the super page a guard page, but leave a
- // hole in the middle.
- // This is where we put page metadata and also a tiny amount of extent
- // metadata.
- SetSystemPagesAccess(super_page, SystemPageSize(), PageInaccessible);
- SetSystemPagesAccess(super_page + (SystemPageSize() * 2),
- PartitionPageSize() - (SystemPageSize() * 2),
- PageInaccessible);
- // SetSystemPagesAccess(super_page + (kSuperPageSize -
- // PartitionPageSize()), PartitionPageSize(), PageInaccessible);
- // All remaining slotspans for the unallocated PartitionPages inside the
- // SuperPage are conceptually decommitted. Correctly set the state here
- // so they do not occupy resources.
- //
- // TODO(ajwong): Refactor Page Allocator API so the SuperPage comes in
- // decommited initially.
- SetSystemPagesAccess(super_page + PartitionPageSize() + total_size,
- (kSuperPageSize - PartitionPageSize() - total_size),
- PageInaccessible);
-
- // If we were after a specific address, but didn't get it, assume that
- // the system chose a lousy address. Here most OS'es have a default
- // algorithm that isn't randomized. For example, most Linux
- // distributions will allocate the mapping directly before the last
- // successful mapping, which is far from random. So we just get fresh
- // randomness for the next mapping attempt.
- if (requested_address && requested_address != super_page)
- root->next_super_page = nullptr;
-
- // We allocated a new super page so update super page metadata.
- // First check if this is a new extent or not.
- PartitionSuperPageExtentEntry* latest_extent =
- reinterpret_cast<PartitionSuperPageExtentEntry*>(
- PartitionSuperPageToMetadataArea(super_page));
- // By storing the root in every extent metadata object, we have a fast way
- // to go from a pointer within the partition to the root object.
- latest_extent->root = root;
- // Most new extents will be part of a larger extent, and these three fields
- // are unused, but we initialize them to 0 so that we get a clear signal
- // in case they are accidentally used.
- latest_extent->super_page_base = nullptr;
- latest_extent->super_pages_end = nullptr;
- latest_extent->next = nullptr;
-
- PartitionSuperPageExtentEntry* current_extent = root->current_extent;
- bool is_new_extent = (super_page != requested_address);
- if (UNLIKELY(is_new_extent)) {
- if (UNLIKELY(!current_extent)) {
- DCHECK(!root->first_extent);
- root->first_extent = latest_extent;
- } else {
- DCHECK(current_extent->super_page_base);
- current_extent->next = latest_extent;
- }
- root->current_extent = latest_extent;
- latest_extent->super_page_base = super_page;
- latest_extent->super_pages_end = super_page + kSuperPageSize;
- } else {
- // We allocated next to an existing extent so just nudge the size up a
- // little.
- DCHECK(current_extent->super_pages_end);
- current_extent->super_pages_end += kSuperPageSize;
- DCHECK(ret >= current_extent->super_page_base &&
- ret < current_extent->super_pages_end);
- }
- return ret;
-}
-
-ALWAYS_INLINE uint16_t PartitionBucket::get_pages_per_slot_span() {
- // Rounds up to nearest multiple of NumSystemPagesPerPartitionPage().
- return (num_system_pages_per_slot_span +
- (NumSystemPagesPerPartitionPage() - 1)) /
- NumSystemPagesPerPartitionPage();
-}
-
-ALWAYS_INLINE void PartitionBucket::InitializeSlotSpan(PartitionPage* page) {
- // The bucket never changes. We set it up once.
- page->bucket = this;
- page->empty_cache_index = -1;
-
- page->Reset();
-
- // If this page has just a single slot, do not set up page offsets for any
- // page metadata other than the first one. This ensures that attempts to
- // touch invalid page metadata fail.
- if (page->num_unprovisioned_slots == 1)
- return;
-
- uint16_t num_partition_pages = get_pages_per_slot_span();
- char* page_char_ptr = reinterpret_cast<char*>(page);
- for (uint16_t i = 1; i < num_partition_pages; ++i) {
- page_char_ptr += kPageMetadataSize;
- PartitionPage* secondary_page =
- reinterpret_cast<PartitionPage*>(page_char_ptr);
- secondary_page->page_offset = i;
- }
-}
-
-ALWAYS_INLINE char* PartitionBucket::AllocAndFillFreelist(PartitionPage* page) {
- DCHECK(page != PartitionPage::get_sentinel_page());
- uint16_t num_slots = page->num_unprovisioned_slots;
- DCHECK(num_slots);
- // We should only get here when _every_ slot is either used or unprovisioned.
- // (The third state is "on the freelist". If we have a non-empty freelist, we
- // should not get here.)
- DCHECK(num_slots + page->num_allocated_slots == get_slots_per_span());
- // Similarly, make explicitly sure that the freelist is empty.
- DCHECK(!page->freelist_head);
- DCHECK(page->num_allocated_slots >= 0);
-
- size_t size = slot_size;
- char* base = reinterpret_cast<char*>(PartitionPage::ToPointer(page));
- char* return_object = base + (size * page->num_allocated_slots);
- char* first_freelist_pointer = return_object + size;
- char* first_freelist_pointer_extent =
- first_freelist_pointer + sizeof(PartitionFreelistEntry*);
- // Our goal is to fault as few system pages as possible. We calculate the
- // page containing the "end" of the returned slot, and then allow freelist
- // pointers to be written up to the end of that page.
- char* sub_page_limit = reinterpret_cast<char*>(
- RoundUpToSystemPage(reinterpret_cast<size_t>(first_freelist_pointer)));
- char* slots_limit = return_object + (size * num_slots);
- char* freelist_limit = sub_page_limit;
- if (UNLIKELY(slots_limit < freelist_limit))
- freelist_limit = slots_limit;
-
- uint16_t num_new_freelist_entries = 0;
- if (LIKELY(first_freelist_pointer_extent <= freelist_limit)) {
- // Only consider used space in the slot span. If we consider wasted
- // space, we may get an off-by-one when a freelist pointer fits in the
- // wasted space, but a slot does not.
- // We know we can fit at least one freelist pointer.
- num_new_freelist_entries = 1;
- // Any further entries require space for the whole slot span.
- num_new_freelist_entries += static_cast<uint16_t>(
- (freelist_limit - first_freelist_pointer_extent) / size);
- }
-
- // We always return an object slot -- that's the +1 below.
- // We do not neccessarily create any new freelist entries, because we cross
- // sub page boundaries frequently for large bucket sizes.
- DCHECK(num_new_freelist_entries + 1 <= num_slots);
- num_slots -= (num_new_freelist_entries + 1);
- page->num_unprovisioned_slots = num_slots;
- page->num_allocated_slots++;
-
- if (LIKELY(num_new_freelist_entries)) {
- char* freelist_pointer = first_freelist_pointer;
- PartitionFreelistEntry* entry =
- reinterpret_cast<PartitionFreelistEntry*>(freelist_pointer);
- page->freelist_head = entry;
- while (--num_new_freelist_entries) {
- freelist_pointer += size;
- PartitionFreelistEntry* next_entry =
- reinterpret_cast<PartitionFreelistEntry*>(freelist_pointer);
- entry->next = PartitionFreelistEntry::Encode(next_entry);
- entry = next_entry;
- }
- entry->next = PartitionFreelistEntry::Encode(nullptr);
- } else {
- page->freelist_head = nullptr;
- }
- return return_object;
-}
-
-bool PartitionBucket::SetNewActivePage() {
- PartitionPage* page = active_pages_head;
- if (page == PartitionPage::get_sentinel_page())
- return false;
-
- PartitionPage* next_page;
-
- for (; page; page = next_page) {
- next_page = page->next_page;
- DCHECK(page->bucket == this);
- DCHECK(page != empty_pages_head);
- DCHECK(page != decommitted_pages_head);
-
- if (LIKELY(page->is_active())) {
- // This page is usable because it has freelist entries, or has
- // unprovisioned slots we can create freelist entries from.
- active_pages_head = page;
- return true;
- }
-
- // Deal with empty and decommitted pages.
- if (LIKELY(page->is_empty())) {
- page->next_page = empty_pages_head;
- empty_pages_head = page;
- } else if (LIKELY(page->is_decommitted())) {
- page->next_page = decommitted_pages_head;
- decommitted_pages_head = page;
- } else {
- DCHECK(page->is_full());
- // If we get here, we found a full page. Skip over it too, and also
- // tag it as full (via a negative value). We need it tagged so that
- // free'ing can tell, and move it back into the active page list.
- page->num_allocated_slots = -page->num_allocated_slots;
- ++num_full_pages;
- // num_full_pages is a uint16_t for efficient packing so guard against
- // overflow to be safe.
- if (UNLIKELY(!num_full_pages))
- OnFull();
- // Not necessary but might help stop accidents.
- page->next_page = nullptr;
- }
- }
-
- active_pages_head = PartitionPage::get_sentinel_page();
- return false;
-}
-
-void* PartitionBucket::SlowPathAlloc(PartitionRootBase* root,
- int flags,
- size_t size,
- bool* is_already_zeroed) {
- // The slow path is called when the freelist is empty.
- DCHECK(!active_pages_head->freelist_head);
-
- PartitionPage* new_page = nullptr;
- *is_already_zeroed = false;
-
- // For the PartitionRootGeneric::Alloc() API, we have a bunch of buckets
- // marked as special cases. We bounce them through to the slow path so that
- // we can still have a blazing fast hot path due to lack of corner-case
- // branches.
- //
- // Note: The ordering of the conditionals matter! In particular,
- // SetNewActivePage() has a side-effect even when returning
- // false where it sweeps the active page list and may move things into
- // the empty or decommitted lists which affects the subsequent conditional.
- bool return_null = flags & PartitionAllocReturnNull;
- if (UNLIKELY(is_direct_mapped())) {
- DCHECK(size > kGenericMaxBucketed);
- DCHECK(this == get_sentinel_bucket());
- DCHECK(active_pages_head == PartitionPage::get_sentinel_page());
- if (size > GenericMaxDirectMapped()) {
- if (return_null)
- return nullptr;
- PartitionExcessiveAllocationSize(size);
- }
- new_page = PartitionDirectMap(root, flags, size);
- *is_already_zeroed = true;
- } else if (LIKELY(SetNewActivePage())) {
- // First, did we find an active page in the active pages list?
- new_page = active_pages_head;
- DCHECK(new_page->is_active());
- } else if (LIKELY(empty_pages_head != nullptr) ||
- LIKELY(decommitted_pages_head != nullptr)) {
- // Second, look in our lists of empty and decommitted pages.
- // Check empty pages first, which are preferred, but beware that an
- // empty page might have been decommitted.
- while (LIKELY((new_page = empty_pages_head) != nullptr)) {
- DCHECK(new_page->bucket == this);
- DCHECK(new_page->is_empty() || new_page->is_decommitted());
- empty_pages_head = new_page->next_page;
- // Accept the empty page unless it got decommitted.
- if (new_page->freelist_head) {
- new_page->next_page = nullptr;
- break;
- }
- DCHECK(new_page->is_decommitted());
- new_page->next_page = decommitted_pages_head;
- decommitted_pages_head = new_page;
- }
- if (UNLIKELY(!new_page) && LIKELY(decommitted_pages_head != nullptr)) {
- new_page = decommitted_pages_head;
- DCHECK(new_page->bucket == this);
- DCHECK(new_page->is_decommitted());
- decommitted_pages_head = new_page->next_page;
- void* addr = PartitionPage::ToPointer(new_page);
- root->RecommitSystemPages(addr, new_page->bucket->get_bytes_per_span());
- new_page->Reset();
- // TODO(https://crbug.com/890752): Optimizing here might cause pages to
- // not be zeroed.
- // *is_already_zeroed = true;
- }
- DCHECK(new_page);
- } else {
- // Third. If we get here, we need a brand new page.
- uint16_t num_partition_pages = get_pages_per_slot_span();
- void* raw_pages = AllocNewSlotSpan(root, flags, num_partition_pages);
- if (LIKELY(raw_pages != nullptr)) {
- new_page = PartitionPage::FromPointerNoAlignmentCheck(raw_pages);
- InitializeSlotSpan(new_page);
- // TODO(https://crbug.com/890752): Optimizing here causes pages to not be
- // zeroed on at least macOS.
- // *is_already_zeroed = true;
- }
- }
-
- // Bail if we had a memory allocation failure.
- if (UNLIKELY(!new_page)) {
- DCHECK(active_pages_head == PartitionPage::get_sentinel_page());
- if (return_null)
- return nullptr;
- root->OutOfMemory(size);
- }
-
- // TODO(ajwong): Is there a way to avoid the reading of bucket here?
- // It seems like in many of the conditional branches above, |this| ==
- // |new_page->bucket|. Maybe pull this into another function?
- PartitionBucket* bucket = new_page->bucket;
- DCHECK(bucket != get_sentinel_bucket());
- bucket->active_pages_head = new_page;
- new_page->set_raw_size(size);
-
- // If we found an active page with free slots, or an empty page, we have a
- // usable freelist head.
- if (LIKELY(new_page->freelist_head != nullptr)) {
- PartitionFreelistEntry* entry = new_page->freelist_head;
- PartitionFreelistEntry* new_head =
- EncodedPartitionFreelistEntry::Decode(entry->next);
- new_page->freelist_head = new_head;
- new_page->num_allocated_slots++;
- return entry;
- }
- // Otherwise, we need to build the freelist.
- DCHECK(new_page->num_unprovisioned_slots);
- return AllocAndFillFreelist(new_page);
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/partition_bucket.h b/third_party/base/allocator/partition_allocator/partition_bucket.h
deleted file mode 100644
index 8bcddb7..0000000
--- a/third_party/base/allocator/partition_allocator/partition_bucket.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_BUCKET_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_BUCKET_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/base_export.h"
-#include "third_party/base/check.h"
-#include "third_party/base/compiler_specific.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-struct PartitionPage;
-struct PartitionRootBase;
-
-struct PartitionBucket {
- // Accessed most in hot path => goes first.
- PartitionPage* active_pages_head;
-
- PartitionPage* empty_pages_head;
- PartitionPage* decommitted_pages_head;
- uint32_t slot_size;
- uint32_t num_system_pages_per_slot_span : 8;
- uint32_t num_full_pages : 24;
-
- // Public API.
- void Init(uint32_t new_slot_size);
-
- // Sets |is_already_zeroed| to true if the allocation was satisfied by
- // requesting (a) new page(s) from the operating system, or false otherwise.
- // This enables an optimization for when callers use |PartitionAllocZeroFill|:
- // there is no need to call memset on fresh pages; the OS has already zeroed
- // them. (See |PartitionRootBase::AllocFromBucket|.)
- //
- // Note the matching Free() functions are in PartitionPage.
- BASE_EXPORT NOINLINE void* SlowPathAlloc(PartitionRootBase* root,
- int flags,
- size_t size,
- bool* is_already_zeroed);
-
- ALWAYS_INLINE bool is_direct_mapped() const {
- return !num_system_pages_per_slot_span;
- }
- ALWAYS_INLINE size_t get_bytes_per_span() const {
- // TODO(ajwong): Change to CheckedMul. https://crbug.com/787153
- // https://crbug.com/680657
- return num_system_pages_per_slot_span * SystemPageSize();
- }
- ALWAYS_INLINE uint16_t get_slots_per_span() const {
- // TODO(ajwong): Change to CheckedMul. https://crbug.com/787153
- // https://crbug.com/680657
- return static_cast<uint16_t>(get_bytes_per_span() / slot_size);
- }
-
- static ALWAYS_INLINE size_t get_direct_map_size(size_t size) {
- // Caller must check that the size is not above the GenericMaxDirectMapped()
- // limit before calling. This also guards against integer overflow in the
- // calculation here.
- DCHECK(size <= GenericMaxDirectMapped());
- return (size + SystemPageOffsetMask()) & SystemPageBaseMask();
- }
-
- // TODO(ajwong): Can this be made private? https://crbug.com/787153
- static PartitionBucket* get_sentinel_bucket();
-
- // This helper function scans a bucket's active page list for a suitable new
- // active page. When it finds a suitable new active page (one that has
- // free slots and is not empty), it is set as the new active page. If there
- // is no suitable new active page, the current active page is set to
- // PartitionPage::get_sentinel_page(). As potential pages are scanned, they
- // are tidied up according to their state. Empty pages are swept on to the
- // empty page list, decommitted pages on to the decommitted page list and full
- // pages are unlinked from any list.
- //
- // This is where the guts of the bucket maintenance is done!
- bool SetNewActivePage();
-
- private:
- static void OutOfMemory(const PartitionRootBase* root);
- static void OutOfMemoryWithLotsOfUncommitedPages();
-
- static NOINLINE void OnFull();
-
- // Returns a natural number of PartitionPages (calculated by
- // get_system_pages_per_slot_span()) to allocate from the current
- // SuperPage when the bucket runs out of slots.
- ALWAYS_INLINE uint16_t get_pages_per_slot_span();
-
- // Returns the number of system pages in a slot span.
- //
- // The calculation attemps to find the best number of System Pages to
- // allocate for the given slot_size to minimize wasted space. It uses a
- // heuristic that looks at number of bytes wasted after the last slot and
- // attempts to account for the PTE usage of each System Page.
- uint8_t get_system_pages_per_slot_span();
-
- // Allocates a new slot span with size |num_partition_pages| from the
- // current extent. Metadata within this slot span will be uninitialized.
- // Returns nullptr on error.
- ALWAYS_INLINE void* AllocNewSlotSpan(PartitionRootBase* root,
- int flags,
- uint16_t num_partition_pages);
-
- // Each bucket allocates a slot span when it runs out of slots.
- // A slot span's size is equal to get_pages_per_slot_span() number of
- // PartitionPages. This function initializes all PartitionPage within the
- // span to point to the first PartitionPage which holds all the metadata
- // for the span and registers this bucket as the owner of the span. It does
- // NOT put the slots into the bucket's freelist.
- ALWAYS_INLINE void InitializeSlotSpan(PartitionPage* page);
-
- // Allocates one slot from the given |page| and then adds the remainder to
- // the current bucket. If the |page| was freshly allocated, it must have been
- // passed through InitializeSlotSpan() first.
- ALWAYS_INLINE char* AllocAndFillFreelist(PartitionPage* page);
-
- static PartitionBucket sentinel_bucket_;
-};
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_BUCKET_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_cookie.h b/third_party/base/allocator/partition_allocator/partition_cookie.h
deleted file mode 100644
index 3c2b688..0000000
--- a/third_party/base/allocator/partition_allocator/partition_cookie.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_COOKIE_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_COOKIE_H_
-
-#include "third_party/base/check.h"
-#include "third_party/base/compiler_specific.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-#if DCHECK_IS_ON()
-// Handles alignment up to XMM instructions on Intel.
-static constexpr size_t kCookieSize = 16;
-
-static constexpr unsigned char kCookieValue[kCookieSize] = {
- 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xD0, 0x0D,
- 0x13, 0x37, 0xF0, 0x05, 0xBA, 0x11, 0xAB, 0x1E};
-#endif
-
-ALWAYS_INLINE void PartitionCookieCheckValue(void* ptr) {
-#if DCHECK_IS_ON()
- unsigned char* cookie_ptr = reinterpret_cast<unsigned char*>(ptr);
- for (size_t i = 0; i < kCookieSize; ++i, ++cookie_ptr)
- DCHECK(*cookie_ptr == kCookieValue[i]);
-#endif
-}
-
-ALWAYS_INLINE size_t PartitionCookieSizeAdjustAdd(size_t size) {
-#if DCHECK_IS_ON()
- // Add space for cookies, checking for integer overflow. TODO(palmer):
- // Investigate the performance and code size implications of using
- // CheckedNumeric throughout PA.
- DCHECK(size + (2 * kCookieSize) > size);
- size += 2 * kCookieSize;
-#endif
- return size;
-}
-
-ALWAYS_INLINE void* PartitionCookieFreePointerAdjust(void* ptr) {
-#if DCHECK_IS_ON()
- // The value given to the application is actually just after the cookie.
- ptr = static_cast<char*>(ptr) - kCookieSize;
-#endif
- return ptr;
-}
-
-ALWAYS_INLINE size_t PartitionCookieSizeAdjustSubtract(size_t size) {
-#if DCHECK_IS_ON()
- // Remove space for cookies.
- DCHECK(size >= 2 * kCookieSize);
- size -= 2 * kCookieSize;
-#endif
- return size;
-}
-
-ALWAYS_INLINE void PartitionCookieWriteValue(void* ptr) {
-#if DCHECK_IS_ON()
- unsigned char* cookie_ptr = reinterpret_cast<unsigned char*>(ptr);
- for (size_t i = 0; i < kCookieSize; ++i, ++cookie_ptr)
- *cookie_ptr = kCookieValue[i];
-#endif
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_COOKIE_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_direct_map_extent.h b/third_party/base/allocator/partition_allocator/partition_direct_map_extent.h
deleted file mode 100644
index 192c5b4..0000000
--- a/third_party/base/allocator/partition_allocator/partition_direct_map_extent.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_DIRECT_MAP_EXTENT_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_DIRECT_MAP_EXTENT_H_
-
-#include "third_party/base/allocator/partition_allocator/partition_bucket.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-struct PartitionDirectMapExtent {
- PartitionDirectMapExtent* next_extent;
- PartitionDirectMapExtent* prev_extent;
- PartitionBucket* bucket;
- size_t map_size; // Mapped size, not including guard pages and meta-data.
-
- ALWAYS_INLINE static PartitionDirectMapExtent* FromPage(PartitionPage* page);
-};
-
-ALWAYS_INLINE PartitionDirectMapExtent* PartitionDirectMapExtent::FromPage(
- PartitionPage* page) {
- DCHECK(page->bucket->is_direct_mapped());
- return reinterpret_cast<PartitionDirectMapExtent*>(
- reinterpret_cast<char*>(page) + 3 * kPageMetadataSize);
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_DIRECT_MAP_EXTENT_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_freelist_entry.h b/third_party/base/allocator/partition_allocator/partition_freelist_entry.h
deleted file mode 100644
index 5d46f0f..0000000
--- a/third_party/base/allocator/partition_allocator/partition_freelist_entry.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_FREELIST_ENTRY_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_FREELIST_ENTRY_H_
-
-#include <stdint.h>
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/compiler_specific.h"
-#include "third_party/base/sys_byteorder.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-struct EncodedPartitionFreelistEntry;
-
-struct PartitionFreelistEntry {
- EncodedPartitionFreelistEntry* next;
-
- PartitionFreelistEntry() = delete;
- ~PartitionFreelistEntry() = delete;
-
- ALWAYS_INLINE static EncodedPartitionFreelistEntry* Encode(
- PartitionFreelistEntry* ptr) {
- return reinterpret_cast<EncodedPartitionFreelistEntry*>(Transform(ptr));
- }
-
- private:
- friend struct EncodedPartitionFreelistEntry;
- static ALWAYS_INLINE void* Transform(void* ptr) {
- // We use bswap on little endian as a fast mask for two reasons:
- // 1) If an object is freed and its vtable used where the attacker doesn't
- // get the chance to run allocations between the free and use, the vtable
- // dereference is likely to fault.
- // 2) If the attacker has a linear buffer overflow and elects to try and
- // corrupt a freelist pointer, partial pointer overwrite attacks are
- // thwarted.
- // For big endian, similar guarantees are arrived at with a negation.
-#if defined(ARCH_CPU_BIG_ENDIAN)
- uintptr_t masked = ~reinterpret_cast<uintptr_t>(ptr);
-#else
- uintptr_t masked = ByteSwapUintPtrT(reinterpret_cast<uintptr_t>(ptr));
-#endif
- return reinterpret_cast<void*>(masked);
- }
-};
-
-struct EncodedPartitionFreelistEntry {
- char scrambled[sizeof(PartitionFreelistEntry*)];
-
- EncodedPartitionFreelistEntry() = delete;
- ~EncodedPartitionFreelistEntry() = delete;
-
- ALWAYS_INLINE static PartitionFreelistEntry* Decode(
- EncodedPartitionFreelistEntry* ptr) {
- return reinterpret_cast<PartitionFreelistEntry*>(
- PartitionFreelistEntry::Transform(ptr));
- }
-};
-
-static_assert(sizeof(PartitionFreelistEntry) ==
- sizeof(EncodedPartitionFreelistEntry),
- "Should not have padding");
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_FREELIST_ENTRY_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_oom.cc b/third_party/base/allocator/partition_allocator/partition_oom.cc
deleted file mode 100644
index f93dae7..0000000
--- a/third_party/base/allocator/partition_allocator/partition_oom.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/partition_oom.h"
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/oom.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-void NOINLINE PartitionExcessiveAllocationSize(size_t size) {
- OOM_CRASH(size);
-}
-
-#if !defined(ARCH_CPU_64_BITS)
-NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size) {
- OOM_CRASH(size);
-}
-#endif
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/partition_oom.h b/third_party/base/allocator/partition_allocator/partition_oom.h
deleted file mode 100644
index 683358e..0000000
--- a/third_party/base/allocator/partition_allocator/partition_oom.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Holds functions for generating OOM errors from PartitionAlloc. This is
-// distinct from oom.h in that it is meant only for use in PartitionAlloc.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
-
-#include <stddef.h>
-
-#include "build/build_config.h"
-#include "third_party/base/compiler_specific.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-NOINLINE void PartitionExcessiveAllocationSize(size_t size);
-
-#if !defined(ARCH_CPU_64_BITS)
-NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size);
-#endif
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_page.cc b/third_party/base/allocator/partition_allocator/partition_page.cc
deleted file mode 100644
index 312c33b..0000000
--- a/third_party/base/allocator/partition_allocator/partition_page.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-
-#include "third_party/base/allocator/partition_allocator/partition_direct_map_extent.h"
-#include "third_party/base/allocator/partition_allocator/partition_root_base.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-namespace {
-
-ALWAYS_INLINE DeferredUnmap PartitionDirectUnmap(PartitionPage* page) {
- PartitionRootBase* root = PartitionRootBase::FromPage(page);
- const PartitionDirectMapExtent* extent =
- PartitionDirectMapExtent::FromPage(page);
- size_t unmap_size = extent->map_size;
-
- // Maintain the doubly-linked list of all direct mappings.
- if (extent->prev_extent) {
- DCHECK(extent->prev_extent->next_extent == extent);
- extent->prev_extent->next_extent = extent->next_extent;
- } else {
- root->direct_map_list = extent->next_extent;
- }
- if (extent->next_extent) {
- DCHECK(extent->next_extent->prev_extent == extent);
- extent->next_extent->prev_extent = extent->prev_extent;
- }
-
- // Add on the size of the trailing guard page and preceeding partition
- // page.
- unmap_size += PartitionPageSize() + SystemPageSize();
-
- size_t uncommitted_page_size = page->bucket->slot_size + SystemPageSize();
- root->DecreaseCommittedPages(uncommitted_page_size);
- DCHECK(root->total_size_of_direct_mapped_pages >= uncommitted_page_size);
- root->total_size_of_direct_mapped_pages -= uncommitted_page_size;
-
- DCHECK(!(unmap_size & PageAllocationGranularityOffsetMask()));
-
- char* ptr = reinterpret_cast<char*>(PartitionPage::ToPointer(page));
- // Account for the mapping starting a partition page before the actual
- // allocation address.
- ptr -= PartitionPageSize();
- return {ptr, unmap_size};
-}
-
-ALWAYS_INLINE void PartitionRegisterEmptyPage(PartitionPage* page) {
- DCHECK(page->is_empty());
- PartitionRootBase* root = PartitionRootBase::FromPage(page);
-
- // If the page is already registered as empty, give it another life.
- if (page->empty_cache_index != -1) {
- DCHECK(page->empty_cache_index >= 0);
- DCHECK(static_cast<unsigned>(page->empty_cache_index) < kMaxFreeableSpans);
- DCHECK(root->global_empty_page_ring[page->empty_cache_index] == page);
- root->global_empty_page_ring[page->empty_cache_index] = nullptr;
- }
-
- int16_t current_index = root->global_empty_page_ring_index;
- PartitionPage* page_to_decommit = root->global_empty_page_ring[current_index];
- // The page might well have been re-activated, filled up, etc. before we get
- // around to looking at it here.
- if (page_to_decommit)
- page_to_decommit->DecommitIfPossible(root);
-
- // We put the empty slot span on our global list of "pages that were once
- // empty". thus providing it a bit of breathing room to get re-used before
- // we really free it. This improves performance, particularly on Mac OS X
- // which has subpar memory management performance.
- root->global_empty_page_ring[current_index] = page;
- page->empty_cache_index = current_index;
- ++current_index;
- if (current_index == kMaxFreeableSpans)
- current_index = 0;
- root->global_empty_page_ring_index = current_index;
-}
-
-} // namespace
-
-// static
-PartitionPage PartitionPage::sentinel_page_;
-
-PartitionPage* PartitionPage::get_sentinel_page() {
- return &sentinel_page_;
-}
-
-DeferredUnmap PartitionPage::FreeSlowPath() {
- DCHECK(this != get_sentinel_page());
- if (LIKELY(num_allocated_slots == 0)) {
- // Page became fully unused.
- if (UNLIKELY(bucket->is_direct_mapped())) {
- return PartitionDirectUnmap(this);
- }
- // If it's the current active page, change it. We bounce the page to
- // the empty list as a force towards defragmentation.
- if (LIKELY(this == bucket->active_pages_head))
- bucket->SetNewActivePage();
- DCHECK(bucket->active_pages_head != this);
-
- set_raw_size(0);
- DCHECK(!get_raw_size());
-
- PartitionRegisterEmptyPage(this);
- } else {
- DCHECK(!bucket->is_direct_mapped());
- // Ensure that the page is full. That's the only valid case if we
- // arrive here.
- DCHECK(num_allocated_slots < 0);
- // A transition of num_allocated_slots from 0 to -1 is not legal, and
- // likely indicates a double-free.
- CHECK(num_allocated_slots != -1);
- num_allocated_slots = -num_allocated_slots - 2;
- DCHECK(num_allocated_slots == bucket->get_slots_per_span() - 1);
- // Fully used page became partially used. It must be put back on the
- // non-full page list. Also make it the current page to increase the
- // chances of it being filled up again. The old current page will be
- // the next page.
- DCHECK(!next_page);
- if (LIKELY(bucket->active_pages_head != get_sentinel_page()))
- next_page = bucket->active_pages_head;
- bucket->active_pages_head = this;
- --bucket->num_full_pages;
- // Special case: for a partition page with just a single slot, it may
- // now be empty and we want to run it through the empty logic.
- if (UNLIKELY(num_allocated_slots == 0))
- return FreeSlowPath();
- }
- return {};
-}
-
-void PartitionPage::Decommit(PartitionRootBase* root) {
- DCHECK(is_empty());
- DCHECK(!bucket->is_direct_mapped());
- void* addr = PartitionPage::ToPointer(this);
- root->DecommitSystemPages(addr, bucket->get_bytes_per_span());
-
- // We actually leave the decommitted page in the active list. We'll sweep
- // it on to the decommitted page list when we next walk the active page
- // list.
- // Pulling this trick enables us to use a singly-linked page list for all
- // cases, which is critical in keeping the page metadata structure down to
- // 32 bytes in size.
- freelist_head = nullptr;
- num_unprovisioned_slots = 0;
- DCHECK(is_decommitted());
-}
-
-void PartitionPage::DecommitIfPossible(PartitionRootBase* root) {
- DCHECK(empty_cache_index >= 0);
- DCHECK(static_cast<unsigned>(empty_cache_index) < kMaxFreeableSpans);
- DCHECK(this == root->global_empty_page_ring[empty_cache_index]);
- empty_cache_index = -1;
- if (is_empty())
- Decommit(root);
-}
-
-void DeferredUnmap::Unmap() {
- FreePages(ptr, size);
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/partition_page.h b/third_party/base/allocator/partition_allocator/partition_page.h
deleted file mode 100644
index 4e99753..0000000
--- a/third_party/base/allocator/partition_allocator/partition_page.h
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_PAGE_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_PAGE_H_
-
-#include <string.h>
-
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/allocator/partition_allocator/partition_bucket.h"
-#include "third_party/base/allocator/partition_allocator/partition_cookie.h"
-#include "third_party/base/allocator/partition_allocator/partition_freelist_entry.h"
-#include "third_party/base/allocator/partition_allocator/random.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-struct PartitionRootBase;
-
-// PartitionPage::Free() defers unmapping a large page until the lock is
-// released. Callers of PartitionPage::Free() must invoke Run().
-// TODO(1061437): Reconsider once the new locking mechanism is implemented.
-struct DeferredUnmap {
- void* ptr = nullptr;
- size_t size = 0;
- // In most cases there is no page to unmap and ptr == nullptr. This function
- // is inlined to avoid the overhead of a function call in the common case.
- ALWAYS_INLINE void Run();
-
- private:
- BASE_EXPORT NOINLINE void Unmap();
-};
-
-// Some notes on page states. A page can be in one of four major states:
-// 1) Active.
-// 2) Full.
-// 3) Empty.
-// 4) Decommitted.
-// An active page has available free slots. A full page has no free slots. An
-// empty page has no free slots, and a decommitted page is an empty page that
-// had its backing memory released back to the system.
-// There are two linked lists tracking the pages. The "active page" list is an
-// approximation of a list of active pages. It is an approximation because
-// full, empty and decommitted pages may briefly be present in the list until
-// we next do a scan over it.
-// The "empty page" list is an accurate list of pages which are either empty
-// or decommitted.
-//
-// The significant page transitions are:
-// - free() will detect when a full page has a slot free()'d and immediately
-// return the page to the head of the active list.
-// - free() will detect when a page is fully emptied. It _may_ add it to the
-// empty list or it _may_ leave it on the active list until a future list scan.
-// - malloc() _may_ scan the active page list in order to fulfil the request.
-// If it does this, full, empty and decommitted pages encountered will be
-// booted out of the active list. If there are no suitable active pages found,
-// an empty or decommitted page (if one exists) will be pulled from the empty
-// list on to the active list.
-//
-// TODO(ajwong): Evaluate if this should be named PartitionSlotSpanMetadata or
-// similar. If so, all uses of the term "page" in comments, member variables,
-// local variables, and documentation that refer to this concept should be
-// updated.
-struct PartitionPage {
- PartitionFreelistEntry* freelist_head;
- PartitionPage* next_page;
- PartitionBucket* bucket;
- // Deliberately signed, 0 for empty or decommitted page, -n for full pages:
- int16_t num_allocated_slots;
- uint16_t num_unprovisioned_slots;
- uint16_t page_offset;
- int16_t empty_cache_index; // -1 if not in the empty cache.
-
- // Public API
-
- // Note the matching Alloc() functions are in PartitionPage.
- // Callers must invoke DeferredUnmap::Run() after releasing the lock.
- [[nodiscard]] BASE_EXPORT NOINLINE DeferredUnmap FreeSlowPath();
- [[nodiscard]] ALWAYS_INLINE DeferredUnmap Free(void* ptr);
-
- void Decommit(PartitionRootBase* root);
- void DecommitIfPossible(PartitionRootBase* root);
-
- // Pointer manipulation functions. These must be static as the input |page|
- // pointer may be the result of an offset calculation and therefore cannot
- // be trusted. The objective of these functions is to sanitize this input.
- ALWAYS_INLINE static void* ToPointer(const PartitionPage* page);
- ALWAYS_INLINE static PartitionPage* FromPointerNoAlignmentCheck(void* ptr);
- ALWAYS_INLINE static PartitionPage* FromPointer(void* ptr);
-
- ALWAYS_INLINE const size_t* get_raw_size_ptr() const;
- ALWAYS_INLINE size_t* get_raw_size_ptr() {
- return const_cast<size_t*>(
- const_cast<const PartitionPage*>(this)->get_raw_size_ptr());
- }
-
- ALWAYS_INLINE size_t get_raw_size() const;
- ALWAYS_INLINE void set_raw_size(size_t size);
-
- ALWAYS_INLINE void Reset();
-
- // TODO(ajwong): Can this be made private? https://crbug.com/787153
- BASE_EXPORT static PartitionPage* get_sentinel_page();
-
- // Page State accessors.
- // Note that it's only valid to call these functions on pages found on one of
- // the page lists. Specifically, you can't call these functions on full pages
- // that were detached from the active list.
- //
- // This restriction provides the flexibity for some of the status fields to
- // be repurposed when a page is taken off a list. See the negation of
- // |num_allocated_slots| when a full page is removed from the active list
- // for an example of such repurposing.
- ALWAYS_INLINE bool is_active() const;
- ALWAYS_INLINE bool is_full() const;
- ALWAYS_INLINE bool is_empty() const;
- ALWAYS_INLINE bool is_decommitted() const;
-
- private:
- // g_sentinel_page is used as a sentinel to indicate that there is no page
- // in the active page list. We can use nullptr, but in that case we need
- // to add a null-check branch to the hot allocation path. We want to avoid
- // that.
- //
- // Note, this declaration is kept in the header as opposed to an anonymous
- // namespace so the getter can be fully inlined.
- static PartitionPage sentinel_page_;
-};
-static_assert(sizeof(PartitionPage) <= kPageMetadataSize,
- "PartitionPage must be able to fit in a metadata slot");
-
-ALWAYS_INLINE char* PartitionSuperPageToMetadataArea(char* ptr) {
- uintptr_t pointer_as_uint = reinterpret_cast<uintptr_t>(ptr);
- DCHECK(!(pointer_as_uint & kSuperPageOffsetMask));
- // The metadata area is exactly one system page (the guard page) into the
- // super page.
- return reinterpret_cast<char*>(pointer_as_uint + SystemPageSize());
-}
-
-ALWAYS_INLINE PartitionPage* PartitionPage::FromPointerNoAlignmentCheck(
- void* ptr) {
- uintptr_t pointer_as_uint = reinterpret_cast<uintptr_t>(ptr);
- char* super_page_ptr =
- reinterpret_cast<char*>(pointer_as_uint & kSuperPageBaseMask);
- uintptr_t partition_page_index =
- (pointer_as_uint & kSuperPageOffsetMask) >> PartitionPageShift();
- // Index 0 is invalid because it is the metadata and guard area and
- // the last index is invalid because it is a guard page.
- DCHECK(partition_page_index);
- DCHECK(partition_page_index < NumPartitionPagesPerSuperPage() - 1);
- PartitionPage* page = reinterpret_cast<PartitionPage*>(
- PartitionSuperPageToMetadataArea(super_page_ptr) +
- (partition_page_index << kPageMetadataShift));
- // Partition pages in the same slot span can share the same page object.
- // Adjust for that.
- size_t delta = page->page_offset << kPageMetadataShift;
- page =
- reinterpret_cast<PartitionPage*>(reinterpret_cast<char*>(page) - delta);
- return page;
-}
-
-// Resturns start of the slot span for the PartitionPage.
-ALWAYS_INLINE void* PartitionPage::ToPointer(const PartitionPage* page) {
- uintptr_t pointer_as_uint = reinterpret_cast<uintptr_t>(page);
-
- uintptr_t super_page_offset = (pointer_as_uint & kSuperPageOffsetMask);
-
- // A valid |page| must be past the first guard System page and within
- // the following metadata region.
- DCHECK(super_page_offset > SystemPageSize());
- // Must be less than total metadata region.
- DCHECK(super_page_offset <
- SystemPageSize() +
- (NumPartitionPagesPerSuperPage() * kPageMetadataSize));
- uintptr_t partition_page_index =
- (super_page_offset - SystemPageSize()) >> kPageMetadataShift;
- // Index 0 is invalid because it is the superpage extent metadata and the
- // last index is invalid because the whole PartitionPage is set as guard
- // pages for the metadata region.
- DCHECK(partition_page_index);
- DCHECK(partition_page_index < NumPartitionPagesPerSuperPage() - 1);
- uintptr_t super_page_base = (pointer_as_uint & kSuperPageBaseMask);
- void* ret = reinterpret_cast<void*>(
- super_page_base + (partition_page_index << PartitionPageShift()));
- return ret;
-}
-
-ALWAYS_INLINE PartitionPage* PartitionPage::FromPointer(void* ptr) {
- PartitionPage* page = PartitionPage::FromPointerNoAlignmentCheck(ptr);
- // Checks that the pointer is a multiple of bucket size.
- DCHECK(!((reinterpret_cast<uintptr_t>(ptr) -
- reinterpret_cast<uintptr_t>(PartitionPage::ToPointer(page))) %
- page->bucket->slot_size));
- return page;
-}
-
-ALWAYS_INLINE const size_t* PartitionPage::get_raw_size_ptr() const {
- // For single-slot buckets which span more than one partition page, we
- // have some spare metadata space to store the raw allocation size. We
- // can use this to report better statistics.
- if (bucket->slot_size <= MaxSystemPagesPerSlotSpan() * SystemPageSize())
- return nullptr;
-
- DCHECK((bucket->slot_size % SystemPageSize()) == 0);
- DCHECK(bucket->is_direct_mapped() || bucket->get_slots_per_span() == 1);
-
- const PartitionPage* the_next_page = this + 1;
- return reinterpret_cast<const size_t*>(&the_next_page->freelist_head);
-}
-
-ALWAYS_INLINE size_t PartitionPage::get_raw_size() const {
- const size_t* ptr = get_raw_size_ptr();
- if (UNLIKELY(ptr != nullptr))
- return *ptr;
- return 0;
-}
-
-ALWAYS_INLINE DeferredUnmap PartitionPage::Free(void* ptr) {
-#if DCHECK_IS_ON()
- size_t slot_size = bucket->slot_size;
- const size_t raw_size = get_raw_size();
- if (raw_size) {
- slot_size = raw_size;
- }
-
- // If these asserts fire, you probably corrupted memory.
- PartitionCookieCheckValue(ptr);
- PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
- kCookieSize);
-
- memset(ptr, kFreedByte, slot_size);
-#endif
-
- DCHECK(num_allocated_slots);
- // Catches an immediate double free.
- CHECK(ptr != freelist_head);
- // Look for double free one level deeper in debug.
- DCHECK(!freelist_head ||
- ptr != EncodedPartitionFreelistEntry::Decode(freelist_head->next));
- internal::PartitionFreelistEntry* entry =
- static_cast<internal::PartitionFreelistEntry*>(ptr);
- entry->next = internal::PartitionFreelistEntry::Encode(freelist_head);
- freelist_head = entry;
- --num_allocated_slots;
- if (UNLIKELY(num_allocated_slots <= 0)) {
- return FreeSlowPath();
- } else {
- // All single-slot allocations must go through the slow path to
- // correctly update the size metadata.
- DCHECK(get_raw_size() == 0);
- }
- return {};
-}
-
-ALWAYS_INLINE bool PartitionPage::is_active() const {
- DCHECK(this != get_sentinel_page());
- DCHECK(!page_offset);
- return (num_allocated_slots > 0 &&
- (freelist_head || num_unprovisioned_slots));
-}
-
-ALWAYS_INLINE bool PartitionPage::is_full() const {
- DCHECK(this != get_sentinel_page());
- DCHECK(!page_offset);
- bool ret = (num_allocated_slots == bucket->get_slots_per_span());
- if (ret) {
- DCHECK(!freelist_head);
- DCHECK(!num_unprovisioned_slots);
- }
- return ret;
-}
-
-ALWAYS_INLINE bool PartitionPage::is_empty() const {
- DCHECK(this != get_sentinel_page());
- DCHECK(!page_offset);
- return (!num_allocated_slots && freelist_head);
-}
-
-ALWAYS_INLINE bool PartitionPage::is_decommitted() const {
- DCHECK(this != get_sentinel_page());
- DCHECK(!page_offset);
- bool ret = (!num_allocated_slots && !freelist_head);
- if (ret) {
- DCHECK(!num_unprovisioned_slots);
- DCHECK(empty_cache_index == -1);
- }
- return ret;
-}
-
-ALWAYS_INLINE void PartitionPage::set_raw_size(size_t size) {
- size_t* raw_size_ptr = get_raw_size_ptr();
- if (UNLIKELY(raw_size_ptr != nullptr))
- *raw_size_ptr = size;
-}
-
-ALWAYS_INLINE void PartitionPage::Reset() {
- DCHECK(is_decommitted());
-
- num_unprovisioned_slots = bucket->get_slots_per_span();
- DCHECK(num_unprovisioned_slots);
-
- next_page = nullptr;
-}
-
-ALWAYS_INLINE void DeferredUnmap::Run() {
- if (UNLIKELY(ptr)) {
- Unmap();
- }
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_PAGE_H_
diff --git a/third_party/base/allocator/partition_allocator/partition_root_base.cc b/third_party/base/allocator/partition_allocator/partition_root_base.cc
deleted file mode 100644
index 5434347..0000000
--- a/third_party/base/allocator/partition_allocator/partition_root_base.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/partition_root_base.h"
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/oom.h"
-#include "third_party/base/allocator/partition_allocator/partition_oom.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-
-namespace pdfium {
-namespace base {
-namespace internal {
-
-NOINLINE void PartitionRootBase::OutOfMemory(size_t size) {
-#if !defined(ARCH_CPU_64_BITS)
- // Check whether this OOM is due to a lot of super pages that are allocated
- // but not committed, probably due to http://crbug.com/421387.
- if (total_size_of_super_pages + total_size_of_direct_mapped_pages -
- total_size_of_committed_pages >
- kReasonableSizeOfUnusedPages) {
- PartitionOutOfMemoryWithLotsOfUncommitedPages(size);
- }
-#endif
- if (PartitionRootBase::g_oom_handling_function)
- (*PartitionRootBase::g_oom_handling_function)(size);
- OOM_CRASH(size);
-}
-
-void PartitionRootBase::DecommitEmptyPages() {
- for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
- internal::PartitionPage* page = global_empty_page_ring[i];
- if (page)
- page->DecommitIfPossible(this);
- global_empty_page_ring[i] = nullptr;
- }
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/partition_root_base.h b/third_party/base/allocator/partition_allocator/partition_root_base.h
deleted file mode 100644
index e394c3a..0000000
--- a/third_party/base/allocator/partition_allocator/partition_root_base.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ROOT_BASE_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ROOT_BASE_H_
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/page_allocator.h"
-#include "third_party/base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "third_party/base/allocator/partition_allocator/partition_bucket.h"
-#include "third_party/base/allocator/partition_allocator/partition_direct_map_extent.h"
-#include "third_party/base/allocator/partition_allocator/partition_page.h"
-
-namespace pdfium {
-namespace base {
-
-typedef void (*OomFunction)(size_t);
-
-namespace internal {
-
-struct PartitionPage;
-struct PartitionRootBase;
-
-// An "extent" is a span of consecutive superpages. We link to the partition's
-// next extent (if there is one) to the very start of a superpage's metadata
-// area.
-struct PartitionSuperPageExtentEntry {
- PartitionRootBase* root;
- char* super_page_base;
- char* super_pages_end;
- PartitionSuperPageExtentEntry* next;
-};
-static_assert(
- sizeof(PartitionSuperPageExtentEntry) <= kPageMetadataSize,
- "PartitionSuperPageExtentEntry must be able to fit in a metadata slot");
-
-struct BASE_EXPORT PartitionRootBase {
- PartitionRootBase();
- virtual ~PartitionRootBase();
- size_t total_size_of_committed_pages = 0;
- size_t total_size_of_super_pages = 0;
- size_t total_size_of_direct_mapped_pages = 0;
- // Invariant: total_size_of_committed_pages <=
- // total_size_of_super_pages +
- // total_size_of_direct_mapped_pages.
- unsigned num_buckets = 0;
- unsigned max_allocation = 0;
- bool initialized = false;
- char* next_super_page = nullptr;
- char* next_partition_page = nullptr;
- char* next_partition_page_end = nullptr;
- PartitionSuperPageExtentEntry* current_extent = nullptr;
- PartitionSuperPageExtentEntry* first_extent = nullptr;
- PartitionDirectMapExtent* direct_map_list = nullptr;
- PartitionPage* global_empty_page_ring[kMaxFreeableSpans] = {};
- int16_t global_empty_page_ring_index = 0;
- uintptr_t inverted_self = 0;
-
- // Public API
-
- // Allocates out of the given bucket. Properly, this function should probably
- // be in PartitionBucket, but because the implementation needs to be inlined
- // for performance, and because it needs to inspect PartitionPage,
- // it becomes impossible to have it in PartitionBucket as this causes a
- // cyclical dependency on PartitionPage function implementations.
- //
- // Moving it a layer lower couples PartitionRootBase and PartitionBucket, but
- // preserves the layering of the includes.
- //
- // Note the matching Free() functions are in PartitionPage.
- ALWAYS_INLINE void* AllocFromBucket(PartitionBucket* bucket,
- int flags,
- size_t size);
-
- ALWAYS_INLINE static bool IsValidPage(PartitionPage* page);
- ALWAYS_INLINE static PartitionRootBase* FromPage(PartitionPage* page);
-
- // g_oom_handling_function is invoked when PartitionAlloc hits OutOfMemory.
- static OomFunction g_oom_handling_function;
- NOINLINE void OutOfMemory(size_t size);
-
- ALWAYS_INLINE void IncreaseCommittedPages(size_t len);
- ALWAYS_INLINE void DecreaseCommittedPages(size_t len);
- ALWAYS_INLINE void DecommitSystemPages(void* address, size_t length);
- ALWAYS_INLINE void RecommitSystemPages(void* address, size_t length);
-
- // Frees memory from this partition, if possible, by decommitting pages.
- // |flags| is an OR of base::PartitionPurgeFlags.
- virtual void PurgeMemory(int flags) = 0;
- void DecommitEmptyPages();
-};
-
-ALWAYS_INLINE void* PartitionRootBase::AllocFromBucket(PartitionBucket* bucket,
- int flags,
- size_t size) {
- bool zero_fill = flags & PartitionAllocZeroFill;
- bool is_already_zeroed = false;
-
- PartitionPage* page = bucket->active_pages_head;
- // Check that this page is neither full nor freed.
- DCHECK(page->num_allocated_slots >= 0);
- void* ret = page->freelist_head;
- if (LIKELY(ret != 0)) {
- // If these DCHECKs fire, you probably corrupted memory. TODO(palmer): See
- // if we can afford to make these CHECKs.
- DCHECK(PartitionRootBase::IsValidPage(page));
-
- // All large allocations must go through the slow path to correctly update
- // the size metadata.
- DCHECK(page->get_raw_size() == 0);
- internal::PartitionFreelistEntry* new_head =
- internal::EncodedPartitionFreelistEntry::Decode(
- page->freelist_head->next);
- page->freelist_head = new_head;
- page->num_allocated_slots++;
- } else {
- ret = bucket->SlowPathAlloc(this, flags, size, &is_already_zeroed);
- // TODO(palmer): See if we can afford to make this a CHECK.
- DCHECK(!ret ||
- PartitionRootBase::IsValidPage(PartitionPage::FromPointer(ret)));
- }
-
-#if DCHECK_IS_ON()
- if (!ret) {
- return nullptr;
- }
-
- page = PartitionPage::FromPointer(ret);
- // TODO(ajwong): Can |page->bucket| ever not be |this|? If not, can this just
- // be bucket->slot_size?
- size_t new_slot_size = page->bucket->slot_size;
- size_t raw_size = page->get_raw_size();
- if (raw_size) {
- DCHECK(raw_size == size);
- new_slot_size = raw_size;
- }
- size_t no_cookie_size = PartitionCookieSizeAdjustSubtract(new_slot_size);
- char* char_ret = static_cast<char*>(ret);
- // The value given to the application is actually just after the cookie.
- ret = char_ret + kCookieSize;
-
- // Fill the region kUninitializedByte or 0, and surround it with 2 cookies.
- PartitionCookieWriteValue(char_ret);
- if (!zero_fill) {
- memset(ret, kUninitializedByte, no_cookie_size);
- } else if (!is_already_zeroed) {
- memset(ret, 0, no_cookie_size);
- }
- PartitionCookieWriteValue(char_ret + kCookieSize + no_cookie_size);
-#else
- if (ret && zero_fill && !is_already_zeroed) {
- memset(ret, 0, size);
- }
-#endif
-
- return ret;
-}
-
-ALWAYS_INLINE bool PartitionRootBase::IsValidPage(PartitionPage* page) {
- PartitionRootBase* root = PartitionRootBase::FromPage(page);
- return root->inverted_self == ~reinterpret_cast<uintptr_t>(root);
-}
-
-ALWAYS_INLINE PartitionRootBase* PartitionRootBase::FromPage(
- PartitionPage* page) {
- PartitionSuperPageExtentEntry* extent_entry =
- reinterpret_cast<PartitionSuperPageExtentEntry*>(
- reinterpret_cast<uintptr_t>(page) & SystemPageBaseMask());
- return extent_entry->root;
-}
-
-ALWAYS_INLINE void PartitionRootBase::IncreaseCommittedPages(size_t len) {
- total_size_of_committed_pages += len;
- DCHECK(total_size_of_committed_pages <=
- total_size_of_super_pages + total_size_of_direct_mapped_pages);
-}
-
-ALWAYS_INLINE void PartitionRootBase::DecreaseCommittedPages(size_t len) {
- total_size_of_committed_pages -= len;
- DCHECK(total_size_of_committed_pages <=
- total_size_of_super_pages + total_size_of_direct_mapped_pages);
-}
-
-ALWAYS_INLINE void PartitionRootBase::DecommitSystemPages(void* address,
- size_t length) {
- ::pdfium::base::DecommitSystemPages(address, length);
- DecreaseCommittedPages(length);
-}
-
-ALWAYS_INLINE void PartitionRootBase::RecommitSystemPages(void* address,
- size_t length) {
- CHECK(::pdfium::base::RecommitSystemPages(address, length, PageReadWrite));
- IncreaseCommittedPages(length);
-}
-
-} // namespace internal
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ROOT_BASE_H_
diff --git a/third_party/base/allocator/partition_allocator/random.cc b/third_party/base/allocator/partition_allocator/random.cc
deleted file mode 100644
index ce87d87..0000000
--- a/third_party/base/allocator/partition_allocator/random.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/random.h"
-
-#include "build/build_config.h"
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-#include "third_party/base/no_destructor.h"
-
-#if BUILDFLAG(IS_WIN)
-#include <windows.h>
-#else
-#include <sys/time.h>
-#include <unistd.h>
-#endif
-
-namespace pdfium {
-namespace base {
-
-// This is the same PRNG as used by tcmalloc for mapping address randomness;
-// see http://burtleburtle.net/bob/rand/smallprng.html.
-struct RandomContext {
- subtle::SpinLock lock;
- bool initialized;
- uint32_t a;
- uint32_t b;
- uint32_t c;
- uint32_t d;
-};
-
-namespace {
-
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-uint32_t RandomValueInternal(RandomContext* x) {
- uint32_t e = x->a - rot(x->b, 27);
- x->a = x->b ^ rot(x->c, 17);
- x->b = x->c + x->d;
- x->c = x->d + e;
- x->d = e + x->a;
- return x->d;
-}
-
-#undef rot
-
-RandomContext* GetRandomContext() {
- static NoDestructor<RandomContext> g_random_context;
- RandomContext* x = g_random_context.get();
- subtle::SpinLock::Guard guard(x->lock);
- if (UNLIKELY(!x->initialized)) {
- x->initialized = true;
- char c;
- uint32_t seed = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&c));
- uint32_t pid;
- uint32_t usec;
-#if BUILDFLAG(IS_WIN)
- pid = GetCurrentProcessId();
- SYSTEMTIME st;
- GetSystemTime(&st);
- usec = static_cast<uint32_t>(st.wMilliseconds * 1000);
-#else
- pid = static_cast<uint32_t>(getpid());
- struct timeval tv;
- gettimeofday(&tv, 0);
- usec = static_cast<uint32_t>(tv.tv_usec);
-#endif
- seed ^= pid;
- seed ^= usec;
- x->a = 0xf1ea5eed;
- x->b = x->c = x->d = seed;
- for (int i = 0; i < 20; ++i) {
- RandomValueInternal(x);
- }
- }
- return x;
-}
-
-} // namespace
-
-uint32_t RandomValue() {
- RandomContext* x = GetRandomContext();
- subtle::SpinLock::Guard guard(x->lock);
- return RandomValueInternal(x);
-}
-
-void SetMmapSeedForTesting(int64_t seed) {
- RandomContext* x = GetRandomContext();
- subtle::SpinLock::Guard guard(x->lock);
- x->a = x->b = static_cast<uint32_t>(seed);
- x->c = x->d = static_cast<uint32_t>(seed >> 32);
- x->initialized = true;
-}
-
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/random.h b/third_party/base/allocator/partition_allocator/random.h
deleted file mode 100644
index e485d6d..0000000
--- a/third_party/base/allocator/partition_allocator/random.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_RANDOM_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_RANDOM_H_
-
-#include <stdint.h>
-
-#include "third_party/base/base_export.h"
-
-namespace pdfium {
-namespace base {
-
-// Returns a random value. The generator's internal state is initialized with
-// `base::RandUint64` which is very unpredictable, but which is expensive due to
-// the need to call into the kernel. Therefore this generator uses a fast,
-// entirely user-space function after initialization.
-BASE_EXPORT uint32_t RandomValue();
-
-// Sets the seed for the random number generator to a known value, to cause the
-// RNG to generate a predictable sequence of outputs. May be called multiple
-// times.
-BASE_EXPORT void SetMmapSeedForTesting(uint64_t seed);
-
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_RANDOM_H_
diff --git a/third_party/base/allocator/partition_allocator/spin_lock.cc b/third_party/base/allocator/partition_allocator/spin_lock.cc
deleted file mode 100644
index d7cdd15..0000000
--- a/third_party/base/allocator/partition_allocator/spin_lock.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/base/allocator/partition_allocator/spin_lock.h"
-
-#include "build/build_config.h"
-#include "third_party/base/notreached.h"
-
-#if BUILDFLAG(IS_WIN)
-#include <windows.h>
-#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-#include <sched.h>
-#endif
-
-// The YIELD_PROCESSOR macro wraps an architecture specific-instruction that
-// informs the processor we're in a busy wait, so it can handle the branch more
-// intelligently and e.g. reduce power to our core or give more resources to the
-// other hyper-thread on this core. See the following for context:
-// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
-//
-// The YIELD_THREAD macro tells the OS to relinquish our quantum. This is
-// basically a worst-case fallback, and if you're hitting it with any frequency
-// you really should be using a proper lock (such as |base::Lock|)rather than
-// these spinlocks.
-#if BUILDFLAG(IS_WIN)
-
-#define YIELD_PROCESSOR YieldProcessor()
-#define YIELD_THREAD SwitchToThread()
-
-#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-
-#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_X86)
-#define YIELD_PROCESSOR __asm__ __volatile__("pause")
-#elif (defined(ARCH_CPU_ARMEL) && __ARM_ARCH >= 6) || defined(ARCH_CPU_ARM64)
-#define YIELD_PROCESSOR __asm__ __volatile__("yield")
-#elif defined(ARCH_CPU_MIPSEL)
-// The MIPS32 docs state that the PAUSE instruction is a no-op on older
-// architectures (first added in MIPS32r2). To avoid assembler errors when
-// targeting pre-r2, we must encode the instruction manually.
-#define YIELD_PROCESSOR __asm__ __volatile__(".word 0x00000140")
-#elif defined(ARCH_CPU_MIPS64EL) && __mips_isa_rev >= 2
-// Don't bother doing using .word here since r2 is the lowest supported mips64
-// that Chromium supports.
-#define YIELD_PROCESSOR __asm__ __volatile__("pause")
-#elif defined(ARCH_CPU_PPC64_FAMILY)
-#define YIELD_PROCESSOR __asm__ __volatile__("or 31,31,31")
-#elif defined(ARCH_CPU_S390_FAMILY)
-// just do nothing
-#define YIELD_PROCESSOR ((void)0)
-#endif // ARCH
-
-#ifndef YIELD_PROCESSOR
-#warning "Processor yield not supported on this architecture."
-#define YIELD_PROCESSOR ((void)0)
-#endif
-
-#define YIELD_THREAD sched_yield()
-
-#else // Other OS
-
-#warning "Thread yield not supported on this OS."
-#define YIELD_THREAD ((void)0)
-
-#endif // OS_WIN
-
-namespace pdfium {
-namespace base {
-namespace subtle {
-
-void SpinLock::LockSlow() {
- // The value of |kYieldProcessorTries| is cargo culted from TCMalloc, Windows
- // critical section defaults, and various other recommendations.
- // TODO(jschuh): Further tuning may be warranted.
- static const int kYieldProcessorTries = 1000;
- // The value of |kYieldThreadTries| is completely made up.
- static const int kYieldThreadTries = 10;
- int yield_thread_count = 0;
- do {
- do {
- for (int count = 0; count < kYieldProcessorTries; ++count) {
- // Let the processor know we're spinning.
- YIELD_PROCESSOR;
- if (!lock_.load(std::memory_order_relaxed) &&
- LIKELY(!lock_.exchange(true, std::memory_order_acquire)))
- return;
- }
-
- if (yield_thread_count < kYieldThreadTries) {
- ++yield_thread_count;
- // Give the OS a chance to schedule something on this core.
- YIELD_THREAD;
- } else {
- // At this point, it's likely that the lock is held by a lower priority
- // thread that is unavailable to finish its work because of higher
- // priority threads spinning here. Sleeping should ensure that they make
- // progress.
- NOTREACHED();
- }
- } while (lock_.load(std::memory_order_relaxed));
- } while (UNLIKELY(lock_.exchange(true, std::memory_order_acquire)));
-}
-
-} // namespace subtle
-} // namespace base
-} // namespace pdfium
diff --git a/third_party/base/allocator/partition_allocator/spin_lock.h b/third_party/base/allocator/partition_allocator/spin_lock.h
deleted file mode 100644
index 5613fd1..0000000
--- a/third_party/base/allocator/partition_allocator/spin_lock.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_SPIN_LOCK_H_
-#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_SPIN_LOCK_H_
-
-#include <atomic>
-#include <memory>
-#include <mutex>
-
-#include "third_party/base/base_export.h"
-#include "third_party/base/compiler_specific.h"
-
-// Spinlock is a simple spinlock class based on the standard CPU primitive of
-// atomic increment and decrement of an int at a given memory address. These are
-// intended only for very short duration locks and assume a system with multiple
-// cores. For any potentially longer wait you should use a real lock, such as
-// |base::Lock|.
-namespace pdfium {
-namespace base {
-namespace subtle {
-
-class BASE_EXPORT SpinLock {
- public:
- constexpr SpinLock() = default;
- ~SpinLock() = default;
- using Guard = std::lock_guard<SpinLock>;
-
- ALWAYS_INLINE void lock() {
- static_assert(sizeof(lock_) == sizeof(int),
- "int and lock_ are different sizes");
- if (LIKELY(!lock_.exchange(true, std::memory_order_acquire)))
- return;
- LockSlow();
- }
-
- ALWAYS_INLINE void unlock() { lock_.store(false, std::memory_order_release); }
-
- private:
- // This is called if the initial attempt to acquire the lock fails. It's
- // slower, but has a much better scheduling and power consumption behavior.
- void LockSlow();
-
- std::atomic_int lock_{0};
-};
-
-} // namespace subtle
-} // namespace base
-} // namespace pdfium
-
-#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_SPIN_LOCK_H_