v8_platform_page_allocator.cc 5.4 KB

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