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