| // Copyright 2021 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ |
| #define V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ |
| |
| #include "include/v8-platform.h" |
| #include "src/base/base-export.h" |
| #include "src/base/compiler-specific.h" |
| #include "src/base/platform/mutex.h" |
| #include "src/base/region-allocator.h" |
| #include "src/base/virtual-address-space.h" |
| |
| namespace v8 { |
| namespace base { |
| |
| /** |
| * Emulates a virtual address subspace. |
| * |
| * This class is (optionally) backed by a page allocation and emulates a virtual |
| * address space that is potentially larger than that mapping. It generally |
| * first attempts to satisfy page allocation requests from its backing mapping, |
| * but will also attempt to obtain new page mappings inside the unmapped space |
| * through page allocation hints if necessary. |
| * |
| * Caveat: an emulated subspace violates the invariant that page allocations in |
| * an address space will never end up inside a child space and so does not |
| * provide the same security gurarantees. |
| */ |
| class V8_BASE_EXPORT EmulatedVirtualAddressSubspace final |
| : public NON_EXPORTED_BASE(::v8::VirtualAddressSpace) { |
| public: |
| // Construct an emulated virtual address subspace of the specified total size, |
| // potentially backed by a page allocation from the parent space. The newly |
| // created instance takes ownership of the page allocation (if any) and frees |
| // it during destruction. |
| EmulatedVirtualAddressSubspace(v8::VirtualAddressSpace* parent_space, |
| Address base, size_t mapped_size, |
| size_t total_size); |
| |
| ~EmulatedVirtualAddressSubspace() override; |
| |
| void SetRandomSeed(int64_t seed) override; |
| |
| Address RandomPageAddress() override; |
| |
| Address AllocatePages(Address hint, size_t size, size_t alignment, |
| PagePermissions permissions) override; |
| |
| void FreePages(Address address, size_t size) override; |
| |
| Address AllocateSharedPages(Address hint, size_t size, |
| PagePermissions permissions, |
| PlatformSharedMemoryHandle handle, |
| uint64_t offset) override; |
| |
| void FreeSharedPages(Address address, size_t size) override; |
| |
| bool SetPagePermissions(Address address, size_t size, |
| PagePermissions permissions) override; |
| |
| bool AllocateGuardRegion(Address address, size_t size) override; |
| |
| void FreeGuardRegion(Address address, size_t size) override; |
| |
| bool CanAllocateSubspaces() override; |
| |
| std::unique_ptr<v8::VirtualAddressSpace> AllocateSubspace( |
| Address hint, size_t size, size_t alignment, |
| PagePermissions max_page_permissions) override; |
| |
| bool RecommitPages(Address address, size_t size, |
| PagePermissions permissions) override; |
| |
| bool DiscardSystemPages(Address address, size_t size) override; |
| |
| bool DecommitPages(Address address, size_t size) override; |
| |
| private: |
| size_t mapped_size() const { return mapped_size_; } |
| size_t unmapped_size() const { return size() - mapped_size_; } |
| |
| Address mapped_base() const { return base(); } |
| Address unmapped_base() const { return base() + mapped_size_; } |
| |
| bool Contains(Address outer_start, size_t outer_size, Address inner_start, |
| size_t inner_size) const { |
| return (inner_start >= outer_start) && |
| ((inner_start + inner_size) <= (outer_start + outer_size)); |
| } |
| |
| bool Contains(Address addr, size_t length) const { |
| return Contains(base(), size(), addr, length); |
| } |
| |
| bool MappedRegionContains(Address addr, size_t length) const { |
| return Contains(mapped_base(), mapped_size(), addr, length); |
| } |
| |
| bool UnmappedRegionContains(Address addr, size_t length) const { |
| return Contains(unmapped_base(), unmapped_size(), addr, length); |
| } |
| |
| // Helper function to define a limit for the size of allocations in the |
| // unmapped region. This limit makes it possible to estimate the expected |
| // runtime of some loops in the Allocate methods. |
| bool IsUsableSizeForUnmappedRegion(size_t size) const { |
| return size <= (unmapped_size() / 2); |
| } |
| |
| // Size of the mapped region located at the beginning of this address space. |
| const size_t mapped_size_; |
| |
| // Pointer to the parent space from which the backing pages were allocated. |
| // Must be kept alive by the owner of this instance. |
| v8::VirtualAddressSpace* parent_space_; |
| |
| // Mutex guarding the non-threadsafe RegionAllocator and |
| // RandomNumberGenerator. |
| Mutex mutex_; |
| |
| // RegionAllocator to manage the page allocation and divide it into further |
| // regions as necessary. |
| RegionAllocator region_allocator_; |
| |
| // Random number generator for generating random addresses. |
| RandomNumberGenerator rng_; |
| }; |
| |
| } // namespace base |
| } // namespace v8 |
| |
| #endif // V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ |