// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/virtual_memory.h" #include "platform/assert.h" #include "platform/utils.h" #if defined(DART_HOST_OS_MACOS) #include #endif namespace dart { bool VirtualMemory::InSamePage(uword address0, uword address1) { return (Utils::RoundDown(address0, PageSize()) == Utils::RoundDown(address1, PageSize())); } void VirtualMemory::Truncate(intptr_t new_size) { ASSERT(Utils::IsAligned(new_size, PageSize())); ASSERT(new_size <= size()); if (reserved_.size() == region_.size()) { // Don't create holes in reservation. if (FreeSubSegment(reinterpret_cast(start() + new_size), size() - new_size)) { reserved_.set_size(new_size); } } region_.Subregion(region_, 0, new_size); } VirtualMemory* VirtualMemory::ForImagePage(void* pointer, uword size) { // Memory for precompilated instructions was allocated by the embedder, so // create a VirtualMemory without allocating. MemoryRegion region(pointer, size); MemoryRegion reserved(nullptr, 0); // null reservation indicates VM should // not attempt to free this memory. VirtualMemory* memory = new VirtualMemory(region, reserved); ASSERT(!memory->vm_owns_region()); return memory; } #if !defined(DART_TARGET_OS_FUCHSIA) // TODO(52579): Reenable on Fuchsia. bool VirtualMemory::DuplicateRX(VirtualMemory* target) { const intptr_t aligned_size = Utils::RoundUp(size(), PageSize()); ASSERT_LESS_OR_EQUAL(aligned_size, target->size()); #if defined(DART_HOST_OS_MACOS) && defined(DART_PRECOMPILED_RUNTIME) // Mac is special cased because iOS doesn't allow allocating new executable // memory, so the default approach would fail. We are allowed to make new // mappings of existing executable memory using vm_remap though, which is // effectively the same for non-writable memory. const mach_port_t task = mach_task_self(); const vm_address_t source_address = reinterpret_cast(address()); const vm_size_t mem_size = aligned_size; const vm_prot_t read_execute = VM_PROT_READ | VM_PROT_EXECUTE; vm_prot_t current_protection = read_execute; vm_prot_t max_protection = read_execute; vm_address_t target_address = reinterpret_cast(target->address()); kern_return_t status = vm_remap( task, &target_address, mem_size, /*mask=*/0, /*flags=*/VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, task, source_address, /*copy=*/true, ¤t_protection, &max_protection, /*inheritance=*/VM_INHERIT_NONE); if (status != KERN_SUCCESS) { return false; } ASSERT(reinterpret_cast(target_address) == target->address()); ASSERT_EQUAL(current_protection & read_execute, read_execute); ASSERT_EQUAL(max_protection & read_execute, read_execute); return true; #else // defined(DART_HOST_OS_MACOS) // TODO(52497): Use dual mapping on platforms where it's supported. // Check that target doesn't overlap with this. ASSERT(target->start() >= end() || target->end() <= start()); memcpy(target->address(), address(), size()); // NOLINT Protect(target->address(), aligned_size, kReadExecute); return true; #endif // defined(DART_HOST_OS_MACOS) } #endif // !defined(DART_TARGET_OS_FUCHSIA) } // namespace dart