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