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 #include "precompiled.hpp" 26 #include "gc/shared/gcLocker.hpp" 27 #include "memory/resourceArea.hpp" 28 #include "memory/vtBuffer.hpp" 29 #include "oops/oop.inline.hpp" 30 #include "oops/valueKlass.hpp" 31 #include "runtime/frame.hpp" 32 #include "runtime/globals_extension.hpp" 33 #include "runtime/os.hpp" 34 #include "runtime/safepointVerifiers.hpp" 35 #include "runtime/thread.hpp" 36 #include "utilities/globalDefinitions.hpp" 37 #include "utilities/ticks.hpp" 38 39 VTBufferChunk* VTBuffer::_free_list = NULL; 40 Mutex* VTBuffer::_pool_lock = new Mutex(Mutex::leaf, "VTBuffer::_pool_lock", true, Monitor::_safepoint_check_never); 41 int VTBuffer::_pool_counter = 0; 42 int VTBuffer::_max_pool_counter = 0; 43 int VTBuffer::_total_allocated = 0; 44 int VTBuffer::_total_failed = 0; 45 address VTBuffer::_base = NULL; 46 address VTBuffer::_commit_ptr; 47 size_t VTBuffer::_size; 48 49 void VTBuffer::init() { 50 if ((!EnableValhalla) || ValueTypesBufferMaxMemory == 0) { 51 _base = NULL; 52 _commit_ptr = NULL; 53 _size = 0; 54 return; 55 } 56 size_t size = ValueTypesBufferMaxMemory * os::vm_page_size(); 57 _base = (address)os::reserve_memory(size, NULL, (size_t)os::vm_page_size()); 58 if (_base == NULL) { 59 if (!FLAG_IS_DEFAULT(ValueTypesBufferMaxMemory)) { 60 vm_exit_during_initialization("Cannot reserved memory requested for Thread-Local Value Buffer"); 61 } 62 // memory allocation failed, disabling buffering 63 ValueTypesBufferMaxMemory = 0; 64 _size = 0; 65 _commit_ptr = NULL; 66 } else { 67 _commit_ptr = _base; 68 _size = size; 69 } 70 } 71 72 VTBufferChunk* VTBuffer::get_new_chunk(JavaThread* thread) { 73 if (_commit_ptr >= _base + _size) { 74 return NULL; 75 } 76 if (os::commit_memory((char*)_commit_ptr, (size_t)os::vm_page_size(), false)) { 77 VTBufferChunk* chunk = (VTBufferChunk*)_commit_ptr; 78 _commit_ptr += os::vm_page_size(); 79 VTBufferChunk::init(chunk, thread); 80 return chunk; 81 } else { 82 return NULL; 83 } 84 } 85 86 void VTBufferChunk::zap(void* start) { 87 assert(this == (VTBufferChunk*)((intptr_t)start & chunk_mask()), "start must be in current chunk"); 88 if (ZapVTBufferChunks) { 89 size_t size = chunk_size() - ((char*)start - (char*)this); 90 memset((char*)start, 0, size); 91 } 92 } 93 94 oop VTBuffer::allocate_value(ValueKlass* k, TRAPS) { 95 assert(THREAD->is_Java_thread(), "Only JavaThreads have a buffer for value types"); 96 JavaThread* thread = (JavaThread*)THREAD; 97 if (thread->vt_alloc_ptr() == NULL) { 98 if (!allocate_vt_chunk(thread)) { 99 return NULL; // will trigger fall back strategy: allocation in Java heap 100 } 101 } 102 assert(thread->vt_alloc_ptr() != NULL, "should not be null if chunk allocation was successful"); 103 int allocation_size_in_bytes = k->size_helper() * HeapWordSize; 104 if ((char*)thread->vt_alloc_ptr() + allocation_size_in_bytes >= thread->vt_alloc_limit()) { 105 if (allocation_size_in_bytes > (int)VTBufferChunk::max_alloc_size()) { 106 // Too big to be allocated in a buffer 107 return NULL; 108 } 109 VTBufferChunk* next = VTBufferChunk::chunk(thread->vt_alloc_ptr())->next(); 110 if (next != NULL) { 111 thread->set_vt_alloc_ptr(next->first_alloc()); 112 thread->set_vt_alloc_limit(next->alloc_limit()); 113 } else { 114 if (!allocate_vt_chunk(thread)) { 115 return NULL; // will trigger fall back strategy: allocation in Java heap 116 } 117 } 118 } 119 assert((char*)thread->vt_alloc_ptr() + allocation_size_in_bytes < thread->vt_alloc_limit(),"otherwise the logic above is wrong"); 120 oop new_vt = (oop)thread->vt_alloc_ptr(); 121 int allocation_size_in_words = k->size_helper(); 122 thread->increment_vtchunk_total_memory_buffered(allocation_size_in_words * HeapWordSize); 123 int increment = align_object_size(allocation_size_in_words); 124 void* new_ptr = (char*)thread->vt_alloc_ptr() + increment * HeapWordSize; 125 new_ptr = MIN2(new_ptr, thread->vt_alloc_limit()); 126 assert(VTBufferChunk::chunk(new_ptr) == VTBufferChunk::chunk(thread->vt_alloc_ptr()), 127 "old and new alloc ptr must be in the same chunk"); 128 thread->set_vt_alloc_ptr(new_ptr); 129 // the value and its header must be initialized before being returned!!! 130 memset(((char*)(oopDesc*)new_vt), 0, allocation_size_in_bytes); 131 new_vt->set_klass(k); 132 assert(((intptr_t)(oopDesc*)k->java_mirror() & (intptr_t)VTBuffer::mark_mask) == 0, "Checking least significant bits are available"); 133 new_vt->set_mark(markOop(k->java_mirror())); 134 return new_vt; 135 } 136 137 bool VTBuffer::allocate_vt_chunk(JavaThread* thread) { 138 VTBufferChunk* new_chunk = NULL; 139 // Trying local cache; 140 if (thread->local_free_chunk() != NULL) { 141 new_chunk = thread->local_free_chunk(); 142 thread->set_local_free_chunk(NULL); 143 } else { 144 // Trying global pool 145 MutexLockerEx ml(_pool_lock, Mutex::_no_safepoint_check_flag); 146 if (_free_list != NULL) { 147 new_chunk = _free_list; 148 _free_list = new_chunk->next(); 149 if (_free_list != NULL) { 150 _free_list->set_prev(NULL); 151 } 152 new_chunk->set_next(NULL); 153 _pool_counter--; 154 } else { 155 // Trying to commit a new chunk 156 // Hold _pool_lock for thread-safety 157 new_chunk = get_new_chunk(thread); 158 _total_allocated += new_chunk == NULL ? 0 : 1; 159 } 160 } 161 if (new_chunk == NULL) { 162 _total_failed++; 163 thread->increment_vtchunk_failed(); 164 return false; // allocation failed 165 } 166 VTBufferChunk* current = thread->current_chunk(); 167 assert(new_chunk->owner() == thread || new_chunk->owner()== NULL, "Sanity check"); 168 assert(new_chunk->index() == -1, "Sanity check"); 169 new_chunk->set_owner(thread); 170 if(current != NULL) { 171 new_chunk->set_prev(current); 172 new_chunk->set_index(current->index() + 1); 173 current->set_next(new_chunk); 174 } else { 175 new_chunk->set_index(0); 176 } 177 thread->increment_vtchunk_in_use(); 178 thread->set_vt_alloc_ptr(new_chunk->first_alloc()); 179 thread->set_vt_alloc_limit(new_chunk->alloc_limit()); 180 return true; // allocation was successful 181 } 182 183 void VTBuffer::recycle_chunk(JavaThread* thread, VTBufferChunk* chunk) { 184 if (thread->local_free_chunk() == NULL) { 185 chunk->set_prev(NULL); 186 chunk->set_next(NULL); 187 chunk->set_index(-1); 188 chunk->zap(chunk->first_alloc()); 189 thread->set_local_free_chunk(chunk); 190 } else { 191 return_vt_chunk(thread, chunk); 192 } 193 thread->decrement_vtchunk_in_use(); 194 } 195 196 // This is the main way to recycle VTBuffer memory, it is called from 197 // remove_activation() when an interpreter frame is about to be removed 198 // from the stack. All memory used in the context of this frame is freed, 199 // and the vt_alloc_ptr is restored to the value it had when the frame 200 // was created (modulo a possible adjustment if a value is being returned) 201 void VTBuffer::recycle_vtbuffer(JavaThread* thread, void* alloc_ptr) { 202 address current_ptr = (address)thread->vt_alloc_ptr(); 203 assert(current_ptr != NULL, "Should not reach here if NULL"); 204 VTBufferChunk* current_chunk = VTBufferChunk::chunk(current_ptr); 205 assert(current_chunk->owner() == thread, "Sanity check"); 206 address previous_ptr = (address)alloc_ptr; 207 if (previous_ptr == NULL) { 208 // vt_alloc_ptr has not been initialized in this frame 209 // let's initialize it to the first_alloc() value of the first chunk 210 VTBufferChunk* first_chunk = current_chunk; 211 while (first_chunk->prev() != NULL) { 212 first_chunk = first_chunk->prev(); 213 } 214 previous_ptr = (address)first_chunk->first_alloc(); 215 } 216 assert(previous_ptr != NULL, "Should not reach here if NULL"); 217 VTBufferChunk* previous_chunk = VTBufferChunk::chunk(previous_ptr); 218 assert(previous_chunk->owner() == thread, "Sanity check"); 219 if (current_ptr == previous_ptr) return; 220 assert(current_chunk != previous_chunk || current_ptr >= previous_ptr, "Sanity check"); 221 VTBufferChunk* del = previous_chunk->next(); 222 previous_chunk->set_next(NULL); 223 thread->set_vt_alloc_ptr(previous_ptr); 224 previous_chunk->zap(previous_ptr); 225 thread->set_vt_alloc_limit(previous_chunk->alloc_limit()); 226 while (del != NULL) { 227 VTBufferChunk* temp = del->next(); 228 VTBuffer::recycle_chunk(thread, del); 229 del = temp; 230 } 231 } 232 233 void VTBuffer::return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk) { 234 chunk->set_prev(NULL); 235 chunk->set_owner(NULL); 236 chunk->set_index(-1); 237 chunk->zap(chunk->first_alloc()); 238 MutexLockerEx ml(_pool_lock, Mutex::_no_safepoint_check_flag); 239 if (_free_list != NULL) { 240 chunk->set_next(_free_list); 241 _free_list->set_prev(chunk); 242 _free_list = chunk; 243 } else { 244 chunk->set_next(NULL); 245 _free_list = chunk; 246 } 247 _pool_counter++; 248 if (_pool_counter > _max_pool_counter) { 249 _max_pool_counter = _pool_counter; 250 } 251 thread->increment_vtchunk_returned(); 252 } 253 254 bool VTBuffer::value_belongs_to_frame(oop p, frame* f) { 255 return is_value_allocated_after(p, f->interpreter_frame_vt_alloc_ptr()); 256 } 257 258 bool VTBuffer::is_value_allocated_after(oop p, void* a) { 259 // Test if value p has been allocated after alloc ptr a 260 int p_chunk_idx = VTBufferChunk::chunk(p)->index(); 261 int frame_first_chunk_idx; 262 if (a != NULL) { 263 frame_first_chunk_idx = VTBufferChunk::chunk(a)->index(); 264 } else { 265 frame_first_chunk_idx = 0; 266 } 267 if (p_chunk_idx == frame_first_chunk_idx) { 268 return (intptr_t*)p >= a; 269 } else { 270 return p_chunk_idx > frame_first_chunk_idx; 271 } 272 } 273 274 void VTBuffer::fix_frame_vt_alloc_ptr(frame f, VTBufferChunk* chunk) { 275 assert(f.is_interpreted_frame(), "recycling can only be triggered from interpreted frames"); 276 assert(chunk != NULL, "Should not be called if null"); 277 while (chunk->prev() != NULL) { 278 chunk = chunk->prev(); 279 } 280 f.interpreter_frame_set_vt_alloc_ptr((intptr_t*)chunk->first_alloc()); 281 } 282 283 extern "C" { 284 static int compare_reloc_entries(const void* void_a, const void* void_b) { 285 struct VT_relocation_entry* entry_a = (struct VT_relocation_entry*)void_a; 286 struct VT_relocation_entry* entry_b = (struct VT_relocation_entry*)void_b; 287 if (entry_a->chunk_index == entry_b->chunk_index) { 288 if (entry_a->old_ptr < entry_b->old_ptr) { 289 return -1; 290 } else { 291 return 1; 292 } 293 } else { 294 if (entry_a->chunk_index < entry_b->chunk_index) { 295 return -1; 296 } else { 297 return 1; 298 } 299 } 300 } 301 } 302 303 void dump_reloc_table(struct VT_relocation_entry* table, int nelem, bool print_new_ptr) { 304 ResourceMark rm; 305 for (int i = 0; i < nelem; i++) { 306 InstanceKlass* ik = InstanceKlass::cast(((oop)table[i].old_ptr)->klass()); 307 tty->print("%d:\t%p\t%d\t%s\t%x", i, table[i].old_ptr, table[i].chunk_index, 308 ik->name()->as_C_string(), ik->size_helper() * HeapWordSize); 309 if (print_new_ptr) { 310 tty->print_cr("\t%p\t%d\n", table[i].new_ptr, VTBufferChunk::chunk(table[i].new_ptr)->index()); 311 } else { 312 tty->print_cr(""); 313 } 314 } 315 } 316 317 // Relocate value 'old' after value 'previous' 318 address VTBuffer::relocate_value(address old, address previous, int previous_size_in_words) { 319 InstanceKlass* ik_old = InstanceKlass::cast(((oop)old)->klass()); 320 assert(ik_old->is_value(), "Sanity check"); 321 VTBufferChunk* chunk = VTBufferChunk::chunk(previous); 322 address next_alloc = previous + previous_size_in_words * HeapWordSize; 323 if(next_alloc + ik_old->size_helper() * HeapWordSize < chunk->alloc_limit()) { 324 // relocation can be performed in the same chunk 325 return next_alloc; 326 } else { 327 // relocation must be performed in the next chunk 328 VTBufferChunk* next_chunk = chunk->next(); 329 assert(next_chunk != NULL, "Because we are compacting, there should be enough chunks"); 330 return (address)next_chunk->first_alloc(); 331 } 332 } 333 334 oop VTBuffer::relocate_return_value(JavaThread* thread, void* alloc_ptr, oop obj) { 335 assert(!Universe::heap()->is_in_reserved(obj), "This method should never be called on Java heap allocated values"); 336 assert(obj->klass()->is_value(), "Sanity check"); 337 if (!VTBuffer::is_value_allocated_after(obj, alloc_ptr)) return obj; 338 ValueKlass* vk = ValueKlass::cast(obj->klass()); 339 address current_ptr = (address)thread->vt_alloc_ptr(); 340 VTBufferChunk* current_chunk = VTBufferChunk::chunk(current_ptr); 341 address previous_ptr = (address)alloc_ptr; 342 if (previous_ptr == NULL) { 343 VTBufferChunk* c = VTBufferChunk::chunk(obj); 344 while (c->prev() != NULL) c = c->prev(); 345 previous_ptr = (address)c->first_alloc(); 346 } 347 VTBufferChunk* previous_chunk = VTBufferChunk::chunk(previous_ptr); 348 address dest; 349 if ((address)obj != previous_ptr) { 350 if (previous_chunk == current_chunk 351 && (previous_ptr + vk->size_helper() * HeapWordSize) < previous_chunk->alloc_limit()) { 352 dest = previous_ptr; 353 } else { 354 assert(previous_chunk->next() != NULL, "Should not happen"); 355 dest = (address)previous_chunk->next()->first_alloc(); 356 } 357 // Copying header 358 memcpy(dest, obj, vk->first_field_offset()); 359 // Copying value content 360 vk->value_store(((char*)(address)obj) + vk->first_field_offset(), 361 dest + vk->first_field_offset(), false, true); 362 } else { 363 dest = (address)obj; 364 } 365 VTBufferChunk* last = VTBufferChunk::chunk(dest); 366 thread->set_vt_alloc_limit(last->alloc_limit()); 367 void* new_alloc_ptr = MIN2((void*)(dest + vk->size_helper() * HeapWordSize), last->alloc_limit()); 368 thread->set_vt_alloc_ptr(new_alloc_ptr); 369 assert(VTBufferChunk::chunk(thread->vt_alloc_limit()) == VTBufferChunk::chunk(thread->vt_alloc_ptr()), "Sanity check"); 370 VTBufferChunk* del = last->next(); 371 last->set_next(NULL); 372 while (del != NULL) { 373 VTBufferChunk* tmp = del->next(); 374 VTBuffer::recycle_chunk(thread, del); 375 del = tmp; 376 } 377 return (oop)dest; 378 } 379 380 // This method is called to recycle VTBuffer memory when the VM has detected 381 // that too much memory is being consumed in the current frame context. This 382 // can only happen when the method contains at least one loop in which new 383 // values are created. 384 void VTBuffer::recycle_vt_in_frame(JavaThread* thread, frame* f) { 385 Ticks begin, end; 386 Ticks step1, step2, step3, step4, step5, step6, step7; 387 int returned_chunks = 0; 388 389 if (ReportVTBufferRecyclingTimes) { 390 begin = Ticks::now(); 391 } 392 assert(f->is_interpreted_frame(), "only interpreted frames are using VT buffering so far"); 393 ResourceMark rm(thread); 394 395 // 1 - allocate relocation table 396 Method* m = f->interpreter_frame_method(); 397 int max_entries = m->max_locals() + m->max_stack(); 398 VT_relocation_entry* reloc_table = NEW_RESOURCE_ARRAY_IN_THREAD(thread, struct VT_relocation_entry, max_entries); 399 int n_entries = 0; 400 if (ReportVTBufferRecyclingTimes) { 401 step1 = Ticks::now(); 402 } 403 404 { 405 // No GC should occur during the phases 2->5 406 // either because the mark word (usually containing the pointer 407 // to the Java mirror) is used for marking, or because the values are being relocated 408 NoSafepointVerifier nsv; 409 410 // 2 - marking phase + populate relocation table 411 BufferedValuesMarking marking_closure = BufferedValuesMarking(f, reloc_table, max_entries, &n_entries); 412 f->buffered_values_interpreted_do(&marking_closure); 413 if (ReportVTBufferRecyclingTimes) { 414 step2 = Ticks::now(); 415 } 416 417 if (n_entries > 0) { 418 // 3 - sort relocation table entries and compute compaction 419 qsort(reloc_table, n_entries, sizeof(struct VT_relocation_entry), compare_reloc_entries); 420 if (f->interpreter_frame_vt_alloc_ptr() == NULL) { 421 VTBufferChunk* chunk = VTBufferChunk::chunk(reloc_table[0].old_ptr); 422 while (chunk->prev() != NULL) chunk = chunk->prev(); 423 //f->interpreter_frame_set_vt_alloc_ptr((intptr_t*)chunk->first_alloc()); 424 reloc_table[0].new_ptr = (address)chunk->first_alloc(); 425 } else { 426 reloc_table[0].new_ptr = (address)f->interpreter_frame_vt_alloc_ptr(); 427 } 428 ((oop)reloc_table[0].old_ptr)->set_mark((markOop)reloc_table[0].new_ptr); 429 for (int i = 1; i < n_entries; i++) { 430 reloc_table[i].new_ptr = relocate_value(reloc_table[i].old_ptr, reloc_table[i-1].new_ptr, 431 InstanceKlass::cast(((oop)reloc_table[i-1].old_ptr)->klass())->size_helper()); 432 ((oop)reloc_table[i].old_ptr)->set_mark((markOop)reloc_table[i].new_ptr); 433 } 434 if (ReportVTBufferRecyclingTimes) { 435 step3 = Ticks::now(); 436 } 437 438 // 4 - update pointers 439 BufferedValuesPointersUpdate update_closure = BufferedValuesPointersUpdate(f); 440 f->buffered_values_interpreted_do(&update_closure); 441 if (ReportVTBufferRecyclingTimes) { 442 step4 = Ticks::now(); 443 } 444 445 // 5 - relocate values 446 for (int i = 0; i < n_entries; i++) { 447 if (reloc_table[i].old_ptr != reloc_table[i].new_ptr) { 448 assert(VTBufferChunk::chunk(reloc_table[i].old_ptr)->owner() == Thread::current(), "Sanity check"); 449 assert(VTBufferChunk::chunk(reloc_table[i].new_ptr)->owner() == Thread::current(), "Sanity check"); 450 InstanceKlass* ik_old = InstanceKlass::cast(((oop)reloc_table[i].old_ptr)->klass()); 451 // instead of memcpy, a value_store() might be required here 452 memcpy(reloc_table[i].new_ptr, reloc_table[i].old_ptr, ik_old->size_helper() * HeapWordSize); 453 } 454 // Restoring the mark word 455 ((oop)reloc_table[i].new_ptr)->set_mark(reloc_table[i].mark_word); 456 } 457 if (ReportVTBufferRecyclingTimes) { 458 step5 = Ticks::now(); 459 } 460 461 oop last_oop = (oop)reloc_table[n_entries - 1].new_ptr; 462 assert(last_oop->is_value(), "sanity check"); 463 assert(VTBufferChunk::chunk((address)last_oop)->owner() == Thread::current(), "Sanity check"); 464 VTBufferChunk* last_chunk = VTBufferChunk::chunk(last_oop); 465 InstanceKlass* ik = InstanceKlass::cast(last_oop->klass()); 466 thread->set_vt_alloc_limit(last_chunk->alloc_limit()); 467 void* new_alloc_ptr = MIN2((void*)((address)last_oop + ik->size_helper() * HeapWordSize), thread->vt_alloc_limit()); 468 thread->set_vt_alloc_ptr(new_alloc_ptr); 469 assert(VTBufferChunk::chunk(thread->vt_alloc_ptr())->owner() == Thread::current(), "Sanity check"); 470 assert(VTBufferChunk::chunk(thread->vt_alloc_limit()) == VTBufferChunk::chunk(thread->vt_alloc_ptr()), "Sanity check"); 471 if (ReportVTBufferRecyclingTimes) { 472 step6 = Ticks::now(); 473 } 474 475 // 7 - free/return unused chunks 476 VTBufferChunk* last = VTBufferChunk::chunk(thread->vt_alloc_ptr()); 477 VTBufferChunk* del = last->next(); 478 last->set_next(NULL); 479 while (del != NULL) { 480 returned_chunks++; 481 VTBufferChunk* tmp = del->next(); 482 VTBuffer::recycle_chunk(thread, del); 483 del = tmp; 484 } 485 if (ReportVTBufferRecyclingTimes) { 486 step7 = Ticks::now(); 487 } 488 } else { 489 f->interpreter_frame_set_vt_alloc_ptr((intptr_t*)thread->vt_alloc_ptr()); 490 } 491 } 492 493 // 8 - free relocation table 494 FREE_RESOURCE_ARRAY(struct VT_relocation_entry, reloc_table, max_entries); 495 496 if (ReportVTBufferRecyclingTimes) { 497 end = Ticks::now(); 498 ResourceMark rm(thread); 499 tty->print_cr("VTBufferRecyling: %s : %s.%s %s : " JLONG_FORMAT "us", 500 thread->name(), 501 f->interpreter_frame_method()->klass_name()->as_C_string(), 502 f->interpreter_frame_method()->name()->as_C_string(), 503 f->interpreter_frame_method()->signature()->as_C_string(), 504 (end.value() - begin.value()) / 1000); 505 tty->print("Step1 : " JLONG_FORMAT "ns ", step1.value() - begin.value()); 506 tty->print("Step2 : " JLONG_FORMAT "ns ", step2.value() - step1.value()); 507 tty->print("Step3 : " JLONG_FORMAT "ns ", step3.value() - step2.value()); 508 tty->print("Step4 : " JLONG_FORMAT "ns ", step4.value() - step3.value()); 509 tty->print("Step5 : " JLONG_FORMAT "ns ", step5.value() - step4.value()); 510 tty->print("Step6 : " JLONG_FORMAT "ns ", step6.value() - step5.value()); 511 tty->print("Step7 : " JLONG_FORMAT "ns ", step7.value() - step6.value()); 512 tty->print("Step8 : " JLONG_FORMAT "ns ", end.value() - step7.value()); 513 tty->print_cr("Returned chunks: %d", returned_chunks); 514 } 515 } 516 517 void BufferedValuesMarking::do_buffered_value(oop* p) { 518 assert(!Universe::heap()->is_in_reserved_or_null(*p), "Sanity check"); 519 if (VTBuffer::value_belongs_to_frame(*p, _frame)) { 520 if (!(*p)->mark()->is_marked()) { 521 assert(*_index < _size, "index outside of relocation table range"); 522 _reloc_table[*_index].old_ptr = (address)*p; 523 _reloc_table[*_index].chunk_index = VTBufferChunk::chunk(*p)->index(); 524 _reloc_table[*_index].mark_word = (*p)->mark(); 525 *_index = (*_index) + 1; 526 (*p)->set_mark((*p)->mark()->set_marked()); 527 } 528 } 529 } 530 531 void BufferedValuesPointersUpdate::do_buffered_value(oop* p) { 532 assert(!Universe::heap()->is_in_reserved_or_null(*p), "Sanity check"); 533 // might be coded more efficiently just by checking mark word is not NULL 534 if (VTBuffer::value_belongs_to_frame(*p, _frame)) { 535 *p = (oop)(*p)->mark(); 536 } 537 } 538 539 BufferedValuesDealiaser::BufferedValuesDealiaser(JavaThread* thread) { 540 Thread* current = Thread::current(); 541 assert(current->buffered_values_dealiaser() == NULL, "Must not be used twice concurrently"); 542 VTBuffer::Mark mark = VTBuffer::switch_mark(thread->current_vtbuffer_mark()); 543 _target = thread; 544 _current_mark = mark; 545 thread->set_current_vtbuffer_mark(_current_mark); 546 current->_buffered_values_dealiaser = this; 547 } 548 549 void BufferedValuesDealiaser::oops_do(OopClosure* f, oop value) { 550 551 assert(VTBuffer::is_in_vt_buffer((oopDesc*)value), "Should only be called on buffered values"); 552 553 intptr_t mark = *(intptr_t*)(value)->mark_addr_raw(); 554 if ((mark & VTBuffer::mark_mask) == _current_mark) { 555 return; 556 } 557 558 ValueKlass* vk = ValueKlass::cast(value->klass()); 559 560 oop mirror = (oopDesc*)((intptr_t)value->mark() & (intptr_t)~VTBuffer::mark_mask); 561 assert(oopDesc::is_oop(mirror), "Sanity check"); 562 value->set_mark((markOop)mirror); 563 564 vk->iterate_over_inside_oops(f, value); 565 566 intptr_t new_mark_word = ((intptr_t) (oopDesc*)(value->mark())) 567 | (intptr_t)_current_mark; 568 value->set_mark(markOop((oopDesc*)new_mark_word)); 569 570 assert(((intptr_t)value->mark() & VTBuffer::mark_mask) == _current_mark, "Sanity check"); 571 } 572 573 BufferedValuesDealiaser::~BufferedValuesDealiaser() { 574 assert(Thread::current()->buffered_values_dealiaser() != NULL, "Should not be NULL"); 575 assert(_target->current_vtbuffer_mark() == _current_mark, "Must be the same"); 576 Thread::current()->_buffered_values_dealiaser = NULL; 577 }