• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 the V8 project 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 
5 #include "src/base/page-allocator.h"
6 
7 #include "src/base/platform/platform.h"
8 #include "src/base/platform/wrappers.h"
9 
10 #if V8_OS_DARWIN
11 #include <sys/mman.h>  // For MAP_JIT.
12 #endif
13 
14 namespace v8 {
15 namespace base {
16 
17 #define STATIC_ASSERT_ENUM(a, b)                            \
18   static_assert(static_cast<int>(a) == static_cast<int>(b), \
19                 "mismatching enum: " #a)
20 
21 STATIC_ASSERT_ENUM(PageAllocator::kNoAccess,
22                    base::OS::MemoryPermission::kNoAccess);
23 STATIC_ASSERT_ENUM(PageAllocator::kReadWrite,
24                    base::OS::MemoryPermission::kReadWrite);
25 STATIC_ASSERT_ENUM(PageAllocator::kReadWriteExecute,
26                    base::OS::MemoryPermission::kReadWriteExecute);
27 STATIC_ASSERT_ENUM(PageAllocator::kReadExecute,
28                    base::OS::MemoryPermission::kReadExecute);
29 STATIC_ASSERT_ENUM(PageAllocator::kNoAccessWillJitLater,
30                    base::OS::MemoryPermission::kNoAccessWillJitLater);
31 
32 #undef STATIC_ASSERT_ENUM
33 
PageAllocator()34 PageAllocator::PageAllocator()
35     : allocate_page_size_(base::OS::AllocatePageSize()),
36       commit_page_size_(base::OS::CommitPageSize()) {}
37 
SetRandomMmapSeed(int64_t seed)38 void PageAllocator::SetRandomMmapSeed(int64_t seed) {
39   base::OS::SetRandomMmapSeed(seed);
40 }
41 
GetRandomMmapAddr()42 void* PageAllocator::GetRandomMmapAddr() {
43   return base::OS::GetRandomMmapAddr();
44 }
45 
AllocatePages(void * hint,size_t size,size_t alignment,PageAllocator::Permission access)46 void* PageAllocator::AllocatePages(void* hint, size_t size, size_t alignment,
47                                    PageAllocator::Permission access) {
48 #if !V8_HAS_PTHREAD_JIT_WRITE_PROTECT
49   // kNoAccessWillJitLater is only used on Apple Silicon. Map it to regular
50   // kNoAccess on other platforms, so code doesn't have to handle both enum
51   // values.
52   if (access == PageAllocator::kNoAccessWillJitLater) {
53     access = PageAllocator::kNoAccess;
54   }
55 #endif
56   return base::OS::Allocate(hint, size, alignment,
57                             static_cast<base::OS::MemoryPermission>(access));
58 }
59 
60 class SharedMemoryMapping : public ::v8::PageAllocator::SharedMemoryMapping {
61  public:
SharedMemoryMapping(PageAllocator * page_allocator,void * ptr,size_t size)62   explicit SharedMemoryMapping(PageAllocator* page_allocator, void* ptr,
63                                size_t size)
64       : page_allocator_(page_allocator), ptr_(ptr), size_(size) {}
~SharedMemoryMapping()65   ~SharedMemoryMapping() override { page_allocator_->FreePages(ptr_, size_); }
GetMemory() const66   void* GetMemory() const override { return ptr_; }
67 
68  private:
69   PageAllocator* page_allocator_;
70   void* ptr_;
71   size_t size_;
72 };
73 
74 class SharedMemory : public ::v8::PageAllocator::SharedMemory {
75  public:
SharedMemory(PageAllocator * allocator,void * memory,size_t size)76   SharedMemory(PageAllocator* allocator, void* memory, size_t size)
77       : allocator_(allocator), ptr_(memory), size_(size) {}
GetMemory() const78   void* GetMemory() const override { return ptr_; }
GetSize() const79   size_t GetSize() const override { return size_; }
RemapTo(void * new_address) const80   std::unique_ptr<::v8::PageAllocator::SharedMemoryMapping> RemapTo(
81       void* new_address) const override {
82     if (allocator_->RemapShared(ptr_, new_address, size_)) {
83       return std::make_unique<SharedMemoryMapping>(allocator_, new_address,
84                                                    size_);
85     } else {
86       return {};
87     }
88   }
89 
~SharedMemory()90   ~SharedMemory() override { allocator_->FreePages(ptr_, size_); }
91 
92  private:
93   PageAllocator* allocator_;
94   void* ptr_;
95   size_t size_;
96 };
97 
CanAllocateSharedPages()98 bool PageAllocator::CanAllocateSharedPages() {
99 #ifdef V8_OS_LINUX
100   return true;
101 #else
102   return false;
103 #endif
104 }
105 
106 std::unique_ptr<v8::PageAllocator::SharedMemory>
AllocateSharedPages(size_t size,const void * original_address)107 PageAllocator::AllocateSharedPages(size_t size, const void* original_address) {
108 #ifdef V8_OS_LINUX
109   void* ptr =
110       base::OS::AllocateShared(size, base::OS::MemoryPermission::kReadWrite);
111   CHECK_NOT_NULL(ptr);
112   memcpy(ptr, original_address, size);
113   bool success = base::OS::SetPermissions(
114       ptr, size, base::OS::MemoryPermission::kReadWrite);
115   CHECK(success);
116 
117   auto shared_memory =
118       std::make_unique<v8::base::SharedMemory>(this, ptr, size);
119   return shared_memory;
120 #else
121   return {};
122 #endif
123 }
124 
RemapShared(void * old_address,void * new_address,size_t size)125 void* PageAllocator::RemapShared(void* old_address, void* new_address,
126                                  size_t size) {
127 #ifdef V8_OS_LINUX
128   return base::OS::RemapShared(old_address, new_address, size);
129 #else
130   return nullptr;
131 #endif
132 }
133 
FreePages(void * address,size_t size)134 bool PageAllocator::FreePages(void* address, size_t size) {
135   base::OS::Free(address, size);
136   return true;
137 }
138 
ReleasePages(void * address,size_t size,size_t new_size)139 bool PageAllocator::ReleasePages(void* address, size_t size, size_t new_size) {
140   DCHECK_LT(new_size, size);
141   base::OS::Release(reinterpret_cast<uint8_t*>(address) + new_size,
142                     size - new_size);
143   return true;
144 }
145 
SetPermissions(void * address,size_t size,PageAllocator::Permission access)146 bool PageAllocator::SetPermissions(void* address, size_t size,
147                                    PageAllocator::Permission access) {
148   return base::OS::SetPermissions(
149       address, size, static_cast<base::OS::MemoryPermission>(access));
150 }
151 
DiscardSystemPages(void * address,size_t size)152 bool PageAllocator::DiscardSystemPages(void* address, size_t size) {
153   return base::OS::DiscardSystemPages(address, size);
154 }
155 
DecommitPages(void * address,size_t size)156 bool PageAllocator::DecommitPages(void* address, size_t size) {
157   return base::OS::DecommitPages(address, size);
158 }
159 
160 }  // namespace base
161 }  // namespace v8
162