// 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 #include #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, }; // Mac OSX supports tagged memory regions, to help in debugging. enum class PageTag { kFirst = 240, // Minimum tag value. kChromium = 254, // Chromium page, including off-heap V8 ArrayBuffers. 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 |kPageAllocationGranularity|. // |align| is in bytes, and must be a power-of-two multiple of // |kPageAllocationGranularity|. // // If |address| is null, then a suitable and randomized address will be chosen // automatically. // // |page_accessibility| controls the permission of the allocated pages. // // 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 = PageTag::kChromium, 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 |kPageAllocationGranularity| bytes, and |length| // must be a multiple of |kPageAllocationGranularity|. 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 |kSystemPageSize| bytes. // // Returns true if the permission change succeeded. In most cases you must // |CHECK| the result. BASE_EXPORT WARN_UNUSED_RESULT bool 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 |kSystemPageSize|. // // 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 |kSystemPageSize|. // // 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. BASE_EXPORT WARN_UNUSED_RESULT 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 |kSystemPageSize|. // // 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 |kSystemPageSize|. Returns // 0 for an |address| of 0. constexpr ALWAYS_INLINE uintptr_t RoundUpToSystemPage(uintptr_t address) { return (address + kSystemPageOffsetMask) & kSystemPageBaseMask; } // Rounds down |address| to the previous multiple of |kSystemPageSize|. Returns // 0 for an |address| of 0. constexpr ALWAYS_INLINE uintptr_t RoundDownToSystemPage(uintptr_t address) { return address & kSystemPageBaseMask; } // Rounds up |address| to the next multiple of |kPageAllocationGranularity|. // Returns 0 for an |address| of 0. constexpr ALWAYS_INLINE uintptr_t RoundUpToPageAllocationGranularity(uintptr_t address) { return (address + kPageAllocationGranularityOffsetMask) & kPageAllocationGranularityBaseMask; } // Rounds down |address| to the previous multiple of // |kPageAllocationGranularity|. Returns 0 for an |address| of 0. constexpr ALWAYS_INLINE uintptr_t RoundDownToPageAllocationGranularity(uintptr_t address) { return address & kPageAllocationGranularityBaseMask; } // Reserves (at least) |size| bytes of address space, aligned to // |kPageAllocationGranularity|. 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. BASE_EXPORT void 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_