blob: 1512cada80a17f36adbbf669c677a4cc591ef83b [file] [log] [blame]
Nicolas Geoffray2a905b22019-06-06 09:04:07 +01001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_JIT_JIT_MEMORY_REGION_H_
18#define ART_RUNTIME_JIT_JIT_MEMORY_REGION_H_
19
20#include <string>
21
22#include "base/globals.h"
23#include "base/locks.h"
24#include "base/mem_map.h"
25
26namespace art {
27namespace jit {
28
Nicolas Geoffray2411f492019-06-14 08:54:46 +010029class TestZygoteMemory;
30
Nicolas Geoffray2a905b22019-06-06 09:04:07 +010031// Alignment in bytes that will suit all architectures for JIT code cache allocations. The
32// allocated block is used for method header followed by generated code. Allocations should be
33// aligned to avoid sharing cache lines between different allocations. The alignment should be
34// determined from the hardware, but this isn't readily exposed in userland plus some hardware
35// misreports.
36static constexpr int kJitCodeAlignment = 64;
37
38// Represents a memory region for the JIT, where code and data are stored. This class
39// provides allocation and deallocation primitives.
40class JitMemoryRegion {
41 public:
42 JitMemoryRegion()
Nicolas Geoffray9c54e182019-06-18 10:42:52 +010043 : initial_capacity_(0),
44 max_capacity_(0),
45 current_capacity_(0),
46 data_end_(0),
47 exec_end_(0),
48 used_memory_for_code_(0),
49 used_memory_for_data_(0),
50 exec_pages_(),
51 non_exec_pages_(),
52 data_mspace_(nullptr),
53 exec_mspace_(nullptr) {}
Nicolas Geoffray2a905b22019-06-06 09:04:07 +010054
Nicolas Geoffray9c54e182019-06-18 10:42:52 +010055 bool Initialize(size_t initial_capacity,
56 size_t max_capacity,
57 bool rwx_memory_allowed,
58 bool is_zygote,
59 std::string* error_msg)
Nicolas Geoffray2a905b22019-06-06 09:04:07 +010060 REQUIRES(Locks::jit_lock_);
61
Nicolas Geoffray2a905b22019-06-06 09:04:07 +010062 // Try to increase the current capacity of the code cache. Return whether we
63 // succeeded at doing so.
64 bool IncreaseCodeCacheCapacity() REQUIRES(Locks::jit_lock_);
65
66 // Set the footprint limit of the code cache.
67 void SetFootprintLimit(size_t new_footprint) REQUIRES(Locks::jit_lock_);
68 uint8_t* AllocateCode(size_t code_size) REQUIRES(Locks::jit_lock_);
69 void FreeCode(uint8_t* code) REQUIRES(Locks::jit_lock_);
70 uint8_t* AllocateData(size_t data_size) REQUIRES(Locks::jit_lock_);
71 void FreeData(uint8_t* data) REQUIRES(Locks::jit_lock_);
72
73 bool HasDualCodeMapping() const {
74 return non_exec_pages_.IsValid();
75 }
76
77 bool HasCodeMapping() const {
78 return exec_pages_.IsValid();
79 }
80
81 bool IsInDataSpace(const void* ptr) const {
82 return data_pages_.HasAddress(ptr);
83 }
84
85 bool IsInExecSpace(const void* ptr) const {
86 return exec_pages_.HasAddress(ptr);
87 }
88
89 const MemMap* GetUpdatableCodeMapping() const {
90 if (HasDualCodeMapping()) {
91 return &non_exec_pages_;
92 } else if (HasCodeMapping()) {
93 return &exec_pages_;
94 } else {
95 return nullptr;
96 }
97 }
98
99 const MemMap* GetExecPages() const {
100 return &exec_pages_;
101 }
102
103 template <typename T> T* GetExecutableAddress(T* src_ptr) {
104 return TranslateAddress(src_ptr, non_exec_pages_, exec_pages_);
105 }
106
107 template <typename T> T* GetNonExecutableAddress(T* src_ptr) {
108 return TranslateAddress(src_ptr, exec_pages_, non_exec_pages_);
109 }
110
111 void* MoreCore(const void* mspace, intptr_t increment);
112
113 bool OwnsSpace(const void* mspace) const NO_THREAD_SAFETY_ANALYSIS {
114 return mspace == data_mspace_ || mspace == exec_mspace_;
115 }
116
117 size_t GetCurrentCapacity() const REQUIRES(Locks::jit_lock_) {
118 return current_capacity_;
119 }
120
121 size_t GetMaxCapacity() const REQUIRES(Locks::jit_lock_) {
122 return max_capacity_;
123 }
124
125 size_t GetUsedMemoryForCode() const REQUIRES(Locks::jit_lock_) {
126 return used_memory_for_code_;
127 }
128
129 size_t GetUsedMemoryForData() const REQUIRES(Locks::jit_lock_) {
130 return used_memory_for_data_;
131 }
132
133 private:
134 template <typename T>
135 T* TranslateAddress(T* src_ptr, const MemMap& src, const MemMap& dst) {
136 if (!HasDualCodeMapping()) {
137 return src_ptr;
138 }
139 CHECK(src.HasAddress(src_ptr));
140 uint8_t* const raw_src_ptr = reinterpret_cast<uint8_t*>(src_ptr);
141 return reinterpret_cast<T*>(raw_src_ptr - src.Begin() + dst.Begin());
142 }
143
Nicolas Geoffray2411f492019-06-14 08:54:46 +0100144 static int CreateZygoteMemory(size_t capacity, std::string* error_msg);
145 static bool ProtectZygoteMemory(int fd, std::string* error_msg);
146
Nicolas Geoffray2a905b22019-06-06 09:04:07 +0100147 // The initial capacity in bytes this code region starts with.
148 size_t initial_capacity_ GUARDED_BY(Locks::jit_lock_);
149
150 // The maximum capacity in bytes this region can go to.
151 size_t max_capacity_ GUARDED_BY(Locks::jit_lock_);
152
153 // The current capacity in bytes of the region.
154 size_t current_capacity_ GUARDED_BY(Locks::jit_lock_);
155
156 // The current footprint in bytes of the data portion of the region.
157 size_t data_end_ GUARDED_BY(Locks::jit_lock_);
158
159 // The current footprint in bytes of the code portion of the region.
160 size_t exec_end_ GUARDED_BY(Locks::jit_lock_);
161
162 // The size in bytes of used memory for the code portion of the region.
163 size_t used_memory_for_code_ GUARDED_BY(Locks::jit_lock_);
164
165 // The size in bytes of used memory for the data portion of the region.
166 size_t used_memory_for_data_ GUARDED_BY(Locks::jit_lock_);
167
168 // Mem map which holds data (stack maps and profiling info).
169 MemMap data_pages_;
170
171 // Mem map which holds code and has executable permission.
172 MemMap exec_pages_;
173
174 // Mem map which holds code with non executable permission. Only valid for dual view JIT when
175 // this is the non-executable view of code used to write updates.
176 MemMap non_exec_pages_;
177
178 // The opaque mspace for allocating data.
179 void* data_mspace_ GUARDED_BY(Locks::jit_lock_);
180
181 // The opaque mspace for allocating code.
182 void* exec_mspace_ GUARDED_BY(Locks::jit_lock_);
Nicolas Geoffray2411f492019-06-14 08:54:46 +0100183
184 friend class TestZygoteMemory;
Nicolas Geoffray2a905b22019-06-06 09:04:07 +0100185};
186
187} // namespace jit
188} // namespace art
189
190#endif // ART_RUNTIME_JIT_JIT_MEMORY_REGION_H_