Flutter Engine
The Flutter Engine
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)
Definition: utils_android.h:40
static constexpr T RoundDown(T x, intptr_t alignment)
Definition: utils.h:108
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition: utils.h:92
static constexpr bool IsPowerOfTwo(T x)
Definition: utils.h:76
intptr_t size() const
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
Definition: dart_vm.cc:33
const char *const name
uintptr_t uword
Definition: globals.h:501
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259