#include "v8_platform_page_allocator.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/cpu.h"
#include "base/memory/page_size.h"
#include "build/build_config.h"
#include "partition_alloc/address_space_randomization.h"
#include "partition_alloc/page_allocator_constants.h"
#include "partition_alloc/random.h"
namespace {
template <typename T>
T IfBtiEnabledOr(T enabled_value, T disabled_value) {
#if defined(__ARM_FEATURE_BTI_DEFAULT)
return base::CPU::GetInstanceNoAllocation().has_bti() ? enabled_value
: disabled_value;
#else
return disabled_value;
#endif
}
::partition_alloc::PageAccessibilityConfiguration::Permissions
GetPagePermissions(v8::PageAllocator::Permission permission) {
switch (permission) {
case v8::PageAllocator::Permission::kRead:
return ::partition_alloc::PageAccessibilityConfiguration::kRead;
case v8::PageAllocator::Permission::kReadWrite:
return ::partition_alloc::PageAccessibilityConfiguration::kReadWrite;
case v8::PageAllocator::Permission::kReadWriteExecute:
return IfBtiEnabledOr(
::partition_alloc::PageAccessibilityConfiguration::
kReadWriteExecuteProtected,
::partition_alloc::PageAccessibilityConfiguration::kReadWriteExecute);
case v8::PageAllocator::Permission::kReadExecute:
return IfBtiEnabledOr(
::partition_alloc::PageAccessibilityConfiguration::
kReadExecuteProtected,
::partition_alloc::PageAccessibilityConfiguration::kReadExecute);
case v8::PageAllocator::Permission::kNoAccessWillJitLater:
return ::partition_alloc::PageAccessibilityConfiguration::
kInaccessibleWillJitLater;
case v8::PageAllocator::Permission::kNoAccess:
return ::partition_alloc::PageAccessibilityConfiguration::kInaccessible;
}
}
::partition_alloc::PageAccessibilityConfiguration GetPageConfig(
v8::PageAllocator::Permission permission) {
return ::partition_alloc::PageAccessibilityConfiguration(
GetPagePermissions(permission));
}
}
namespace gin {
PageAllocator::~PageAllocator() = default;
size_t PageAllocator::AllocatePageSize() {
return partition_alloc::internal::PageAllocationGranularity();
}
size_t PageAllocator::CommitPageSize() {
return base::GetPageSize();
}
void PageAllocator::SetRandomMmapSeed(int64_t seed) {
::partition_alloc::SetMmapSeedForTesting(seed);
}
void* PageAllocator::GetRandomMmapAddr() {
return reinterpret_cast<void*>(::partition_alloc::GetRandomPageBase());
}
void* PageAllocator::AllocatePages(void* address,
size_t length,
size_t alignment,
v8::PageAllocator::Permission permissions) {
partition_alloc::PageAccessibilityConfiguration config =
GetPageConfig(permissions);
return partition_alloc::AllocPages(address, length, alignment, config,
::partition_alloc::PageTag::kV8);
}
bool PageAllocator::FreePages(void* address, size_t length) {
partition_alloc::FreePages(address, length);
return true;
}
bool PageAllocator::ReleasePages(void* address,
size_t length,
size_t new_length) {
DCHECK_LT(new_length, length);
uint8_t* release_base =
UNSAFE_TODO(reinterpret_cast<uint8_t*>(address) + new_length);
size_t release_size = length - new_length;
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
partition_alloc::FreePages(release_base, release_size);
#elif BUILDFLAG(IS_WIN)
partition_alloc::DecommitSystemPages(
release_base, release_size,
::partition_alloc::PageAccessibilityDisposition::kRequireUpdate);
#else
#error Unsupported platform
#endif
return true;
}
bool PageAllocator::SetPermissions(void* address,
size_t length,
Permission permissions) {
if (permissions == v8::PageAllocator::Permission::kNoAccess) {
partition_alloc::DecommitSystemPages(
address, length,
::partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
return true;
} else {
return partition_alloc::TrySetSystemPagesAccess(address, length,
GetPageConfig(permissions));
}
}
bool PageAllocator::RecommitPages(void* address,
size_t length,
Permission permissions) {
partition_alloc::RecommitSystemPages(
reinterpret_cast<uintptr_t>(address), length, GetPageConfig(permissions),
partition_alloc::PageAccessibilityDisposition::kAllowKeepForPerf);
return true;
}
bool PageAllocator::DiscardSystemPages(void* address, size_t size) {
partition_alloc::DiscardSystemPages(address, size);
return true;
}
bool PageAllocator::DecommitPages(void* address, size_t size) {
return partition_alloc::DecommitAndZeroSystemPages(
address, size, partition_alloc::PageTag::kV8);
}
bool PageAllocator::SealPages(void* address, size_t size) {
return partition_alloc::SealSystemPages(address, size);
}
partition_alloc::PageAccessibilityConfiguration::Permissions
PageAllocator::GetPageConfigPermissionsForTesting(
v8::PageAllocator::Permission permission) {
return GetPageConfig(permission).permissions;
}
}