1 /*
   2  * Copyright (c) 2018, 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 
  25 #ifndef SHARE_GC_SHARED_OOPSTORAGE_INLINE_HPP
  26 #define SHARE_GC_SHARED_OOPSTORAGE_INLINE_HPP
  27 
  28 #include "gc/shared/oopStorage.hpp"
  29 #include "memory/allocation.hpp"
  30 #include "metaprogramming/conditional.hpp"
  31 #include "metaprogramming/isConst.hpp"
  32 #include "oops/oop.hpp"
  33 #include "runtime/safepoint.hpp"
  34 #include "utilities/count_trailing_zeros.hpp"
  35 #include "utilities/debug.hpp"
  36 #include "utilities/globalDefinitions.hpp"
  37 
  38 class OopStorage::Block /* No base class, to avoid messing up alignment. */ {
  39   // _data must be the first non-static data member, for alignment.
  40   oop _data[BitsPerWord];
  41   static const unsigned _data_pos = 0; // Position of _data.
  42 
  43   volatile uintx _allocated_bitmask; // One bit per _data element.
  44   const OopStorage* _owner;
  45   void* _memory;              // Unaligned storage containing block.
  46   BlockEntry _active_entry;
  47   BlockEntry _allocate_entry;
  48   Block* volatile _deferred_updates_next;
  49   volatile uintx _release_refcount;
  50 
  51   Block(const OopStorage* owner, void* memory);
  52   ~Block();
  53 
  54   void check_index(unsigned index) const;
  55   unsigned get_index(const oop* ptr) const;
  56 
  57   template<typename F, typename BlockPtr>
  58   static bool iterate_impl(F f, BlockPtr b);
  59 
  60   // Noncopyable.
  61   Block(const Block&);
  62   Block& operator=(const Block&);
  63 
  64 public:
  65   static const BlockEntry& get_active_entry(const Block& block);
  66   static const BlockEntry& get_allocate_entry(const Block& block);
  67 
  68   static size_t allocation_size();
  69   static size_t allocation_alignment_shift();
  70 
  71   oop* get_pointer(unsigned index);
  72   const oop* get_pointer(unsigned index) const;
  73 
  74   uintx bitmask_for_index(unsigned index) const;
  75   uintx bitmask_for_entry(const oop* ptr) const;
  76 
  77   // Allocation bitmask accessors are racy.
  78   bool is_full() const;
  79   bool is_empty() const;
  80   uintx allocated_bitmask() const;
  81   bool is_deletable() const;
  82 
  83   Block* deferred_updates_next() const;
  84   void set_deferred_updates_next(Block* new_next);
  85 
  86   bool contains(const oop* ptr) const;
  87 
  88   // Returns NULL if ptr is not in a block or not allocated in that block.
  89   static Block* block_for_ptr(const OopStorage* owner, const oop* ptr);
  90 
  91   oop* allocate();
  92   static Block* new_block(const OopStorage* owner);
  93   static void delete_block(const Block& block);
  94 
  95   void release_entries(uintx releasing, Block* volatile* deferred_list);
  96 
  97   template<typename F> bool iterate(F f);
  98   template<typename F> bool iterate(F f) const;
  99 }; // class Block
 100 
 101 inline OopStorage::Block* OopStorage::BlockList::head() {
 102   return const_cast<Block*>(_head);
 103 }
 104 
 105 inline const OopStorage::Block* OopStorage::BlockList::chead() const {
 106   return _head;
 107 }
 108 
 109 inline const OopStorage::Block* OopStorage::BlockList::ctail() const {
 110   return _tail;
 111 }
 112 
 113 inline OopStorage::Block* OopStorage::BlockList::prev(Block& block) {
 114   return const_cast<Block*>(_get_entry(block)._prev);
 115 }
 116 
 117 inline OopStorage::Block* OopStorage::BlockList::next(Block& block) {
 118   return const_cast<Block*>(_get_entry(block)._next);
 119 }
 120 
 121 inline const OopStorage::Block* OopStorage::BlockList::prev(const Block& block) const {
 122   return _get_entry(block)._prev;
 123 }
 124 
 125 inline const OopStorage::Block* OopStorage::BlockList::next(const Block& block) const {
 126   return _get_entry(block)._next;
 127 }
 128 
 129 template<typename Closure>
 130 class OopStorage::OopFn VALUE_OBJ_CLASS_SPEC {
 131 public:
 132   explicit OopFn(Closure* cl) : _cl(cl) {}
 133 
 134   template<typename OopPtr>     // [const] oop*
 135   bool operator()(OopPtr ptr) const {
 136     _cl->do_oop(ptr);
 137     return true;
 138   }
 139 
 140 private:
 141   Closure* _cl;
 142 };
 143 
 144 template<typename Closure>
 145 inline OopStorage::OopFn<Closure> OopStorage::oop_fn(Closure* cl) {
 146   return OopFn<Closure>(cl);
 147 }
 148 
 149 template<typename IsAlive, typename F>
 150 class OopStorage::IfAliveFn VALUE_OBJ_CLASS_SPEC {
 151 public:
 152   IfAliveFn(IsAlive* is_alive, F f) : _is_alive(is_alive), _f(f) {}
 153 
 154   bool operator()(oop* ptr) const {
 155     bool result = true;
 156     oop v = *ptr;
 157     if (v != NULL) {
 158       if (_is_alive->do_object_b(v)) {
 159         result = _f(ptr);
 160       } else {
 161         *ptr = NULL;            // Clear dead value.
 162       }
 163     }
 164     return result;
 165   }
 166 
 167 private:
 168   IsAlive* _is_alive;
 169   F _f;
 170 };
 171 
 172 template<typename IsAlive, typename F>
 173 inline OopStorage::IfAliveFn<IsAlive, F> OopStorage::if_alive_fn(IsAlive* is_alive, F f) {
 174   return IfAliveFn<IsAlive, F>(is_alive, f);
 175 }
 176 
 177 template<typename F>
 178 class OopStorage::SkipNullFn VALUE_OBJ_CLASS_SPEC {
 179 public:
 180   SkipNullFn(F f) : _f(f) {}
 181 
 182   template<typename OopPtr>     // [const] oop*
 183   bool operator()(OopPtr ptr) const {
 184     return (*ptr != NULL) ? _f(ptr) : true;
 185   }
 186 
 187 private:
 188   F _f;
 189 };
 190 
 191 template<typename F>
 192 inline OopStorage::SkipNullFn<F> OopStorage::skip_null_fn(F f) {
 193   return SkipNullFn<F>(f);
 194 }
 195 
 196 // Inline Block accesses for use in iteration inner loop.
 197 
 198 inline void OopStorage::Block::check_index(unsigned index) const {
 199   assert(index < ARRAY_SIZE(_data), "Index out of bounds: %u", index);
 200 }
 201 
 202 inline oop* OopStorage::Block::get_pointer(unsigned index) {
 203   check_index(index);
 204   return &_data[index];
 205 }
 206 
 207 inline const oop* OopStorage::Block::get_pointer(unsigned index) const {
 208   check_index(index);
 209   return &_data[index];
 210 }
 211 
 212 inline uintx OopStorage::Block::allocated_bitmask() const {
 213   return _allocated_bitmask;
 214 }
 215 
 216 inline uintx OopStorage::Block::bitmask_for_index(unsigned index) const {
 217   check_index(index);
 218   return uintx(1) << index;
 219 }
 220 
 221 // Provide const or non-const iteration, depending on whether BlockPtr
 222 // is const Block* or Block*, respectively.
 223 template<typename F, typename BlockPtr> // BlockPtr := [const] Block*
 224 inline bool OopStorage::Block::iterate_impl(F f, BlockPtr block) {
 225   uintx bitmask = block->allocated_bitmask();
 226   while (bitmask != 0) {
 227     unsigned index = count_trailing_zeros(bitmask);
 228     bitmask ^= block->bitmask_for_index(index);
 229     if (!f(block->get_pointer(index))) {
 230       return false;
 231     }
 232   }
 233   return true;
 234 }
 235 
 236 template<typename F>
 237 inline bool OopStorage::Block::iterate(F f) {
 238   return iterate_impl(f, this);
 239 }
 240 
 241 template<typename F>
 242 inline bool OopStorage::Block::iterate(F f) const {
 243   return iterate_impl(f, this);
 244 }
 245 
 246 //////////////////////////////////////////////////////////////////////////////
 247 // Support for serial iteration, always at a safepoint.
 248 
 249 // Provide const or non-const iteration, depending on whether Storage is
 250 // const OopStorage* or OopStorage*, respectively.
 251 template<typename F, typename Storage> // Storage := [const] OopStorage
 252 inline bool OopStorage::iterate_impl(F f, Storage* storage) {
 253   assert_at_safepoint();
 254   // Propagate const/non-const iteration to the block layer, by using
 255   // const or non-const blocks as corresponding to Storage.
 256   typedef typename Conditional<IsConst<Storage>::value, const Block*, Block*>::type BlockPtr;
 257   for (BlockPtr block = storage->_active_head;
 258        block != NULL;
 259        block = storage->_active_list.next(*block)) {
 260     if (!block->iterate(f)) {
 261       return false;
 262     }
 263   }
 264   return true;
 265 }
 266 
 267 template<typename F>
 268 inline bool OopStorage::iterate_safepoint(F f) {
 269   return iterate_impl(f, this);
 270 }
 271 
 272 template<typename F>
 273 inline bool OopStorage::iterate_safepoint(F f) const {
 274   return iterate_impl(f, this);
 275 }
 276 
 277 template<typename Closure>
 278 inline void OopStorage::oops_do(Closure* cl) {
 279   iterate_safepoint(oop_fn(cl));
 280 }
 281 
 282 template<typename Closure>
 283 inline void OopStorage::oops_do(Closure* cl) const {
 284   iterate_safepoint(oop_fn(cl));
 285 }
 286 
 287 template<typename Closure>
 288 inline void OopStorage::weak_oops_do(Closure* cl) {
 289   iterate_safepoint(skip_null_fn(oop_fn(cl)));
 290 }
 291 
 292 template<typename IsAliveClosure, typename Closure>
 293 inline void OopStorage::weak_oops_do(IsAliveClosure* is_alive, Closure* cl) {
 294   iterate_safepoint(if_alive_fn(is_alive, oop_fn(cl)));
 295 }
 296 
 297 #endif // include guard