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