1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include "precompiled.hpp" 25 #include "gc/z/zMapper_windows.hpp" 26 #include "gc/z/zSyscall_windows.hpp" 27 #include "logging/log.hpp" 28 #include "utilities/debug.hpp" 29 30 #include <Windows.h> 31 32 // Memory reservation, commit, views, and placeholders. 33 // 34 // To be able to up-front reserve address space for the heap views, and later 35 // multi-map the heap views to the same physical memory, without ever losing the 36 // reservation of the reserved address space, we use "placeholders". 37 // 38 // These placeholders block out the address space from being used by other parts 39 // of the process. To commit memory in this address space, the placeholder must 40 // be replaced by anonymous memory, or replaced by mapping a view against a 41 // paging file mapping. We use the later to support multi-mapping. 42 // 43 // We want to be able to dynamically commit and uncommit the physical memory of 44 // the heap (and also unmap ZPages), in granules of ZGranuleSize bytes. There is 45 // no way to grow and shrink the committed memory of a paging file mapping. 46 // Therefore, we create multiple granule-sized page file mappings. The memory is 47 // committed by creating a page file mapping, map a view against it, commit the 48 // memory, unmap the view. The memory will stay committed until all views are 49 // unmapped, and the paging file mapping handle is closed. 50 // 51 // When replacing a placeholder address space reservation with a mapped view 52 // against a paging file mapping, the virtual address space must exactly match 53 // an existing placeholder's address and size. Therefore we only deal with 54 // granule-sized placeholders at this layer. Higher layers that keep track of 55 // reserved available address space can (and will) coalesce placeholders, but 56 // they will be split before being used. 57 58 #define fatal_error(msg, addr, size) \ 59 fatal(msg ": " PTR_FORMAT " " SIZE_FORMAT "M (%d)", \ 60 (addr), (size) / M, GetLastError()) 61 62 uintptr_t ZMapper::reserve(uintptr_t addr, size_t size) { 63 void* const res = ZSyscall::VirtualAlloc2( 64 GetCurrentProcess(), // Process 65 (void*)addr, // BaseAddress 66 size, // Size 67 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, // AllocationType 68 PAGE_NOACCESS, // PageProtection 69 NULL, // ExtendedParameters 70 0 // ParameterCount 71 ); 72 73 // Caller responsible for error handling 74 return (uintptr_t)res; 75 } 76 77 void ZMapper::unreserve(uintptr_t addr, size_t size) { 78 const bool res = ZSyscall::VirtualFreeEx( 79 GetCurrentProcess(), // hProcess 80 (void*)addr, // lpAddress 81 size, // dwSize 82 MEM_RELEASE // dwFreeType 83 ); 84 85 if (!res) { 86 fatal_error("Failed to unreserve memory", addr, size); 87 } 88 } 89 90 HANDLE ZMapper::create_paging_file_mapping(size_t size) { 91 // Create mapping with SEC_RESERVE instead of SEC_COMMIT. 92 // 93 // We use MapViewOfFile3 for two different reasons: 94 // 1) When commiting memory for the created paging file 95 // 2) When mapping a view of the memory created in (2) 96 // 97 // The non-platform code is only setup to deal with out-of-memory 98 // errors in (1). By using SEC_RESERVE, we prevent MapViewOfFile3 99 // from failing because of "commit limit" checks. To actually commit 100 // memory in (1), a call to VirtualAlloc2 is done. 101 102 HANDLE const res = ZSyscall::CreateFileMappingW( 103 INVALID_HANDLE_VALUE, // hFile 104 NULL, // lpFileMappingAttribute 105 PAGE_READWRITE | SEC_RESERVE, // flProtect 106 size >> 32, // dwMaximumSizeHigh 107 size & 0xFFFFFFFF, // dwMaximumSizeLow 108 NULL // lpName 109 ); 110 111 // Caller responsible for error handling 112 return res; 113 } 114 115 bool ZMapper::commit_paging_file_mapping(HANDLE file_handle, uintptr_t file_offset, size_t size) { 116 const uintptr_t addr = map_view_no_placeholder(file_handle, file_offset, size); 117 if (addr == 0) { 118 log_error(gc)("Failed to map view of paging file mapping (%d)", GetLastError()); 119 return false; 120 } 121 122 const uintptr_t res = commit(addr, size); 123 if (res != addr) { 124 log_error(gc)("Failed to commit memory (%d)", GetLastError()); 125 } 126 127 unmap_view_no_placeholder(addr, size); 128 129 return res == addr; 130 } 131 132 uintptr_t ZMapper::map_view_no_placeholder(HANDLE file_handle, uintptr_t file_offset, size_t size) { 133 void* const res = ZSyscall::MapViewOfFile3( 134 file_handle, // FileMapping 135 GetCurrentProcess(), // ProcessHandle 136 NULL, // BaseAddress 137 file_offset, // Offset 138 size, // ViewSize 139 0, // AllocationType 140 PAGE_NOACCESS, // PageProtection 141 NULL, // ExtendedParameters 142 0 // ParameterCount 143 ); 144 145 // Caller responsible for error handling 146 return (uintptr_t)res; 147 } 148 149 void ZMapper::unmap_view_no_placeholder(uintptr_t addr, size_t size) { 150 const bool res = ZSyscall::UnmapViewOfFile2( 151 GetCurrentProcess(), // ProcessHandle 152 (void*)addr, // BaseAddress 153 0 // UnmapFlags 154 ); 155 156 if (!res) { 157 fatal_error("Failed to unmap memory", addr, size); 158 } 159 } 160 161 uintptr_t ZMapper::commit(uintptr_t addr, size_t size) { 162 void* const res = ZSyscall::VirtualAlloc2( 163 GetCurrentProcess(), // Process 164 (void*)addr, // BaseAddress 165 size, // Size 166 MEM_COMMIT, // AllocationType 167 PAGE_NOACCESS, // PageProtection 168 NULL, // ExtendedParameters 169 0 // ParameterCount 170 ); 171 172 // Caller responsible for error handling 173 return (uintptr_t)res; 174 } 175 176 HANDLE ZMapper::create_and_commit_paging_file_mapping(size_t size) { 177 HANDLE const file_handle = create_paging_file_mapping(size); 178 if (file_handle == 0) { 179 log_error(gc)("Failed to create paging file mapping (%d)", GetLastError()); 180 return 0; 181 } 182 183 const bool res = commit_paging_file_mapping(file_handle, 0 /* file_offset */, size); 184 if (!res) { 185 close_paging_file_mapping(file_handle); 186 return 0; 187 } 188 189 return file_handle; 190 } 191 192 void ZMapper::close_paging_file_mapping(HANDLE file_handle) { 193 const bool res = CloseHandle( 194 file_handle // hObject 195 ); 196 197 if (!res) { 198 fatal("Failed to close paging file handle (%d)", GetLastError()); 199 } 200 } 201 202 void ZMapper::split_placeholder(uintptr_t addr, size_t size) { 203 const bool res = VirtualFree( 204 (void*)addr, // lpAddress 205 size, // dwSize 206 MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER // dwFreeType 207 ); 208 209 if (!res) { 210 fatal_error("Failed to split placeholder", addr, size); 211 } 212 } 213 214 void ZMapper::coalesce_placeholders(uintptr_t addr, size_t size) { 215 const bool res = VirtualFree( 216 (void*)addr, // lpAddress 217 size, // dwSize 218 MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS // dwFreeType 219 ); 220 221 if (!res) { 222 fatal_error("Failed to coalesce placeholders", addr, size); 223 } 224 } 225 226 void ZMapper::map_view_replace_placeholder(HANDLE file_handle, uintptr_t file_offset, uintptr_t addr, size_t size) { 227 void* const res = ZSyscall::MapViewOfFile3( 228 file_handle, // FileMapping 229 GetCurrentProcess(), // ProcessHandle 230 (void*)addr, // BaseAddress 231 file_offset, // Offset 232 size, // ViewSize 233 MEM_REPLACE_PLACEHOLDER, // AllocationType 234 PAGE_READWRITE, // PageProtection 235 NULL, // ExtendedParameters 236 0 // ParameterCount 237 ); 238 239 if (res == NULL) { 240 fatal_error("Failed to map memory", addr, size); 241 } 242 } 243 244 void ZMapper::unmap_view_preserve_placeholder(uintptr_t addr, size_t size) { 245 const bool res = ZSyscall::UnmapViewOfFile2( 246 GetCurrentProcess(), // ProcessHandle 247 (void*)addr, // BaseAddress 248 MEM_PRESERVE_PLACEHOLDER // UnmapFlags 249 ); 250 251 if (!res) { 252 fatal_error("Failed to unmap memory", addr, size); 253 } 254 }