annotate src/share/vm/memory/vtBuffer.cpp @ 13588:488f0d311b80

8187820: [MVT] Build failures on 32-bit x86
author thartmann
date Fri, 22 Sep 2017 13:51:12 +0200
parents a9010a9e2e11
children
rev   line source
fparain@13041 1 /*
fparain@13041 2 * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
fparain@13041 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
fparain@13041 4 *
fparain@13041 5 * This code is free software; you can redistribute it and/or modify it
fparain@13041 6 * under the terms of the GNU General Public License version 2 only, as
fparain@13041 7 * published by the Free Software Foundation.
fparain@13041 8 *
fparain@13041 9 * This code is distributed in the hope that it will be useful, but WITHOUT
fparain@13041 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
fparain@13041 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
fparain@13041 12 * version 2 for more details (a copy is included in the LICENSE file that
fparain@13041 13 * accompanied this code).
fparain@13041 14 *
fparain@13041 15 * You should have received a copy of the GNU General Public License version
fparain@13041 16 * 2 along with this work; if not, write to the Free Software Foundation,
fparain@13041 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
fparain@13041 18 *
fparain@13041 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
fparain@13041 20 * or visit www.oracle.com if you need additional information or have any
fparain@13041 21 * questions.
fparain@13041 22 *
fparain@13041 23 */
fparain@13041 24
fparain@13041 25 #include "precompiled.hpp"
fparain@13041 26 #include "gc/shared/gcLocker.hpp"
fparain@13041 27 #include "memory/vtBuffer.hpp"
fparain@13041 28 #include "oops/oop.inline.hpp"
fparain@13041 29 #include "oops/valueKlass.hpp"
fparain@13041 30 #include "runtime/frame.hpp"
fparain@13041 31 #include "runtime/thread.hpp"
fparain@13041 32 #include "utilities/globalDefinitions.hpp"
fparain@13041 33 #include "utilities/ticks.hpp"
fparain@13041 34 #include "utilities/ticks.inline.hpp"
fparain@13041 35
fparain@13041 36 VTBufferChunk* VTBuffer::_free_list = NULL;
fparain@13041 37 Mutex* VTBuffer::_pool_lock = new Mutex(Mutex::leaf, "VTBuffer::_pool_lock", true, Monitor::_safepoint_check_never);
fparain@13041 38 int VTBuffer::_pool_counter = 0;
fparain@13041 39 int VTBuffer::_max_pool_counter = 0;
fparain@13041 40 int VTBuffer::_total_allocated = 0;
fparain@13041 41 int VTBuffer::_total_deallocated = 0;
fparain@13041 42 int VTBuffer::_total_failed = 0;
fparain@13041 43
fparain@13041 44 oop VTBuffer::allocate_value(ValueKlass* k, TRAPS) {
fparain@13041 45 assert(THREAD->is_Java_thread(), "Only JavaThreads have a buffer for value types");
fparain@13041 46 JavaThread* thread = (JavaThread*)THREAD;
fparain@13041 47 if (thread->vt_alloc_ptr() == NULL) {
fparain@13041 48 if (!allocate_vt_chunk(thread)) {
fparain@13041 49 return NULL; // will trigger fall back strategy: allocation in Java heap
fparain@13041 50 }
fparain@13041 51 }
fparain@13041 52 assert(thread->vt_alloc_ptr() != NULL, "should not be null if chunk allocation was successful");
fparain@13041 53 int size_in_bytes = k->size_helper() * wordSize;
fparain@13041 54 if ((char*)thread->vt_alloc_ptr() + size_in_bytes >= thread->vt_alloc_limit()) {
fparain@13041 55 if (size_in_bytes > (int)VTBufferChunk::max_alloc_size()) {
fparain@13041 56 // Too big to be allocated in a buffer
fparain@13041 57 return NULL;
fparain@13041 58 }
fparain@13041 59 if (!allocate_vt_chunk(thread)) {
fparain@13041 60 return NULL; // will trigger fall back strategy: allocation in Java heap
fparain@13041 61 }
fparain@13041 62 }
fparain@13041 63 assert((char*)thread->vt_alloc_ptr() + size_in_bytes < thread->vt_alloc_limit(),"otherwise the logic above is wrong");
fparain@13041 64 oop new_vt = (oop)thread->vt_alloc_ptr();
fparain@13041 65 int size_in_words = k->size_helper();
fparain@13041 66 thread->increment_vtchunk_total_memory_buffered(size_in_words * HeapWordSize);
fparain@13041 67 int increment = align_object_size(size_in_words);
fparain@13041 68 void* new_ptr = (char*)thread->vt_alloc_ptr() + increment * HeapWordSize;
fparain@13041 69 new_ptr = MIN2(new_ptr, thread->vt_alloc_limit());
fparain@13041 70 assert(VTBufferChunk::chunk(new_ptr) == VTBufferChunk::chunk(thread->vt_alloc_ptr()),
fparain@13041 71 "old and new alloc ptr must be in the same chunk");
fparain@13041 72 thread->set_vt_alloc_ptr(new_ptr);
fparain@13041 73 // the value and its header must be initialized before being returned!!!
fparain@13041 74 memset(((char*)(oopDesc*)new_vt), 0, size_in_bytes);
fparain@13041 75 new_vt->set_klass(k);
fparain@13041 76 new_vt->set_mark(markOop(k->java_mirror()));
fparain@13041 77 return new_vt;
fparain@13041 78 }
fparain@13041 79
fparain@13041 80 bool VTBuffer::allocate_vt_chunk(JavaThread* thread) {
fparain@13041 81 VTBufferChunk* new_chunk = NULL;
fparain@13041 82 // Trying local cache;
fparain@13041 83 if (thread->local_free_chunk() != NULL) {
fparain@13041 84 new_chunk = thread->local_free_chunk();
fparain@13041 85 thread->set_local_free_chunk(NULL);
fparain@13041 86 } else {
fparain@13041 87 // Trying global pool
fparain@13041 88 MutexLockerEx ml(_pool_lock, Mutex::_no_safepoint_check_flag);
fparain@13041 89 if (_free_list != NULL) {
fparain@13041 90 new_chunk = _free_list;
fparain@13041 91 _free_list = new_chunk->next();
fparain@13041 92 if (_free_list != NULL) {
fparain@13041 93 _free_list->set_prev(NULL);
fparain@13041 94 }
fparain@13041 95 new_chunk->set_next(NULL);
fparain@13041 96 _pool_counter--;
fparain@13041 97 } else {
fparain@13041 98 // A new chunk has to be allocated
fparain@13041 99 // Hold _pool_lock to maintain counters
fparain@13041 100 if ((_total_allocated + 1) <= ValueTypesBufferMaxMemory) {
fparain@13041 101 // Allocate new chunk only if total size for buffer
fparain@13041 102 // memory is below its max size
fparain@13041 103 new_chunk = new VTBufferChunk(thread);
fparain@13041 104 _total_allocated += new_chunk == NULL ? 0 : 1;
fparain@13041 105 }
fparain@13041 106 }
fparain@13041 107 }
fparain@13041 108 if (new_chunk == NULL) {
fparain@13041 109 _total_failed++;
fparain@13041 110 thread->increment_vtchunk_failed();
fparain@13041 111 return false; // allocation failed
fparain@13041 112 }
fparain@13041 113 VTBufferChunk* current = thread->current_chunk();
fparain@13041 114 assert(new_chunk->owner() == thread || new_chunk->owner()== NULL, "Sanity check");
fparain@13041 115 assert(new_chunk->index() == -1, "Sanity check");
fparain@13041 116 new_chunk->set_owner(thread);
fparain@13041 117 if(current != NULL) {
fparain@13041 118 new_chunk->set_prev(current);
fparain@13041 119 new_chunk->set_index(current->index() + 1);
fparain@13041 120 current->set_next(new_chunk);
fparain@13041 121 } else {
fparain@13041 122 new_chunk->set_index(0);
fparain@13041 123 }
fparain@13041 124 thread->increment_vtchunk_in_use();
fparain@13041 125 thread->set_vt_alloc_ptr(new_chunk->first_alloc());
fparain@13041 126 thread->set_vt_alloc_limit(new_chunk->alloc_limit());
fparain@13041 127 return true; // allocation was successful
fparain@13041 128 }
fparain@13041 129
fparain@13041 130 void VTBuffer::recycle_chunk(JavaThread* thread, VTBufferChunk* chunk) {
fparain@13041 131 if (thread->local_free_chunk() == NULL) {
fparain@13041 132 chunk->set_prev(NULL);
fparain@13041 133 chunk->set_next(NULL);
fparain@13041 134 chunk->set_index(-1);
fparain@13041 135 thread->set_local_free_chunk(chunk);
fparain@13041 136 } else {
fparain@13041 137 return_vt_chunk(thread, chunk);
fparain@13041 138 }
fparain@13041 139 thread->decrement_vtchunk_in_use();
fparain@13041 140 }
fparain@13041 141
fparain@13041 142 // This is the main way to recycle VTBuffer memory, it is called from
fparain@13041 143 // remove_activation() when an interpreter frame is about to be removed
fparain@13041 144 // from the stack. All memory used in the context of this frame is freed,
fparain@13041 145 // and the vt_alloc_ptr is restored to the value it had when the frame
fparain@13041 146 // was created (modulo a possible adjustment if a value is being returned)
fparain@13041 147 void VTBuffer::recycle_vtbuffer(JavaThread* thread, frame current_frame) {
fparain@13041 148 address current_ptr = (address)thread->vt_alloc_ptr();
fparain@13041 149 assert(current_ptr != NULL, "Should not reach here if NULL");
fparain@13041 150 VTBufferChunk* current_chunk = VTBufferChunk::chunk(current_ptr);
fparain@13041 151 assert(current_chunk->owner() == thread, "Sanity check");
fparain@13041 152 address previous_ptr = (address)current_frame.interpreter_frame_vt_alloc_ptr();
fparain@13041 153 if (previous_ptr == NULL) {
fparain@13041 154 // vt_alloc_ptr has not been initialized in this frame
fparain@13041 155 // let's initialize it to the first_alloc() value of the first chunk
fparain@13041 156 VTBufferChunk* first_chunk = current_chunk;
fparain@13041 157 while (first_chunk->prev() != NULL) {
fparain@13041 158 first_chunk = first_chunk->prev();
fparain@13041 159 }
fparain@13041 160 previous_ptr = (address)first_chunk->first_alloc();
fparain@13041 161 }
fparain@13041 162 assert(previous_ptr != NULL, "Should not reach here if NULL");
fparain@13041 163 VTBufferChunk* previous_chunk = VTBufferChunk::chunk(previous_ptr);
fparain@13041 164 assert(previous_chunk->owner() == thread, "Sanity check");
fparain@13041 165 if (current_ptr == previous_ptr) return;
fparain@13041 166 assert(current_chunk != previous_chunk || current_ptr >= previous_ptr, "Sanity check");
fparain@13041 167 VTBufferChunk* del = previous_chunk->next();
fparain@13041 168 previous_chunk->set_next(NULL);
fparain@13041 169 thread->set_vt_alloc_ptr(previous_ptr);
fparain@13041 170 thread->set_vt_alloc_limit(previous_chunk->alloc_limit());
fparain@13041 171 while (del != NULL) {
fparain@13041 172 VTBufferChunk* temp = del->next();
fparain@13041 173 VTBuffer::recycle_chunk(thread, del);
fparain@13041 174 del = temp;
fparain@13041 175 }
fparain@13041 176 }
fparain@13041 177
fparain@13041 178 void VTBuffer::return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk) {
fparain@13041 179 chunk->set_prev(NULL);
fparain@13041 180 chunk->set_owner(NULL);
fparain@13041 181 chunk->set_index(-1);
fparain@13041 182 MutexLockerEx ml(_pool_lock, Mutex::_no_safepoint_check_flag);
fparain@13041 183 if (_pool_counter < _max_free_list) {
fparain@13041 184 if (_free_list != NULL) {
fparain@13041 185 chunk->set_next(_free_list);
fparain@13041 186 _free_list->set_prev(chunk);
fparain@13041 187 _free_list = chunk;
fparain@13041 188 } else {
fparain@13041 189 chunk->set_next(NULL);
fparain@13041 190 _free_list = chunk;
fparain@13041 191 }
fparain@13041 192 _pool_counter++;
fparain@13041 193 if (_pool_counter > _max_pool_counter) {
fparain@13041 194 _max_pool_counter = _pool_counter;
fparain@13041 195 }
fparain@13041 196 } else {
fparain@13041 197 delete chunk;
fparain@13041 198 _total_deallocated++;
fparain@13041 199 }
fparain@13041 200 thread->increment_vtchunk_returned();
fparain@13041 201 }
fparain@13041 202
fparain@13041 203 bool VTBuffer::value_belongs_to_frame(oop p, frame* f) {
fparain@13041 204 // the code below assumes that frame f is the last interpreted frame
fparain@13041 205 // on the execution stack
fparain@13041 206 int p_chunk_idx = VTBufferChunk::chunk(p)->index();
fparain@13041 207 int frame_first_chunk_idx;
fparain@13041 208 if (f->interpreter_frame_vt_alloc_ptr() != NULL) {
fparain@13041 209 frame_first_chunk_idx = VTBufferChunk::chunk(f->interpreter_frame_vt_alloc_ptr())->index();
fparain@13041 210 } else {
fparain@13041 211 frame_first_chunk_idx = 0;
fparain@13041 212 }
fparain@13041 213 if (p_chunk_idx == frame_first_chunk_idx) {
fparain@13041 214 return (intptr_t*)p >= f->interpreter_frame_vt_alloc_ptr();
fparain@13041 215 } else {
fparain@13041 216 return p_chunk_idx > frame_first_chunk_idx;
fparain@13041 217 }
fparain@13041 218
fparain@13041 219 }
fparain@13041 220
fparain@13041 221 void VTBuffer::fix_frame_vt_alloc_ptr(frame f, VTBufferChunk* chunk) {
fparain@13041 222 assert(f.is_interpreted_frame(), "recycling can only be triggered from interpreted frames");
fparain@13041 223 assert(chunk != NULL, "Should not be called if null");
fparain@13041 224 while (chunk->prev() != NULL) {
fparain@13041 225 chunk = chunk->prev();
fparain@13041 226 }
fparain@13041 227 f.interpreter_frame_set_vt_alloc_ptr((intptr_t*)chunk->first_alloc());
fparain@13041 228 }
fparain@13041 229
fparain@13041 230 extern "C" {
fparain@13041 231 static int compare_reloc_entries(const void* void_a, const void* void_b) {
fparain@13041 232 struct VT_relocation_entry* entry_a = (struct VT_relocation_entry*)void_a;
fparain@13041 233 struct VT_relocation_entry* entry_b = (struct VT_relocation_entry*)void_b;
fparain@13041 234 if (entry_a->chunk_index == entry_b->chunk_index) {
fparain@13041 235 if (entry_a->old_ptr < entry_b->old_ptr) {
fparain@13041 236 return -1;
fparain@13041 237 } else {
fparain@13041 238 return 1;
fparain@13041 239 }
fparain@13041 240 } else {
fparain@13041 241 if (entry_a->chunk_index < entry_b->chunk_index) {
fparain@13041 242 return -1;
fparain@13041 243 } else {
fparain@13041 244 return 1;
fparain@13041 245 }
fparain@13041 246 }
fparain@13041 247 }
fparain@13041 248 }
fparain@13041 249
fparain@13041 250 void dump_reloc_table(struct VT_relocation_entry* table, int nelem, bool print_new_ptr) {
fparain@13041 251 ResourceMark rm;
fparain@13041 252 for (int i = 0; i < nelem; i++) {
fparain@13574 253 InstanceKlass* ik = InstanceKlass::cast(((oop)table[i].old_ptr)->klass());
fparain@13041 254 tty->print("%d:\t%p\t%d\t%s\t%x", i, table[i].old_ptr, table[i].chunk_index,
fparain@13574 255 ik->name()->as_C_string(), ik->size_helper() * HeapWordSize);
fparain@13041 256 if (print_new_ptr) {
fparain@13574 257 tty->print_cr("\t%p\t%d\n", table[i].new_ptr, VTBufferChunk::chunk(table[i].new_ptr)->index());
fparain@13041 258 } else {
fparain@13574 259 tty->print_cr("");
fparain@13041 260 }
fparain@13041 261 }
fparain@13041 262 }
fparain@13041 263
fparain@13041 264 // Relocate value 'old' after value 'previous'
fparain@13041 265 address VTBuffer::relocate_value(address old, address previous, int previous_size_in_words) {
fparain@13041 266 InstanceKlass* ik_old = InstanceKlass::cast(((oop)old)->klass());
fparain@13041 267 assert(ik_old->is_value(), "Sanity check");
fparain@13041 268 VTBufferChunk* chunk = VTBufferChunk::chunk(previous);
fparain@13041 269 address next_alloc = previous + align_object_size(ik_old->size_helper());
fparain@13041 270 if(next_alloc + ik_old->size_helper() * HeapWordSize < chunk->alloc_limit()) {
fparain@13041 271 // relocation can be performed in the same chunk
fparain@13041 272 return previous + align_object_size(previous_size_in_words) * HeapWordSize;
fparain@13041 273 } else {
fparain@13041 274 // relocation must be performed in the next chunk
fparain@13041 275 VTBufferChunk* next_chunk = chunk->next();
fparain@13041 276 assert(next_chunk != NULL, "Because we are compacting, there should be enough in use chunks");
fparain@13041 277 return (address)next_chunk->first_alloc();
fparain@13041 278 }
fparain@13041 279 }
fparain@13041 280
fparain@13041 281 oop VTBuffer::relocate_return_value(JavaThread* thread, frame current_frame, oop obj) {
fparain@13041 282 assert(!Universe::heap()->is_in_reserved(obj), "This method should never be called on Java heap allocated values");
fparain@13041 283 assert(obj->klass()->is_value(), "Sanity check");
fparain@13574 284 if (!VTBuffer::value_belongs_to_frame(obj, &current_frame)) return obj;
fparain@13041 285 ValueKlass* vk = ValueKlass::cast(obj->klass());
fparain@13041 286 address current_ptr = (address)thread->vt_alloc_ptr();
fparain@13041 287 VTBufferChunk* current_chunk = VTBufferChunk::chunk(current_ptr);
fparain@13041 288 address previous_ptr = (address)current_frame.interpreter_frame_vt_alloc_ptr();
fparain@13041 289 if (previous_ptr == NULL) {
fparain@13041 290 fix_frame_vt_alloc_ptr(current_frame, current_chunk);
fparain@13041 291 previous_ptr = (address)current_frame.interpreter_frame_vt_alloc_ptr();
fparain@13041 292 }
fparain@13041 293 VTBufferChunk* previous_chunk = VTBufferChunk::chunk(previous_ptr);
fparain@13041 294 address dest;
fparain@13041 295 if ((address)obj != previous_ptr) {
fparain@13041 296 if (previous_chunk == current_chunk
fparain@13041 297 || (previous_ptr + vk->size_helper() * wordSize) < previous_chunk->alloc_limit()) {
fparain@13041 298 dest = previous_ptr;
fparain@13041 299 } else {
fparain@13041 300 assert(previous_chunk->next() != NULL, "Should not happen");
fparain@13041 301 dest = (address)previous_chunk->next()->first_alloc();
fparain@13041 302 }
fparain@13041 303 // Copying header
fparain@13041 304 memcpy(dest, obj, vk->first_field_offset());
fparain@13041 305 // Copying value content
fparain@13041 306 vk->value_store(((char*)(address)obj) + vk->first_field_offset(),
fparain@13041 307 dest + vk->first_field_offset(), false, true);
fparain@13041 308 } else {
fparain@13041 309 dest = (address)obj;
fparain@13041 310 }
fparain@13041 311 address new_alloc_ptr = dest + vk->size_helper() * wordSize;
fparain@13041 312 current_frame.interpreter_frame_set_vt_alloc_ptr((intptr_t*)new_alloc_ptr);
fparain@13041 313 VTBufferChunk* last = VTBufferChunk::chunk(dest);
fparain@13041 314 VTBufferChunk* del = last->next();
fparain@13041 315 thread->set_vt_alloc_ptr(new_alloc_ptr);
fparain@13041 316 thread->set_vt_alloc_limit(last->alloc_limit());
fparain@13041 317 last->set_next(NULL);
fparain@13041 318 while (del != NULL) {
fparain@13041 319 VTBufferChunk* tmp = del->next();
fparain@13041 320 VTBuffer::recycle_chunk(thread, del);
fparain@13041 321 del = tmp;
fparain@13041 322 }
fparain@13041 323 return (oop)dest;
fparain@13041 324 }
fparain@13041 325
fparain@13041 326 // This method is called to recycle VTBuffer memory when the VM has detected
fparain@13041 327 // that too much memory is being consumed in the current frame context. This
fparain@13041 328 // can only happen when the method contains at least one loop in which new
fparain@13041 329 // values are created.
fparain@13041 330 void VTBuffer::recycle_vt_in_frame(JavaThread* thread, frame* f) {
fparain@13041 331 Ticks begin, end;
fparain@13041 332 Ticks step1, step2, step3, step4, step5, step6, step7;
fparain@13041 333 int returned_chunks = 0;
fparain@13041 334
fparain@13041 335 if (ReportVTBufferRecyclingTimes) {
fparain@13041 336 begin = Ticks::now();
fparain@13041 337 }
fparain@13041 338 assert(f->is_interpreted_frame(), "only interpreted frames are using VT buffering so far");
fparain@13041 339 ResourceMark rm(thread);
fparain@13041 340
fparain@13041 341 // 1 - allocate relocation table
fparain@13041 342 Method* m = f->interpreter_frame_method();
fparain@13041 343 int max_entries = m->max_locals() + m->max_stack();
fparain@13041 344 VT_relocation_entry* reloc_table = NEW_RESOURCE_ARRAY_IN_THREAD(thread, struct VT_relocation_entry, max_entries);
fparain@13041 345 int n_entries = 0;
fparain@13041 346 if (ReportVTBufferRecyclingTimes) {
fparain@13041 347 step1 = Ticks::now();
fparain@13041 348 }
fparain@13041 349
fparain@13041 350 {
fparain@13041 351 // No GC should occur during the phases 2->5
fparain@13041 352 // either because the mark word (usually containing the pointer
fparain@13041 353 // to the Java mirror) is used for marking, or because the values are being relocated
fparain@13041 354 NoSafepointVerifier nsv;
fparain@13041 355
fparain@13041 356 // 2 - marking phase + populate relocation table
fparain@13041 357 BufferedValuesMarking marking_closure = BufferedValuesMarking(f, reloc_table, max_entries, &n_entries);
fparain@13041 358 f->buffered_values_interpreted_do(&marking_closure);
fparain@13041 359 if (ReportVTBufferRecyclingTimes) {
fparain@13041 360 step2 = Ticks::now();
fparain@13041 361 }
fparain@13041 362
fparain@13041 363 if (n_entries > 0) {
fparain@13041 364 // 3 - sort relocation table entries and compute compaction
fparain@13041 365 qsort(reloc_table, n_entries, sizeof(struct VT_relocation_entry), compare_reloc_entries);
fparain@13041 366 if (f->interpreter_frame_vt_alloc_ptr() == NULL) {
fparain@13041 367 VTBufferChunk* chunk = VTBufferChunk::chunk(reloc_table[0].old_ptr);
fparain@13041 368 while (chunk->prev() != NULL) chunk = chunk->prev();
fparain@13041 369 //f->interpreter_frame_set_vt_alloc_ptr((intptr_t*)chunk->first_alloc());
fparain@13041 370 reloc_table[0].new_ptr = (address)chunk->first_alloc();
fparain@13041 371 } else {
fparain@13041 372 reloc_table[0].new_ptr = (address)f->interpreter_frame_vt_alloc_ptr();
fparain@13041 373 }
fparain@13041 374 ((oop)reloc_table[0].old_ptr)->set_mark((markOop)reloc_table[0].new_ptr);
fparain@13041 375 for (int i = 1; i < n_entries; i++) {
fparain@13041 376 reloc_table[i].new_ptr = relocate_value(reloc_table[i].old_ptr, reloc_table[i-1].new_ptr,
fparain@13041 377 InstanceKlass::cast(((oop)reloc_table[i-1].old_ptr)->klass())->size_helper());
fparain@13041 378 ((oop)reloc_table[i].old_ptr)->set_mark((markOop)reloc_table[i].new_ptr);
fparain@13041 379 }
fparain@13041 380 if (ReportVTBufferRecyclingTimes) {
fparain@13041 381 step3 = Ticks::now();
fparain@13041 382 }
fparain@13041 383
fparain@13041 384 // 4 - update pointers
fparain@13041 385 BufferedValuesPointersUpdate update_closure = BufferedValuesPointersUpdate(f);
fparain@13041 386 f->buffered_values_interpreted_do(&update_closure);
fparain@13041 387 if (ReportVTBufferRecyclingTimes) {
fparain@13041 388 step4 = Ticks::now();
fparain@13041 389 }
fparain@13041 390
fparain@13041 391 // 5 - relocate values
fparain@13041 392 for (int i = 0; i < n_entries; i++) {
fparain@13041 393 if (reloc_table[i].old_ptr != reloc_table[i].new_ptr) {
fparain@13041 394 InstanceKlass* ik_old = InstanceKlass::cast(((oop)reloc_table[i].old_ptr)->klass());
fparain@13041 395 // instead of memcpy, a value_store() might be required here
fparain@13041 396 memcpy(reloc_table[i].new_ptr, reloc_table[i].old_ptr, ik_old->size_helper() * HeapWordSize);
fparain@13041 397 }
fparain@13041 398 // Resetting the mark word
fparain@13041 399 ((oop)reloc_table[i].new_ptr)->set_mark(markOop(((oop)reloc_table[i].new_ptr)->klass()->java_mirror()));
fparain@13041 400 }
fparain@13041 401 if (ReportVTBufferRecyclingTimes) {
fparain@13041 402 step5 = Ticks::now();
fparain@13041 403 }
fparain@13041 404
fparain@13041 405 // 6 - update thread allocation pointer
fparain@13041 406 oop last_oop = (oop)reloc_table[n_entries - 1].new_ptr;
fparain@13041 407 InstanceKlass* ik = InstanceKlass::cast(last_oop->klass());
fparain@13041 408 thread->set_vt_alloc_ptr((address)last_oop + ik->size_helper() * HeapWordSize);
fparain@13041 409 thread->set_vt_alloc_limit(VTBufferChunk::chunk(thread->vt_alloc_ptr())->alloc_limit());
fparain@13041 410 if (ReportVTBufferRecyclingTimes) {
fparain@13041 411 step6 = Ticks::now();
fparain@13041 412 }
fparain@13041 413
fparain@13041 414 // 7 - free/return unused chunks
fparain@13041 415 VTBufferChunk* chunk = VTBufferChunk::chunk(reloc_table[n_entries - 1].new_ptr);
fparain@13041 416 VTBufferChunk* temp = chunk;
fparain@13041 417 chunk = chunk->next();
fparain@13041 418 temp->set_next(NULL);
fparain@13041 419 while (chunk != NULL) {
fparain@13041 420 returned_chunks++;
fparain@13041 421 temp = chunk->next();
fparain@13041 422 VTBuffer::recycle_chunk(thread, chunk);
fparain@13041 423 chunk = temp;
fparain@13041 424 }
fparain@13041 425 if (ReportVTBufferRecyclingTimes) {
fparain@13041 426 step7 = Ticks::now();
fparain@13041 427 }
fparain@13041 428 } else {
fparain@13041 429 f->interpreter_frame_set_vt_alloc_ptr((intptr_t*)thread->vt_alloc_ptr());
fparain@13041 430 }
fparain@13041 431 }
fparain@13041 432
fparain@13041 433 // 8 - free relocation table
fparain@13041 434 FREE_RESOURCE_ARRAY(struct VT_relocation_entry, reloc_table, max_entries);
fparain@13041 435 if (ReportVTBufferRecyclingTimes) {
fparain@13041 436 end = Ticks::now();
fparain@13041 437 ResourceMark rm(thread);
thartmann@13588 438 tty->print_cr("VTBufferRecyling: %s : %s.%s %s : " JLONG_FORMAT "us",
fparain@13041 439 thread->name(),
fparain@13041 440 f->interpreter_frame_method()->klass_name()->as_C_string(),
fparain@13041 441 f->interpreter_frame_method()->name()->as_C_string(),
fparain@13041 442 f->interpreter_frame_method()->signature()->as_C_string(),
fparain@13041 443 (end.value() - begin.value()) / 1000);
thartmann@13588 444 tty->print("Step1 : " JLONG_FORMAT "ns ", step1.value() - begin.value());
thartmann@13588 445 tty->print("Step2 : " JLONG_FORMAT "ns ", step2.value() - step1.value());
thartmann@13588 446 tty->print("Step3 : " JLONG_FORMAT "ns ", step3.value() - step2.value());
thartmann@13588 447 tty->print("Step4 : " JLONG_FORMAT "ns ", step4.value() - step3.value());
thartmann@13588 448 tty->print("Step5 : " JLONG_FORMAT "ns ", step5.value() - step4.value());
thartmann@13588 449 tty->print("Step6 : " JLONG_FORMAT "ns ", step6.value() - step5.value());
thartmann@13588 450 tty->print("Step7 : " JLONG_FORMAT "ns ", step7.value() - step6.value());
thartmann@13588 451 tty->print("Step8 : " JLONG_FORMAT "ns ", end.value() - step7.value());
fparain@13041 452 tty->print_cr("Returned chunks: %d", returned_chunks);
fparain@13041 453 }
fparain@13041 454 }
fparain@13041 455
fparain@13041 456 void BufferedValuesMarking::do_buffered_value(oop* p) {
fparain@13041 457 assert(!Universe::heap()->is_in_reserved_or_null(*p), "Sanity check");
fparain@13041 458 if (VTBuffer::value_belongs_to_frame(*p, _frame)) {
fparain@13041 459 if (!(*p)->mark()->is_marked()) {
fparain@13041 460 assert(*_index < _size, "index outside of relocation table range");
fparain@13041 461 _reloc_table[*_index].old_ptr = (address)*p;
fparain@13041 462 _reloc_table[*_index].chunk_index = VTBufferChunk::chunk(*p)->index();
fparain@13041 463 *_index = (*_index) + 1;
fparain@13041 464 (*p)->set_mark((*p)->mark()->set_marked());
fparain@13041 465 }
fparain@13041 466 }
fparain@13041 467 }
fparain@13041 468
fparain@13041 469 void BufferedValuesPointersUpdate::do_buffered_value(oop* p) {
fparain@13041 470 assert(!Universe::heap()->is_in_reserved_or_null(*p), "Sanity check");
fparain@13041 471 // might be coded more efficiently just by checking mark word is not NULL
fparain@13041 472 if (VTBuffer::value_belongs_to_frame(*p, _frame)) {
fparain@13041 473 *p = (oop)(*p)->mark();
fparain@13041 474 }
fparain@13041 475 }