1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "v8_platform_page_allocator.h"
7 #include "base/allocator/partition_allocator/src/partition_alloc/address_space_randomization.h"
8 #include "base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h"
9 #include "base/allocator/partition_allocator/src/partition_alloc/random.h"
10 #include "base/check_op.h"
12 #include "base/memory/page_size.h"
13 #include "build/build_config.h"
17 // Maps the v8 page permissions into a page configuration from base.
18 ::partition_alloc::PageAccessibilityConfiguration::Permissions
19 GetPagePermissions(v8::PageAllocator::Permission permission) {
21 case v8::PageAllocator::Permission::kRead:
22 return ::partition_alloc::PageAccessibilityConfiguration::kRead;
23 case v8::PageAllocator::Permission::kReadWrite:
24 return ::partition_alloc::PageAccessibilityConfiguration::kReadWrite;
25 case v8::PageAllocator::Permission::kReadWriteExecute:
26 // at the moment bti-protection is not enabled for this path since some
27 // projects may still be using non-bti compliant code.
28 return ::partition_alloc::PageAccessibilityConfiguration::
30 case v8::PageAllocator::Permission::kReadExecute:
31 #if defined(__ARM_FEATURE_BTI_DEFAULT)
32 return base::CPU::GetInstanceNoAllocation().has_bti()
33 ? ::partition_alloc::PageAccessibilityConfiguration::
35 : ::partition_alloc::PageAccessibilityConfiguration::
38 return ::partition_alloc::PageAccessibilityConfiguration::kReadExecute;
40 case v8::PageAllocator::Permission::kNoAccessWillJitLater:
41 return ::partition_alloc::PageAccessibilityConfiguration::
42 kInaccessibleWillJitLater;
44 DCHECK_EQ(v8::PageAllocator::Permission::kNoAccess, permission);
45 return ::partition_alloc::PageAccessibilityConfiguration::kInaccessible;
49 ::partition_alloc::PageAccessibilityConfiguration GetPageConfig(
50 v8::PageAllocator::Permission permission) {
51 return ::partition_alloc::PageAccessibilityConfiguration(
52 GetPagePermissions(permission));
58 PageAllocator::~PageAllocator() = default;
60 size_t PageAllocator::AllocatePageSize() {
61 return partition_alloc::internal::PageAllocationGranularity();
64 size_t PageAllocator::CommitPageSize() {
65 return base::GetPageSize();
68 void PageAllocator::SetRandomMmapSeed(int64_t seed) {
69 ::partition_alloc::SetMmapSeedForTesting(seed);
72 void* PageAllocator::GetRandomMmapAddr() {
73 return reinterpret_cast<void*>(::partition_alloc::GetRandomPageBase());
76 void* PageAllocator::AllocatePages(void* address,
79 v8::PageAllocator::Permission permissions) {
80 partition_alloc::PageAccessibilityConfiguration config =
81 GetPageConfig(permissions);
82 return partition_alloc::AllocPages(address, length, alignment, config,
83 ::partition_alloc::PageTag::kV8);
86 bool PageAllocator::FreePages(void* address, size_t length) {
87 partition_alloc::FreePages(address, length);
91 bool PageAllocator::ReleasePages(void* address,
94 DCHECK_LT(new_length, length);
95 uint8_t* release_base = reinterpret_cast<uint8_t*>(address) + new_length;
96 size_t release_size = length - new_length;
97 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
98 // On POSIX, we can unmap the trailing pages.
99 partition_alloc::FreePages(release_base, release_size);
100 #elif BUILDFLAG(IS_WIN)
101 // On Windows, we can only de-commit the trailing pages. FreePages() will
102 // still free all pages in the region including the released tail, so it's
103 // safe to just decommit the tail.
104 partition_alloc::DecommitSystemPages(
105 release_base, release_size,
106 ::partition_alloc::PageAccessibilityDisposition::kRequireUpdate);
108 #error Unsupported platform
113 bool PageAllocator::SetPermissions(void* address,
115 Permission permissions) {
116 // If V8 sets permissions to none, we can discard the memory.
117 if (permissions == v8::PageAllocator::Permission::kNoAccess) {
118 // Use PageAccessibilityDisposition::kAllowKeepForPerf as an
119 // optimization, to avoid perf regression (see crrev.com/c/2563038 for
120 // details). This may cause the memory region to still be accessible on
121 // certain platforms, but at least the physical pages will be discarded.
122 partition_alloc::DecommitSystemPages(
124 ::partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
127 return partition_alloc::TrySetSystemPagesAccess(address, length,
128 GetPageConfig(permissions));
132 bool PageAllocator::RecommitPages(void* address,
134 Permission permissions) {
135 partition_alloc::RecommitSystemPages(
136 reinterpret_cast<uintptr_t>(address), length, GetPageConfig(permissions),
137 partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
141 bool PageAllocator::DiscardSystemPages(void* address, size_t size) {
142 partition_alloc::DiscardSystemPages(address, size);
146 bool PageAllocator::DecommitPages(void* address, size_t size) {
147 // V8 expects the pages to be inaccessible and zero-initialized upon next
149 partition_alloc::DecommitAndZeroSystemPages(address, size);
153 partition_alloc::PageAccessibilityConfiguration::Permissions
154 PageAllocator::GetPageConfigPermissionsForTesting(
155 v8::PageAllocator::Permission permission) {
156 return GetPageConfig(permission).permissions;