Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
virtual_memory_posix.cc
Go to the documentation of this file.
1// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX) || \
7 defined(DART_HOST_OS_MACOS)
8
10
11#include <errno.h>
12#include <sys/mman.h>
13#include <unistd.h>
14
15#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
16#include <sys/prctl.h>
17#endif
18
19#include "platform/assert.h"
20#include "platform/utils.h"
21
22namespace dart {
23namespace bin {
24
25// standard MAP_FAILED causes "error: use of old-style cast" as it
26// defines MAP_FAILED as ((void *) -1)
27#undef MAP_FAILED
28#define MAP_FAILED reinterpret_cast<void*>(-1)
29
30uword VirtualMemory::page_size_ = 0;
31
32intptr_t VirtualMemory::CalculatePageSize() {
33 const intptr_t page_size = getpagesize();
34 ASSERT(page_size != 0);
35 ASSERT(Utils::IsPowerOfTwo(page_size));
36 return page_size;
37}
38
39VirtualMemory* VirtualMemory::Allocate(intptr_t size,
40 bool is_executable,
41 const char* name) {
43
44 const int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
45
46 int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
47#if (defined(DART_HOST_OS_MACOS) && !defined(DART_HOST_OS_IOS))
48 if (is_executable && IsAtLeastOS10_14()) {
49 map_flags |= MAP_JIT;
50 }
51#endif // defined(DART_HOST_OS_MACOS)
52
53 // Some 64-bit microarchitectures store only the low 32-bits of targets as
54 // part of indirect branch prediction, predicting that the target's upper bits
55 // will be same as the call instruction's address. This leads to misprediction
56 // for indirect calls crossing a 4GB boundary. We ask mmap to place our
57 // generated code near the VM binary to avoid this.
58 void* hint = is_executable ? reinterpret_cast<void*>(&Allocate) : nullptr;
59 void* address = mmap(hint, size, prot, map_flags, -1, 0);
60#if defined(DART_HOST_OS_LINUX)
61 // On WSL 1 trying to allocate memory close to the binary by supplying a hint
62 // fails with ENOMEM for unclear reason. Some reports suggest that this might
63 // be related to the alignment of the hint but aligning it by 64Kb does not
64 // make the issue go away in our experiments. Instead just retry without any
65 // hint.
66 if (address == MAP_FAILED && hint != nullptr &&
67 Utils::IsWindowsSubsystemForLinux()) {
68 address = mmap(nullptr, size, prot, map_flags, -1, 0);
69 }
70#endif
71 if (address == MAP_FAILED) {
72 return nullptr;
73 }
74
75#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
76 // PR_SET_VMA was only added to mainline Linux in 5.17, and some versions of
77 // the Android NDK have incorrect headers, so we manually define it if absent.
78#if !defined(PR_SET_VMA)
79#define PR_SET_VMA 0x53564d41
80#endif
81#if !defined(PR_SET_VMA_ANON_NAME)
82#define PR_SET_VMA_ANON_NAME 0
83#endif
84 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, address, size, name);
85#endif
86
87 return new VirtualMemory(address, size);
88}
89
91 if (address_ != nullptr) {
92 if (munmap(address_, size_) != 0) {
93 int error = errno;
94 const int kBufferSize = 1024;
95 char error_buf[kBufferSize];
96 FATAL("munmap error: %d (%s)", error,
97 Utils::StrError(error, error_buf, kBufferSize));
98 }
99 }
100}
101
102void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
103 uword start_address = reinterpret_cast<uword>(address);
104 uword end_address = start_address + size;
105 uword page_address = Utils::RoundDown(start_address, PageSize());
106 int prot = 0;
107 switch (mode) {
108 case kNoAccess:
109 prot = PROT_NONE;
110 break;
111 case kReadOnly:
112 prot = PROT_READ;
113 break;
114 case kReadWrite:
115 prot = PROT_READ | PROT_WRITE;
116 break;
117 case kReadExecute:
118 prot = PROT_READ | PROT_EXEC;
119 break;
121 prot = PROT_READ | PROT_WRITE | PROT_EXEC;
122 break;
123 }
124 if (mprotect(reinterpret_cast<void*>(page_address),
125 end_address - page_address, prot) != 0) {
126 int error = errno;
127 const int kBufferSize = 1024;
128 char error_buf[kBufferSize];
129 FATAL("mprotect error: %d (%s)", error,
130 Utils::StrError(error, error_buf, kBufferSize));
131 }
132}
133
134} // namespace bin
135} // namespace dart
136
137#endif // defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX) || \
138 // defined(DART_HOST_OS_MACOS)
static const size_t kBufferSize
Definition SkString.cpp:27
static char * StrError(int err, char *buffer, size_t bufsize)
static constexpr T RoundDown(T x, intptr_t alignment)
Definition utils.h:93
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:77
static constexpr bool IsPowerOfTwo(T x)
Definition utils.h:61
static VirtualMemory * Allocate(intptr_t size, bool is_executable, const char *name)
static void Protect(void *address, intptr_t size, Protection mode)
static intptr_t PageSize()
#define ASSERT(E)
#define FATAL(error)
const uint8_t uint32_t uint32_t GError ** error
const char *const name
uintptr_t uword
Definition globals.h:501