// Copyright 2012 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. // Platform-specific code for MacOS goes here. Code shared between iOS and // macOS is in platform-darwin.cc, while the POSIX-compatible are in in // platform-posix.cc. #include <mach/mach.h> #include <mach/mach_vm.h> #include <mach/vm_map.h> #include "src/base/platform/platform.h" namespace v8 { namespace base { namespace { vm_prot_t GetVMProtFromMemoryPermission(OS::MemoryPermission access) { switch (access) { case OS::MemoryPermission::kNoAccess: case OS::MemoryPermission::kNoAccessWillJitLater: return VM_PROT_NONE; case OS::MemoryPermission::kRead: return VM_PROT_READ; case OS::MemoryPermission::kReadWrite: return VM_PROT_READ | VM_PROT_WRITE; case OS::MemoryPermission::kReadWriteExecute: return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; case OS::MemoryPermission::kReadExecute: return VM_PROT_READ | VM_PROT_EXECUTE; } UNREACHABLE(); } kern_return_t mach_vm_map_wrapper(mach_vm_address_t* address, mach_vm_size_t size, int flags, mach_port_t port, memory_object_offset_t offset, vm_prot_t prot) { vm_prot_t current_prot = prot; vm_prot_t maximum_prot = current_prot; return mach_vm_map(mach_task_self(), address, size, 0, flags, port, offset, FALSE, current_prot, maximum_prot, VM_INHERIT_NONE); } } // namespace // static PlatformSharedMemoryHandle OS::CreateSharedMemoryHandleForTesting(size_t size) { mach_vm_size_t vm_size = size; mach_port_t port; kern_return_t kr = mach_make_memory_entry_64( mach_task_self(), &vm_size, 0, MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE, &port, MACH_PORT_NULL); if (kr != KERN_SUCCESS) return kInvalidSharedMemoryHandle; return SharedMemoryHandleFromMachMemoryEntry(port); } // static void OS::DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle) { DCHECK_NE(kInvalidSharedMemoryHandle, handle); mach_port_t port = MachMemoryEntryFromSharedMemoryHandle(handle); CHECK_EQ(KERN_SUCCESS, mach_port_deallocate(mach_task_self(), port)); } // static void* OS::AllocateShared(void* hint, size_t size, MemoryPermission access, PlatformSharedMemoryHandle handle, uint64_t offset) { DCHECK_EQ(0, size % AllocatePageSize()); mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(hint); vm_prot_t prot = GetVMProtFromMemoryPermission(access); mach_port_t shared_mem_port = MachMemoryEntryFromSharedMemoryHandle(handle); kern_return_t kr = mach_vm_map_wrapper(&addr, size, VM_FLAGS_FIXED, shared_mem_port, offset, prot); if (kr != KERN_SUCCESS) { // Retry without hint. kr = mach_vm_map_wrapper(&addr, size, VM_FLAGS_ANYWHERE, shared_mem_port, offset, prot); } if (kr != KERN_SUCCESS) return nullptr; return reinterpret_cast<void*>(addr); } // static bool OS::RemapPages(const void* address, size_t size, void* new_address, MemoryPermission access) { DCHECK(IsAligned(reinterpret_cast<uintptr_t>(address), AllocatePageSize())); DCHECK( IsAligned(reinterpret_cast<uintptr_t>(new_address), AllocatePageSize())); DCHECK(IsAligned(size, AllocatePageSize())); vm_prot_t cur_protection = GetVMProtFromMemoryPermission(access); vm_prot_t max_protection; // Asks the kernel to remap *on top* of an existing mapping, rather than // copying the data. int flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE; mach_vm_address_t target = reinterpret_cast<mach_vm_address_t>(new_address); kern_return_t ret = mach_vm_remap(mach_task_self(), &target, size, 0, flags, mach_task_self(), reinterpret_cast<mach_vm_address_t>(address), FALSE, &cur_protection, &max_protection, VM_INHERIT_NONE); if (ret != KERN_SUCCESS) return false; // Did we get the address we wanted? CHECK_EQ(new_address, reinterpret_cast<void*>(target)); return true; } bool AddressSpaceReservation::AllocateShared(void* address, size_t size, OS::MemoryPermission access, PlatformSharedMemoryHandle handle, uint64_t offset) { DCHECK(Contains(address, size)); vm_prot_t prot = GetVMProtFromMemoryPermission(access); mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(address); mach_port_t shared_mem_port = MachMemoryEntryFromSharedMemoryHandle(handle); kern_return_t kr = mach_vm_map_wrapper(&addr, size, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, shared_mem_port, offset, prot); return kr == KERN_SUCCESS; } } // namespace base } // namespace v8