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