1 /* 2 * Copyright (c) 2015, 2017, 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 #ifndef SHARE_GC_Z_ZPAGE_INLINE_HPP 25 #define SHARE_GC_Z_ZPAGE_INLINE_HPP 26 27 #include "gc/z/zAddress.inline.hpp" 28 #include "gc/z/zForwardingTable.inline.hpp" 29 #include "gc/z/zGlobals.hpp" 30 #include "gc/z/zLiveMap.inline.hpp" 31 #include "gc/z/zMark.hpp" 32 #include "gc/z/zNUMA.hpp" 33 #include "gc/z/zPage.hpp" 34 #include "gc/z/zPhysicalMemory.inline.hpp" 35 #include "gc/z/zUtils.inline.hpp" 36 #include "gc/z/zVirtualMemory.inline.hpp" 37 #include "oops/oop.inline.hpp" 38 #include "runtime/atomic.hpp" 39 #include "utilities/align.hpp" 40 #include "utilities/debug.hpp" 41 42 inline const char* ZPage::type_to_string() const { 43 switch (type()) { 44 case ZPageTypeSmall: 45 return "Small"; 46 47 case ZPageTypeMedium: 48 return "Medium"; 49 50 default: 51 assert(type() == ZPageTypeLarge, "Invalid page type"); 52 return "Large"; 53 } 54 } 55 56 inline uint32_t ZPage::object_max_count() const { 57 switch (type()) { 58 case ZPageTypeLarge: 59 // A large page can only contain a single 60 // object aligned to the start of the page. 61 return 1; 62 63 default: 64 return (uint32_t)(size() >> object_alignment_shift()); 65 } 66 } 67 68 inline size_t ZPage::object_alignment_shift() const { 69 switch (type()) { 70 case ZPageTypeSmall: 71 return ZObjectAlignmentSmallShift; 72 73 case ZPageTypeMedium: 74 return ZObjectAlignmentMediumShift; 75 76 default: 77 assert(type() == ZPageTypeLarge, "Invalid page type"); 78 return ZObjectAlignmentLargeShift; 79 } 80 } 81 82 inline size_t ZPage::object_alignment() const { 83 switch (type()) { 84 case ZPageTypeSmall: 85 return ZObjectAlignmentSmall; 86 87 case ZPageTypeMedium: 88 return ZObjectAlignmentMedium; 89 90 default: 91 assert(type() == ZPageTypeLarge, "Invalid page type"); 92 return ZObjectAlignmentLarge; 93 } 94 } 95 96 inline uint8_t ZPage::type() const { 97 return _type; 98 } 99 100 inline uintptr_t ZPage::start() const { 101 return _virtual.start(); 102 } 103 104 inline uintptr_t ZPage::end() const { 105 return _virtual.end(); 106 } 107 108 inline size_t ZPage::size() const { 109 return _virtual.size(); 110 } 111 112 inline uintptr_t ZPage::top() const { 113 return _top; 114 } 115 116 inline size_t ZPage::remaining() const { 117 return end() - top(); 118 } 119 120 inline ZPhysicalMemory& ZPage::physical_memory() { 121 return _physical; 122 } 123 124 inline const ZVirtualMemory& ZPage::virtual_memory() const { 125 return _virtual; 126 } 127 128 inline uint8_t ZPage::numa_id() { 129 if (_numa_id == (uint8_t)-1) { 130 _numa_id = (uint8_t)ZNUMA::memory_id(ZAddress::good(start())); 131 } 132 133 return _numa_id; 134 } 135 136 inline bool ZPage::inc_refcount() { 137 for (uint32_t prev_refcount = _refcount; prev_refcount > 0; prev_refcount = _refcount) { 138 if (Atomic::cmpxchg(prev_refcount + 1, &_refcount, prev_refcount) == prev_refcount) { 139 return true; 140 } 141 } 142 return false; 143 } 144 145 inline bool ZPage::dec_refcount() { 146 assert(is_active(), "Should be active"); 147 return Atomic::sub(1u, &_refcount) == 0; 148 } 149 150 inline bool ZPage::is_in(uintptr_t addr) const { 151 const uintptr_t offset = ZAddress::offset(addr); 152 return offset >= start() && offset < top(); 153 } 154 155 inline uintptr_t ZPage::block_start(uintptr_t addr) const { 156 if (block_is_obj(addr)) { 157 return addr; 158 } else { 159 return ZAddress::good(top()); 160 } 161 } 162 163 inline size_t ZPage::block_size(uintptr_t addr) const { 164 if (block_is_obj(addr)) { 165 return ZUtils::object_size(addr); 166 } else { 167 return end() - top(); 168 } 169 } 170 171 inline bool ZPage::block_is_obj(uintptr_t addr) const { 172 return ZAddress::offset(addr) < top(); 173 } 174 175 inline bool ZPage::is_active() const { 176 return _refcount > 0; 177 } 178 179 inline bool ZPage::is_allocating() const { 180 return is_active() && _seqnum == ZGlobalSeqNum; 181 } 182 183 inline bool ZPage::is_relocatable() const { 184 return is_active() && _seqnum < ZGlobalSeqNum; 185 } 186 187 inline bool ZPage::is_detached() const { 188 return _physical.is_null(); 189 } 190 191 inline bool ZPage::is_mapped() const { 192 return _seqnum > 0; 193 } 194 195 inline void ZPage::set_pre_mapped() { 196 // The _seqnum variable is also used to signal that the virtual and physical 197 // memory has been mapped. So, we need to set it to non-zero when the memory 198 // has been pre-mapped. 199 _seqnum = 1; 200 } 201 202 inline bool ZPage::is_pinned() const { 203 return _pinned; 204 } 205 206 inline void ZPage::set_pinned() { 207 _pinned = 1; 208 } 209 210 inline bool ZPage::is_forwarding() const { 211 return !_forwarding.is_null(); 212 } 213 214 inline void ZPage::set_forwarding() { 215 assert(is_marked(), "Should be marked"); 216 _forwarding.setup(_livemap.live_objects()); 217 } 218 219 inline void ZPage::reset_forwarding() { 220 _forwarding.reset(); 221 _pinned = 0; 222 } 223 224 inline void ZPage::verify_forwarding() const { 225 _forwarding.verify(object_max_count(), _livemap.live_objects()); 226 } 227 228 inline bool ZPage::is_marked() const { 229 assert(is_relocatable(), "Invalid page state"); 230 return _livemap.is_marked(); 231 } 232 233 inline bool ZPage::is_object_marked(uintptr_t addr) const { 234 const size_t index = ((ZAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; 235 return _livemap.get(index); 236 } 237 238 inline bool ZPage::is_object_strongly_marked(uintptr_t addr) const { 239 const size_t index = ((ZAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; 240 return _livemap.get(index + 1); 241 } 242 243 inline bool ZPage::is_object_live(uintptr_t addr) const { 244 return is_allocating() || is_object_marked(addr); 245 } 246 247 inline bool ZPage::is_object_strongly_live(uintptr_t addr) const { 248 return is_allocating() || is_object_strongly_marked(addr); 249 } 250 251 inline bool ZPage::mark_object(uintptr_t addr, bool finalizable, bool& inc_live) { 252 assert(ZAddress::is_marked(addr), "Invalid address"); 253 assert(is_relocatable(), "Invalid page state"); 254 assert(is_in(addr), "Invalid address"); 255 256 // Set mark bit 257 const size_t index = ((ZAddress::offset(addr) - start()) >> object_alignment_shift()) * 2; 258 return _livemap.set_atomic(index, finalizable, inc_live); 259 } 260 261 inline void ZPage::inc_live_atomic(uint32_t objects, size_t bytes) { 262 _livemap.inc_live_atomic(objects, bytes); 263 } 264 265 inline size_t ZPage::live_bytes() const { 266 assert(is_marked(), "Should be marked"); 267 return _livemap.live_bytes(); 268 } 269 270 inline void ZPage::object_iterate(ObjectClosure* cl) { 271 _livemap.iterate(cl, ZAddress::good(start()), object_alignment_shift()); 272 } 273 274 inline uintptr_t ZPage::alloc_object(size_t size) { 275 assert(is_allocating(), "Invalid state"); 276 277 const size_t aligned_size = align_up(size, object_alignment()); 278 const uintptr_t addr = top(); 279 const uintptr_t new_top = addr + aligned_size; 280 281 if (new_top > end()) { 282 // Not enough space left 283 return 0; 284 } 285 286 _top = new_top; 287 288 return ZAddress::good(addr); 289 } 290 291 inline uintptr_t ZPage::alloc_object_atomic(size_t size) { 292 assert(is_allocating(), "Invalid state"); 293 294 const size_t aligned_size = align_up(size, object_alignment()); 295 uintptr_t addr = top(); 296 297 for (;;) { 298 const uintptr_t new_top = addr + aligned_size; 299 if (new_top > end()) { 300 // Not enough space left 301 return 0; 302 } 303 304 const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, addr); 305 if (prev_top == addr) { 306 // Success 307 return ZAddress::good(addr); 308 } 309 310 // Retry 311 addr = prev_top; 312 } 313 } 314 315 inline bool ZPage::undo_alloc_object(uintptr_t addr, size_t size) { 316 assert(is_allocating(), "Invalid state"); 317 318 const uintptr_t offset = ZAddress::offset(addr); 319 const size_t aligned_size = align_up(size, object_alignment()); 320 const uintptr_t old_top = top(); 321 const uintptr_t new_top = old_top - aligned_size; 322 323 if (new_top != offset) { 324 // Failed to undo allocation, not the last allocated object 325 return false; 326 } 327 328 _top = new_top; 329 330 // Success 331 return true; 332 } 333 334 inline bool ZPage::undo_alloc_object_atomic(uintptr_t addr, size_t size) { 335 assert(is_allocating(), "Invalid state"); 336 337 const uintptr_t offset = ZAddress::offset(addr); 338 const size_t aligned_size = align_up(size, object_alignment()); 339 uintptr_t old_top = top(); 340 341 for (;;) { 342 const uintptr_t new_top = old_top - aligned_size; 343 if (new_top != offset) { 344 // Failed to undo allocation, not the last allocated object 345 return false; 346 } 347 348 const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, old_top); 349 if (prev_top == old_top) { 350 // Success 351 return true; 352 } 353 354 // Retry 355 old_top = prev_top; 356 } 357 } 358 359 #endif // SHARE_GC_Z_ZPAGE_INLINE_HPP