1 /* 2 * Copyright (c) 2016, 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_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP 26 #define SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP 27 28 #include "jfr/recorder/storage/jfrMemorySpace.hpp" 29 30 template <typename T, template <typename> class RetrievalType, typename Callback> 31 JfrMemorySpace<T, RetrievalType, Callback>:: 32 JfrMemorySpace(size_t min_elem_size, size_t limit_size, size_t cache_count, Callback* callback) : 33 _free(), 34 _full(), 35 _min_elem_size(min_elem_size), 36 _limit_size(limit_size), 37 _cache_count(cache_count), 38 _callback(callback) {} 39 40 template <typename T, template <typename> class RetrievalType, typename Callback> 41 JfrMemorySpace<T, RetrievalType, Callback>::~JfrMemorySpace() { 42 Iterator full_iter(_full); 43 while (full_iter.has_next()) { 44 Type* t = full_iter.next(); 45 _full.remove(t); 46 deallocate(t); 47 } 48 Iterator free_iter(_free); 49 while (free_iter.has_next()) { 50 Type* t = free_iter.next(); 51 _free.remove(t); 52 deallocate(t); 53 } 54 } 55 56 template <typename T, template <typename> class RetrievalType, typename Callback> 57 bool JfrMemorySpace<T, RetrievalType, Callback>::initialize() { 58 assert(_min_elem_size % os::vm_page_size() == 0, "invariant"); 59 assert(_limit_size % os::vm_page_size() == 0, "invariant"); 60 // pre-allocate cache elements 61 for (size_t i = 0; i < _cache_count; ++i) { 62 Type* const t = allocate(_min_elem_size); 63 if (t == NULL) { 64 return false; 65 } 66 insert_free_head(t); 67 } 68 assert(_free.count() == _cache_count, "invariant"); 69 return true; 70 } 71 72 template <typename T, template <typename> class RetrievalType, typename Callback> 73 inline void JfrMemorySpace<T, RetrievalType, Callback>::release_full(T* t) { 74 assert(is_locked(), "invariant"); 75 assert(t != NULL, "invariant"); 76 assert(_full.in_list(t), "invariant"); 77 remove_full(t); 78 assert(!_full.in_list(t), "invariant"); 79 if (t->transient()) { 80 deallocate(t); 81 return; 82 } 83 assert(t->empty(), "invariant"); 84 assert(!t->retired(), "invariant"); 85 assert(t->identity() == NULL, "invariant"); 86 if (should_populate_cache()) { 87 assert(!_free.in_list(t), "invariant"); 88 insert_free_head(t); 89 } else { 90 deallocate(t); 91 } 92 } 93 94 template <typename T, template <typename> class RetrievalType, typename Callback> 95 inline void JfrMemorySpace<T, RetrievalType, Callback>::release_free(T* t) { 96 assert(is_locked(), "invariant"); 97 assert(t != NULL, "invariant"); 98 assert(_free.in_list(t), "invariant"); 99 if (t->transient()) { 100 remove_free(t); 101 assert(!_free.in_list(t), "invariant"); 102 deallocate(t); 103 return; 104 } 105 assert(t->empty(), "invariant"); 106 assert(!t->retired(), "invariant"); 107 assert(t->identity() == NULL, "invariant"); 108 if (!should_populate_cache()) { 109 remove_free(t); 110 assert(!_free.in_list(t), "invariant"); 111 deallocate(t); 112 } 113 } 114 115 template <typename T, template <typename> class RetrievalType, typename Callback> 116 template <typename IteratorCallback, typename IteratorType> 117 inline void JfrMemorySpace<T, RetrievalType, Callback> 118 ::iterate(IteratorCallback& callback, bool full, jfr_iter_direction direction) { 119 IteratorType iterator(full ? _full : _free, direction); 120 while (iterator.has_next()) { 121 callback.process(iterator.next()); 122 } 123 } 124 125 template <typename Mspace> 126 inline size_t size_adjustment(size_t size, Mspace* mspace) { 127 assert(mspace != NULL, "invariant"); 128 static const size_t min_elem_size = mspace->min_elem_size(); 129 if (size < min_elem_size) { 130 size = min_elem_size; 131 } 132 return size; 133 } 134 135 template <typename Mspace> 136 inline typename Mspace::Type* mspace_allocate(size_t size, Mspace* mspace) { 137 return mspace->allocate(size_adjustment(size, mspace)); 138 } 139 140 template <typename Mspace> 141 inline typename Mspace::Type* mspace_allocate_acquired(size_t size, Mspace* mspace, Thread* thread) { 142 typename Mspace::Type* const t = mspace_allocate(size, mspace); 143 if (t == NULL) return NULL; 144 t->acquire(thread); 145 return t; 146 } 147 148 template <typename Mspace> 149 inline typename Mspace::Type* mspace_allocate_transient(size_t size, Mspace* mspace, Thread* thread) { 150 typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread); 151 if (t == NULL) return NULL; 152 assert(t->acquired_by_self(), "invariant"); 153 t->set_transient(); 154 return t; 155 } 156 157 template <typename Mspace> 158 inline typename Mspace::Type* mspace_allocate_transient_lease(size_t size, Mspace* mspace, Thread* thread) { 159 typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread); 160 if (t == NULL) return NULL; 161 assert(t->acquired_by_self(), "invariant"); 162 assert(t->transient(), "invaiant"); 163 t->set_lease(); 164 return t; 165 } 166 167 template <typename Mspace> 168 inline typename Mspace::Type* mspace_allocate_to_full(size_t size, Mspace* mspace, Thread* thread) { 169 assert(mspace->is_locked(), "invariant"); 170 typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread); 171 if (t == NULL) return NULL; 172 mspace->insert_full_head(t); 173 return t; 174 } 175 176 template <typename Mspace> 177 inline typename Mspace::Type* mspace_allocate_transient_to_full(size_t size, Mspace* mspace, Thread* thread) { 178 typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread); 179 if (t == NULL) return NULL; 180 MspaceLock<Mspace> lock(mspace); 181 mspace->insert_full_head(t); 182 return t; 183 } 184 185 template <typename Mspace> 186 inline typename Mspace::Type* mspace_allocate_transient_lease_to_full(size_t size, Mspace* mspace, Thread* thread) { 187 typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread); 188 if (t == NULL) return NULL; 189 assert(t->acquired_by_self(), "invariant"); 190 assert(t->transient(), "invaiant"); 191 assert(t->lease(), "invariant"); 192 MspaceLock<Mspace> lock(mspace); 193 mspace->insert_full_head(t); 194 return t; 195 } 196 197 template <typename Mspace> 198 inline typename Mspace::Type* mspace_allocate_transient_lease_to_free(size_t size, Mspace* mspace, Thread* thread) { 199 typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread); 200 if (t == NULL) return NULL; 201 assert(t->acquired_by_self(), "invariant"); 202 assert(t->transient(), "invaiant"); 203 assert(t->lease(), "invariant"); 204 MspaceLock<Mspace> lock(mspace); 205 mspace->insert_free_head(t); 206 return t; 207 } 208 209 template <typename Mspace> 210 inline typename Mspace::Type* mspace_get_free(size_t size, Mspace* mspace, Thread* thread) { 211 return mspace->get(size, thread); 212 } 213 214 template <typename Mspace> 215 inline typename Mspace::Type* mspace_get_free_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) { 216 assert(size <= mspace->min_elem_size(), "invariant"); 217 for (size_t i = 0; i < retry_count; ++i) { 218 typename Mspace::Type* const t = mspace_get_free(size, mspace, thread); 219 if (t != NULL) { 220 return t; 221 } 222 } 223 return NULL; 224 } 225 226 template <typename Mspace> 227 inline typename Mspace::Type* mspace_get_free_with_detach(size_t size, Mspace* mspace, Thread* thread) { 228 typename Mspace::Type* t = mspace_get_free(size, mspace, thread); 229 if (t != NULL) { 230 mspace->remove_free(t); 231 } 232 return t; 233 } 234 235 template <typename Mspace> 236 inline typename Mspace::Type* mspace_get_free_to_full(size_t size, Mspace* mspace, Thread* thread) { 237 assert(size <= mspace->min_elem_size(), "invariant"); 238 assert(mspace->is_locked(), "invariant"); 239 typename Mspace::Type* t = mspace_get_free(size, mspace, thread); 240 if (t == NULL) { 241 return NULL; 242 } 243 assert(t->acquired_by_self(), "invariant"); 244 move_to_head(t, mspace->free(), mspace->full()); 245 return t; 246 } 247 248 template <typename Mspace> 249 inline typename Mspace::Type* mspace_get_to_full(size_t size, Mspace* mspace, Thread* thread) { 250 size = size_adjustment(size, mspace); 251 MspaceLock<Mspace> lock(mspace); 252 if (size <= mspace->min_elem_size()) { 253 typename Mspace::Type* const t = mspace_get_free_to_full(size, mspace, thread); 254 if (t != NULL) { 255 return t; 256 } 257 } 258 return mspace_allocate_to_full(size, mspace, thread); 259 } 260 261 template <typename Mspace> 262 inline typename Mspace::Type* mspace_get_free_lease_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) { 263 typename Mspace::Type* t = mspace_get_free_with_retry(size, mspace, retry_count, thread); 264 if (t != NULL) { 265 t->set_lease(); 266 } 267 return t; 268 } 269 270 template <typename Mspace> 271 inline typename Mspace::Type* mspace_get_lease(size_t size, Mspace* mspace, Thread* thread) { 272 typename Mspace::Type* t; 273 t = mspace_get_free_lease(size, mspace, thread); 274 if (t != NULL) { 275 assert(t->acquired_by_self(), "invariant"); 276 assert(t->lease(), "invariant"); 277 return t; 278 } 279 t = mspace_allocate_transient_to_full(size, mspace, thread); 280 if (t != NULL) { 281 t->set_lease(); 282 } 283 return t; 284 } 285 286 template <typename Mspace> 287 inline void mspace_release_full(typename Mspace::Type* t, Mspace* mspace) { 288 assert(t != NULL, "invariant"); 289 assert(t->unflushed_size() == 0, "invariant"); 290 assert(mspace != NULL, "invariant"); 291 assert(mspace->is_locked(), "invariant"); 292 mspace->release_full(t); 293 } 294 295 template <typename Mspace> 296 inline void mspace_release_free(typename Mspace::Type* t, Mspace* mspace) { 297 assert(t != NULL, "invariant"); 298 assert(t->unflushed_size() == 0, "invariant"); 299 assert(mspace != NULL, "invariant"); 300 assert(mspace->is_locked(), "invariant"); 301 mspace->release_free(t); 302 } 303 304 template <typename Mspace> 305 inline void mspace_release_full_critical(typename Mspace::Type* t, Mspace* mspace) { 306 MspaceLock<Mspace> lock(mspace); 307 mspace_release_full(t, mspace); 308 } 309 310 template <typename Mspace> 311 inline void mspace_release_free_critical(typename Mspace::Type* t, Mspace* mspace) { 312 MspaceLock<Mspace> lock(mspace); 313 mspace_release_free(t, mspace); 314 } 315 316 template <typename List> 317 inline void move_to_head(typename List::Node* t, List& from, List& to) { 318 assert(from.in_list(t), "invariant"); 319 to.prepend(from.remove(t)); 320 } 321 322 template <typename Processor, typename Mspace, typename Iterator> 323 inline void process_free_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) { 324 mspace->template iterate<Processor, Iterator>(processor, false, direction); 325 } 326 327 template <typename Processor, typename Mspace, typename Iterator> 328 inline void process_full_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) { 329 mspace->template iterate<Processor, Iterator>(processor, true, direction); 330 } 331 332 template <typename Processor, typename Mspace> 333 inline void process_full_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) { 334 assert(mspace != NULL, "invariant"); 335 if (mspace->is_full_empty()) return; 336 process_full_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction); 337 } 338 339 template <typename Processor, typename Mspace> 340 inline void process_free_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) { 341 assert(mspace != NULL, "invariant"); 342 assert(mspace->has_free(), "invariant"); 343 process_free_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction); 344 } 345 346 template <typename Mspace> 347 inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) { 348 assert(t != NULL, "invariant"); 349 if (t->retired() || t->try_acquire(_thread)) { 350 if (t->transient()) { 351 if (_release_full) { 352 mspace_release_full_critical(t, _mspace); 353 } else { 354 mspace_release_free_critical(t, _mspace); 355 } 356 return true; 357 } 358 t->reinitialize(); 359 assert(t->empty(), "invariant"); 360 t->release(); // publish 361 } 362 return true; 363 } 364 365 #ifdef ASSERT 366 template <typename T> 367 inline void assert_migration_state(const T* old, const T* new_buffer, size_t used, size_t requested) { 368 assert(old != NULL, "invariant"); 369 assert(new_buffer != NULL, "invariant"); 370 assert(old->pos() >= old->start(), "invariant"); 371 assert(old->pos() + used <= old->end(), "invariant"); 372 assert(new_buffer->free_size() >= (used + requested), "invariant"); 373 } 374 #endif // ASSERT 375 376 template <typename T> 377 inline void migrate_outstanding_writes(const T* old, T* new_buffer, size_t used, size_t requested) { 378 DEBUG_ONLY(assert_migration_state(old, new_buffer, used, requested);) 379 if (used > 0) { 380 memcpy(new_buffer->pos(), old->pos(), used); 381 } 382 } 383 384 #endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP 385