v8_platform_page_allocator.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "v8_platform_page_allocator.h"
  5. #include "base/allocator/partition_allocator/address_space_randomization.h"
  6. #include "base/allocator/partition_allocator/page_allocator_constants.h"
  7. #include "base/allocator/partition_allocator/random.h"
  8. #include "base/check_op.h"
  9. #include "base/cpu.h"
  10. #include "base/memory/page_size.h"
  11. #include "build/build_config.h"
  12. namespace {
  13. // Maps the v8 page permissions into a page configuration from base.
  14. ::partition_alloc::PageAccessibilityConfiguration GetPageConfig(
  15. v8::PageAllocator::Permission permission) {
  16. switch (permission) {
  17. case v8::PageAllocator::Permission::kRead:
  18. return ::partition_alloc::PageAccessibilityConfiguration::kRead;
  19. case v8::PageAllocator::Permission::kReadWrite:
  20. return ::partition_alloc::PageAccessibilityConfiguration::kReadWrite;
  21. case v8::PageAllocator::Permission::kReadWriteExecute:
  22. // at the moment bti-protection is not enabled for this path since some
  23. // projects may still be using non-bti compliant code.
  24. return ::partition_alloc::PageAccessibilityConfiguration::
  25. kReadWriteExecute;
  26. case v8::PageAllocator::Permission::kReadExecute:
  27. #if defined(__ARM_FEATURE_BTI_DEFAULT)
  28. return base::CPU::GetInstanceNoAllocation().has_bti()
  29. ? ::partition_alloc::PageAccessibilityConfiguration::
  30. kReadExecuteProtected
  31. : ::partition_alloc::PageAccessibilityConfiguration::
  32. kReadExecute;
  33. #else
  34. return ::partition_alloc::PageAccessibilityConfiguration::kReadExecute;
  35. #endif
  36. case v8::PageAllocator::Permission::kNoAccessWillJitLater:
  37. // We could use this information to conditionally set the MAP_JIT flag
  38. // on Mac-arm64; however this permissions value is intended to be a
  39. // short-term solution, so we continue to set MAP_JIT for all V8 pages
  40. // for now.
  41. return ::partition_alloc::PageAccessibilityConfiguration::kInaccessible;
  42. default:
  43. DCHECK_EQ(v8::PageAllocator::Permission::kNoAccess, permission);
  44. return ::partition_alloc::PageAccessibilityConfiguration::kInaccessible;
  45. }
  46. }
  47. } // namespace
  48. namespace gin {
  49. PageAllocator::~PageAllocator() = default;
  50. size_t PageAllocator::AllocatePageSize() {
  51. return partition_alloc::internal::PageAllocationGranularity();
  52. }
  53. size_t PageAllocator::CommitPageSize() {
  54. return base::GetPageSize();
  55. }
  56. void PageAllocator::SetRandomMmapSeed(int64_t seed) {
  57. ::partition_alloc::SetMmapSeedForTesting(seed);
  58. }
  59. void* PageAllocator::GetRandomMmapAddr() {
  60. return reinterpret_cast<void*>(::partition_alloc::GetRandomPageBase());
  61. }
  62. void* PageAllocator::AllocatePages(void* address,
  63. size_t length,
  64. size_t alignment,
  65. v8::PageAllocator::Permission permissions) {
  66. partition_alloc::PageAccessibilityConfiguration config =
  67. GetPageConfig(permissions);
  68. return partition_alloc::AllocPages(address, length, alignment, config,
  69. partition_alloc::PageTag::kV8);
  70. }
  71. bool PageAllocator::FreePages(void* address, size_t length) {
  72. partition_alloc::FreePages(address, length);
  73. return true;
  74. }
  75. bool PageAllocator::ReleasePages(void* address,
  76. size_t length,
  77. size_t new_length) {
  78. DCHECK_LT(new_length, length);
  79. uint8_t* release_base = reinterpret_cast<uint8_t*>(address) + new_length;
  80. size_t release_size = length - new_length;
  81. #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  82. // On POSIX, we can unmap the trailing pages.
  83. partition_alloc::FreePages(release_base, release_size);
  84. #elif BUILDFLAG(IS_WIN)
  85. // On Windows, we can only de-commit the trailing pages. FreePages() will
  86. // still free all pages in the region including the released tail, so it's
  87. // safe to just decommit the tail.
  88. partition_alloc::DecommitSystemPages(
  89. release_base, release_size,
  90. ::partition_alloc::PageAccessibilityDisposition::kRequireUpdate);
  91. #else
  92. #error Unsupported platform
  93. #endif
  94. return true;
  95. }
  96. bool PageAllocator::SetPermissions(void* address,
  97. size_t length,
  98. Permission permissions) {
  99. // If V8 sets permissions to none, we can discard the memory.
  100. if (permissions == v8::PageAllocator::Permission::kNoAccess) {
  101. // Use PageAccessibilityDisposition::kAllowKeepForPerf as an
  102. // optimization, to avoid perf regression (see crrev.com/c/2563038 for
  103. // details). This may cause the memory region to still be accessible on
  104. // certain platforms, but at least the physical pages will be discarded.
  105. partition_alloc::DecommitSystemPages(
  106. address, length,
  107. ::partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
  108. return true;
  109. } else {
  110. return partition_alloc::TrySetSystemPagesAccess(address, length,
  111. GetPageConfig(permissions));
  112. }
  113. }
  114. bool PageAllocator::RecommitPages(void* address,
  115. size_t length,
  116. Permission permissions) {
  117. partition_alloc::RecommitSystemPages(
  118. reinterpret_cast<uintptr_t>(address), length, GetPageConfig(permissions),
  119. partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
  120. return true;
  121. }
  122. bool PageAllocator::DiscardSystemPages(void* address, size_t size) {
  123. partition_alloc::DiscardSystemPages(address, size);
  124. return true;
  125. }
  126. bool PageAllocator::DecommitPages(void* address, size_t size) {
  127. // V8 expects the pages to be inaccessible and zero-initialized upon next
  128. // access.
  129. partition_alloc::DecommitAndZeroSystemPages(address, size);
  130. return true;
  131. }
  132. partition_alloc::PageAccessibilityConfiguration
  133. PageAllocator::GetPageConfigForTesting(
  134. v8::PageAllocator::Permission permission) {
  135. return GetPageConfig(permission);
  136. }
  137. } // namespace gin