< prev index next >

src/hotspot/share/cds/aotMappedHeapWriter.cpp

Print this page

 26 #include "cds/aotMappedHeapWriter.hpp"
 27 #include "cds/aotReferenceObjSupport.hpp"
 28 #include "cds/cdsConfig.hpp"
 29 #include "cds/filemap.hpp"
 30 #include "cds/heapShared.inline.hpp"
 31 #include "cds/regeneratedClasses.hpp"
 32 #include "classfile/javaClasses.hpp"
 33 #include "classfile/modules.hpp"
 34 #include "classfile/systemDictionary.hpp"
 35 #include "gc/shared/collectedHeap.hpp"
 36 #include "memory/allocation.inline.hpp"
 37 #include "memory/iterator.inline.hpp"
 38 #include "memory/oopFactory.hpp"
 39 #include "memory/universe.hpp"
 40 #include "oops/compressedOops.hpp"
 41 #include "oops/objArrayOop.inline.hpp"
 42 #include "oops/oop.inline.hpp"
 43 #include "oops/oopHandle.inline.hpp"
 44 #include "oops/typeArrayKlass.hpp"
 45 #include "oops/typeArrayOop.hpp"

 46 #include "runtime/java.hpp"
 47 #include "runtime/mutexLocker.hpp"
 48 #include "utilities/bitMap.inline.hpp"
 49 #if INCLUDE_G1GC
 50 #include "gc/g1/g1CollectedHeap.hpp"
 51 #include "gc/g1/g1HeapRegion.hpp"
 52 #endif
 53 
 54 #if INCLUDE_CDS_JAVA_HEAP
 55 
 56 GrowableArrayCHeap<u1, mtClassShared>* AOTMappedHeapWriter::_buffer = nullptr;
 57 
 58 bool AOTMappedHeapWriter::_is_writing_deterministic_heap = false;
 59 size_t AOTMappedHeapWriter::_buffer_used;
 60 
 61 // Heap root segments
 62 HeapRootSegments AOTMappedHeapWriter::_heap_root_segments;
 63 
 64 address AOTMappedHeapWriter::_requested_bottom;
 65 address AOTMappedHeapWriter::_requested_top;

277 address AOTMappedHeapWriter::requested_address() {
278   assert(_buffer != nullptr, "must be initialized");
279   return _requested_bottom;
280 }
281 
282 void AOTMappedHeapWriter::allocate_buffer() {
283   int initial_buffer_size = 100000;
284   _buffer = new GrowableArrayCHeap<u1, mtClassShared>(initial_buffer_size);
285   _buffer_used = 0;
286   ensure_buffer_space(1); // so that buffer_bottom() works
287 }
288 
289 void AOTMappedHeapWriter::ensure_buffer_space(size_t min_bytes) {
290   // We usually have very small heaps. If we get a huge one it's probably caused by a bug.
291   guarantee(min_bytes <= max_jint, "we dont support archiving more than 2G of objects");
292   _buffer->at_grow(to_array_index(min_bytes));
293 }
294 
295 objArrayOop AOTMappedHeapWriter::allocate_root_segment(size_t offset, int element_count) {
296   HeapWord* mem = offset_to_buffered_address<HeapWord *>(offset);
297   memset(mem, 0, objArrayOopDesc::object_size(element_count));
298 
299   // The initialization code is copied from MemAllocator::finish and ObjArrayAllocator::initialize.
300   if (UseCompactObjectHeaders) {
301     oopDesc::release_set_mark(mem, Universe::objectArrayKlass()->prototype_header());
302   } else {

303     oopDesc::set_mark(mem, markWord::prototype());
304     oopDesc::release_set_klass(mem, Universe::objectArrayKlass());
305   }
306   arrayOopDesc::set_length(mem, element_count);
307   return objArrayOop(cast_to_oop(mem));
308 }
309 
310 void AOTMappedHeapWriter::root_segment_at_put(objArrayOop segment, int index, oop root) {
311   // Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside the real heap!
312   if (UseCompressedOops) {
313     *segment->obj_at_addr<narrowOop>(index) = CompressedOops::encode(root);
314   } else {
315     *segment->obj_at_addr<oop>(index) = root;
316   }
317 }
318 
319 void AOTMappedHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
320   // Depending on the number of classes we are archiving, a single roots array may be
321   // larger than MIN_GC_REGION_ALIGNMENT. Roots are allocated first in the buffer, which
322   // allows us to chop the large array into a series of "segments". Current layout
323   // starts with zero or more segments exactly fitting MIN_GC_REGION_ALIGNMENT, and end
324   // with a single segment that may be smaller than MIN_GC_REGION_ALIGNMENT.
325   // This is simple and efficient. We do not need filler objects anywhere between the segments,
326   // or immediately after the last segment. This allows starting the object dump immediately
327   // after the roots.
328 
329   assert((_buffer_used % MIN_GC_REGION_ALIGNMENT) == 0,
330          "Pre-condition: Roots start at aligned boundary: %zu", _buffer_used);
331 
332   int max_elem_count = ((MIN_GC_REGION_ALIGNMENT - arrayOopDesc::header_size_in_bytes()) / heapOopSize);
333   assert(objArrayOopDesc::object_size(max_elem_count)*HeapWordSize == MIN_GC_REGION_ALIGNMENT,
334          "Should match exactly");
335 
336   HeapRootSegments segments(_buffer_used,
337                             roots->length(),
338                             MIN_GC_REGION_ALIGNMENT,
339                             max_elem_count);
340 
341   int root_index = 0;
342   for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
343     int size_elems = segments.size_in_elems(seg_idx);
344     size_t size_bytes = segments.size_in_bytes(seg_idx);
345 
346     size_t oop_offset = _buffer_used;
347     _buffer_used = oop_offset + size_bytes;
348     ensure_buffer_space(_buffer_used);
349 
350     assert((oop_offset % MIN_GC_REGION_ALIGNMENT) == 0,
351            "Roots segment %zu start is not aligned: %zu",
352            segments.count(), oop_offset);
353 

428     oop src_obj = _source_objs->at(src_obj_index);
429     HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(src_obj);
430     assert(info != nullptr, "must be");
431     size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
432     info->set_buffer_offset(buffer_offset);
433 
434     OopHandle handle(Universe::vm_global(), src_obj);
435     _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, handle);
436     _buffer_offset_to_source_obj_table->maybe_grow();
437 
438     if (java_lang_Module::is_instance(src_obj)) {
439       Modules::check_archived_module_oop(src_obj);
440     }
441   }
442 
443   log_info(aot)("Size of heap region = %zu bytes, %d objects, %d roots, %d native ptrs",
444                 _buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
445 }
446 
447 size_t AOTMappedHeapWriter::filler_array_byte_size(int length) {
448   size_t byte_size = objArrayOopDesc::object_size(length) * HeapWordSize;
449   return byte_size;
450 }
451 
452 int AOTMappedHeapWriter::filler_array_length(size_t fill_bytes) {
453   assert(is_object_aligned(fill_bytes), "must be");
454   size_t elemSize = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
455 
456   int initial_length = to_array_length(fill_bytes / elemSize);
457   for (int length = initial_length; length >= 0; length --) {
458     size_t array_byte_size = filler_array_byte_size(length);
459     if (array_byte_size == fill_bytes) {
460       return length;
461     }
462   }
463 
464   ShouldNotReachHere();
465   return -1;
466 }
467 
468 HeapWord* AOTMappedHeapWriter::init_filler_array_at_buffer_top(int array_length, size_t fill_bytes) {
469   assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses");
470   Klass* oak = Universe::objectArrayKlass(); // already relocated to point to archived klass
471   HeapWord* mem = offset_to_buffered_address<HeapWord*>(_buffer_used);
472   memset(mem, 0, fill_bytes);
473   narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(oak);
474   if (UseCompactObjectHeaders) {
475     oopDesc::release_set_mark(mem, markWord::prototype().set_narrow_klass(nk));
476   } else {

477     oopDesc::set_mark(mem, markWord::prototype());
478     cast_to_oop(mem)->set_narrow_klass(nk);
479   }
480   arrayOopDesc::set_length(mem, array_length);
481   return mem;
482 }
483 
484 void AOTMappedHeapWriter::maybe_fill_gc_region_gap(size_t required_byte_size) {
485   // We fill only with arrays (so we don't need to use a single HeapWord filler if the
486   // leftover space is smaller than a zero-sized array object). Therefore, we need to
487   // make sure there's enough space of min_filler_byte_size in the current region after
488   // required_byte_size has been allocated. If not, fill the remainder of the current
489   // region.
490   size_t min_filler_byte_size = filler_array_byte_size(0);
491   size_t new_used = _buffer_used + required_byte_size + min_filler_byte_size;
492 
493   const size_t cur_min_region_bottom = align_down(_buffer_used, MIN_GC_REGION_ALIGNMENT);
494   const size_t next_min_region_bottom = align_down(new_used, MIN_GC_REGION_ALIGNMENT);
495 
496   if (cur_min_region_bottom != next_min_region_bottom) {

711 
712   assert(request_p >= (T*)_requested_bottom, "sanity");
713   assert(request_p <  (T*)_requested_top, "sanity");
714   requested_region_bottom = _requested_bottom;
715 
716   // Mark the pointer in the oopmap
717   T* region_bottom = (T*)requested_region_bottom;
718   assert(request_p >= region_bottom, "must be");
719   BitMap::idx_t idx = request_p - region_bottom;
720   assert(idx < oopmap->size(), "overflow");
721   oopmap->set_bit(idx);
722 }
723 
724 void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop src_obj,  Klass* src_klass) {
725   assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses");
726   narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass);
727   address buffered_addr = requested_addr_to_buffered_addr(cast_from_oop<address>(requested_obj));
728 
729   oop fake_oop = cast_to_oop(buffered_addr);
730   if (UseCompactObjectHeaders) {
731     fake_oop->set_mark(markWord::prototype().set_narrow_klass(nk));

732   } else {
733     fake_oop->set_narrow_klass(nk);
734   }
735 
736   if (src_obj == nullptr) {
737     return;
738   }
739   // We need to retain the identity_hash, because it may have been used by some hashtables
740   // in the shared heap.
741   if (!src_obj->fast_no_hash_check()) {
742     intptr_t src_hash = src_obj->identity_hash();
743     if (UseCompactObjectHeaders) {
744       fake_oop->set_mark(markWord::prototype().set_narrow_klass(nk).copy_set_hash(src_hash));


745     } else {
746       fake_oop->set_mark(markWord::prototype().copy_set_hash(src_hash));
747     }
748     assert(fake_oop->mark().is_unlocked(), "sanity");
749 
750     DEBUG_ONLY(intptr_t archived_hash = fake_oop->identity_hash());
751     assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash);
752   }
753   // Strip age bits.
754   fake_oop->set_mark(fake_oop->mark().set_age(0));
755 }
756 
757 class AOTMappedHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
758   oop _src_obj;
759   address _buffered_obj;
760   CHeapBitMap* _oopmap;
761   bool _is_java_lang_ref;
762 public:
763   EmbeddedOopRelocator(oop src_obj, address buffered_obj, CHeapBitMap* oopmap) :
764     _src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap)

 26 #include "cds/aotMappedHeapWriter.hpp"
 27 #include "cds/aotReferenceObjSupport.hpp"
 28 #include "cds/cdsConfig.hpp"
 29 #include "cds/filemap.hpp"
 30 #include "cds/heapShared.inline.hpp"
 31 #include "cds/regeneratedClasses.hpp"
 32 #include "classfile/javaClasses.hpp"
 33 #include "classfile/modules.hpp"
 34 #include "classfile/systemDictionary.hpp"
 35 #include "gc/shared/collectedHeap.hpp"
 36 #include "memory/allocation.inline.hpp"
 37 #include "memory/iterator.inline.hpp"
 38 #include "memory/oopFactory.hpp"
 39 #include "memory/universe.hpp"
 40 #include "oops/compressedOops.hpp"
 41 #include "oops/objArrayOop.inline.hpp"
 42 #include "oops/oop.inline.hpp"
 43 #include "oops/oopHandle.inline.hpp"
 44 #include "oops/typeArrayKlass.hpp"
 45 #include "oops/typeArrayOop.hpp"
 46 #include "runtime/arguments.hpp"
 47 #include "runtime/java.hpp"
 48 #include "runtime/mutexLocker.hpp"
 49 #include "utilities/bitMap.inline.hpp"
 50 #if INCLUDE_G1GC
 51 #include "gc/g1/g1CollectedHeap.hpp"
 52 #include "gc/g1/g1HeapRegion.hpp"
 53 #endif
 54 
 55 #if INCLUDE_CDS_JAVA_HEAP
 56 
 57 GrowableArrayCHeap<u1, mtClassShared>* AOTMappedHeapWriter::_buffer = nullptr;
 58 
 59 bool AOTMappedHeapWriter::_is_writing_deterministic_heap = false;
 60 size_t AOTMappedHeapWriter::_buffer_used;
 61 
 62 // Heap root segments
 63 HeapRootSegments AOTMappedHeapWriter::_heap_root_segments;
 64 
 65 address AOTMappedHeapWriter::_requested_bottom;
 66 address AOTMappedHeapWriter::_requested_top;

278 address AOTMappedHeapWriter::requested_address() {
279   assert(_buffer != nullptr, "must be initialized");
280   return _requested_bottom;
281 }
282 
283 void AOTMappedHeapWriter::allocate_buffer() {
284   int initial_buffer_size = 100000;
285   _buffer = new GrowableArrayCHeap<u1, mtClassShared>(initial_buffer_size);
286   _buffer_used = 0;
287   ensure_buffer_space(1); // so that buffer_bottom() works
288 }
289 
290 void AOTMappedHeapWriter::ensure_buffer_space(size_t min_bytes) {
291   // We usually have very small heaps. If we get a huge one it's probably caused by a bug.
292   guarantee(min_bytes <= max_jint, "we dont support archiving more than 2G of objects");
293   _buffer->at_grow(to_array_index(min_bytes));
294 }
295 
296 objArrayOop AOTMappedHeapWriter::allocate_root_segment(size_t offset, int element_count) {
297   HeapWord* mem = offset_to_buffered_address<HeapWord *>(offset);
298   memset(mem, 0, refArrayOopDesc::object_size(element_count));
299 
300   // The initialization code is copied from MemAllocator::finish and ObjArrayAllocator::initialize.
301   if (UseCompactObjectHeaders) {
302     oopDesc::release_set_mark(mem, Universe::objectArrayKlass()->prototype_header());
303   } else {
304     assert(!Arguments::is_valhalla_enabled() || Universe::objectArrayKlass()->prototype_header() == markWord::prototype(), "should be the same");
305     oopDesc::set_mark(mem, markWord::prototype());
306     oopDesc::release_set_klass(mem, Universe::objectArrayKlass());
307   }
308   arrayOopDesc::set_length(mem, element_count);
309   return objArrayOop(cast_to_oop(mem));
310 }
311 
312 void AOTMappedHeapWriter::root_segment_at_put(objArrayOop segment, int index, oop root) {
313   // Do not use arrayOop->obj_at_put(i, o) as arrayOop is outside the real heap!
314   if (UseCompressedOops) {
315     *segment->obj_at_addr<narrowOop>(index) = CompressedOops::encode(root);
316   } else {
317     *segment->obj_at_addr<oop>(index) = root;
318   }
319 }
320 
321 void AOTMappedHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap<oop, mtClassShared>* roots) {
322   // Depending on the number of classes we are archiving, a single roots array may be
323   // larger than MIN_GC_REGION_ALIGNMENT. Roots are allocated first in the buffer, which
324   // allows us to chop the large array into a series of "segments". Current layout
325   // starts with zero or more segments exactly fitting MIN_GC_REGION_ALIGNMENT, and end
326   // with a single segment that may be smaller than MIN_GC_REGION_ALIGNMENT.
327   // This is simple and efficient. We do not need filler objects anywhere between the segments,
328   // or immediately after the last segment. This allows starting the object dump immediately
329   // after the roots.
330 
331   assert((_buffer_used % MIN_GC_REGION_ALIGNMENT) == 0,
332          "Pre-condition: Roots start at aligned boundary: %zu", _buffer_used);
333 
334   int max_elem_count = ((MIN_GC_REGION_ALIGNMENT - arrayOopDesc::header_size_in_bytes()) / heapOopSize);
335   assert(refArrayOopDesc::object_size(max_elem_count)*HeapWordSize == MIN_GC_REGION_ALIGNMENT,
336          "Should match exactly");
337 
338   HeapRootSegments segments(_buffer_used,
339                             roots->length(),
340                             MIN_GC_REGION_ALIGNMENT,
341                             max_elem_count);
342 
343   int root_index = 0;
344   for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) {
345     int size_elems = segments.size_in_elems(seg_idx);
346     size_t size_bytes = segments.size_in_bytes(seg_idx);
347 
348     size_t oop_offset = _buffer_used;
349     _buffer_used = oop_offset + size_bytes;
350     ensure_buffer_space(_buffer_used);
351 
352     assert((oop_offset % MIN_GC_REGION_ALIGNMENT) == 0,
353            "Roots segment %zu start is not aligned: %zu",
354            segments.count(), oop_offset);
355 

430     oop src_obj = _source_objs->at(src_obj_index);
431     HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(src_obj);
432     assert(info != nullptr, "must be");
433     size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
434     info->set_buffer_offset(buffer_offset);
435 
436     OopHandle handle(Universe::vm_global(), src_obj);
437     _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, handle);
438     _buffer_offset_to_source_obj_table->maybe_grow();
439 
440     if (java_lang_Module::is_instance(src_obj)) {
441       Modules::check_archived_module_oop(src_obj);
442     }
443   }
444 
445   log_info(aot)("Size of heap region = %zu bytes, %d objects, %d roots, %d native ptrs",
446                 _buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
447 }
448 
449 size_t AOTMappedHeapWriter::filler_array_byte_size(int length) {
450   size_t byte_size = refArrayOopDesc::object_size(length) * HeapWordSize;
451   return byte_size;
452 }
453 
454 int AOTMappedHeapWriter::filler_array_length(size_t fill_bytes) {
455   assert(is_object_aligned(fill_bytes), "must be");
456   size_t elemSize = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop));
457 
458   int initial_length = to_array_length(fill_bytes / elemSize);
459   for (int length = initial_length; length >= 0; length --) {
460     size_t array_byte_size = filler_array_byte_size(length);
461     if (array_byte_size == fill_bytes) {
462       return length;
463     }
464   }
465 
466   ShouldNotReachHere();
467   return -1;
468 }
469 
470 HeapWord* AOTMappedHeapWriter::init_filler_array_at_buffer_top(int array_length, size_t fill_bytes) {
471   assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses");
472   Klass* oak = Universe::objectArrayKlass(); // already relocated to point to archived klass
473   HeapWord* mem = offset_to_buffered_address<HeapWord*>(_buffer_used);
474   memset(mem, 0, fill_bytes);
475   narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(oak);
476   if (UseCompactObjectHeaders) {
477     oopDesc::release_set_mark(mem, markWord::prototype().set_narrow_klass(nk));
478   } else {
479     assert(!Arguments::is_valhalla_enabled() || Universe::objectArrayKlass()->prototype_header() == markWord::prototype(), "should be the same");
480     oopDesc::set_mark(mem, markWord::prototype());
481     cast_to_oop(mem)->set_narrow_klass(nk);
482   }
483   arrayOopDesc::set_length(mem, array_length);
484   return mem;
485 }
486 
487 void AOTMappedHeapWriter::maybe_fill_gc_region_gap(size_t required_byte_size) {
488   // We fill only with arrays (so we don't need to use a single HeapWord filler if the
489   // leftover space is smaller than a zero-sized array object). Therefore, we need to
490   // make sure there's enough space of min_filler_byte_size in the current region after
491   // required_byte_size has been allocated. If not, fill the remainder of the current
492   // region.
493   size_t min_filler_byte_size = filler_array_byte_size(0);
494   size_t new_used = _buffer_used + required_byte_size + min_filler_byte_size;
495 
496   const size_t cur_min_region_bottom = align_down(_buffer_used, MIN_GC_REGION_ALIGNMENT);
497   const size_t next_min_region_bottom = align_down(new_used, MIN_GC_REGION_ALIGNMENT);
498 
499   if (cur_min_region_bottom != next_min_region_bottom) {

714 
715   assert(request_p >= (T*)_requested_bottom, "sanity");
716   assert(request_p <  (T*)_requested_top, "sanity");
717   requested_region_bottom = _requested_bottom;
718 
719   // Mark the pointer in the oopmap
720   T* region_bottom = (T*)requested_region_bottom;
721   assert(request_p >= region_bottom, "must be");
722   BitMap::idx_t idx = request_p - region_bottom;
723   assert(idx < oopmap->size(), "overflow");
724   oopmap->set_bit(idx);
725 }
726 
727 void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop src_obj,  Klass* src_klass) {
728   assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses");
729   narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass);
730   address buffered_addr = requested_addr_to_buffered_addr(cast_from_oop<address>(requested_obj));
731 
732   oop fake_oop = cast_to_oop(buffered_addr);
733   if (UseCompactObjectHeaders) {
734     markWord prototype_header = src_klass->prototype_header().set_narrow_klass(nk);
735     fake_oop->set_mark(prototype_header);
736   } else {
737     fake_oop->set_narrow_klass(nk);
738   }
739 
740   if (src_obj == nullptr) {
741     return;
742   }
743   // We need to retain the identity_hash, because it may have been used by some hashtables
744   // in the shared heap.
745   if (!src_obj->fast_no_hash_check() && (!(Arguments::is_valhalla_enabled() && src_obj->mark().is_inline_type()))) {
746     intptr_t src_hash = src_obj->identity_hash();
747     if (UseCompactObjectHeaders) {
748       fake_oop->set_mark(fake_oop->mark().copy_set_hash(src_hash));
749     } else if (Arguments::is_valhalla_enabled()) {
750       fake_oop->set_mark(src_klass->prototype_header().copy_set_hash(src_hash));
751     } else {
752       fake_oop->set_mark(markWord::prototype().copy_set_hash(src_hash));
753     }
754     assert(fake_oop->mark().is_unlocked(), "sanity");
755 
756     DEBUG_ONLY(intptr_t archived_hash = fake_oop->identity_hash());
757     assert(src_hash == archived_hash, "Different hash codes: original " INTPTR_FORMAT ", archived " INTPTR_FORMAT, src_hash, archived_hash);
758   }
759   // Strip age bits.
760   fake_oop->set_mark(fake_oop->mark().set_age(0));
761 }
762 
763 class AOTMappedHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
764   oop _src_obj;
765   address _buffered_obj;
766   CHeapBitMap* _oopmap;
767   bool _is_java_lang_ref;
768 public:
769   EmbeddedOopRelocator(oop src_obj, address buffered_obj, CHeapBitMap* oopmap) :
770     _src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap)
< prev index next >