< prev index next >

src/hotspot/share/gc/g1/g1ParScanThreadState.cpp

Print this page
rev 60648 : [mq]: partial_arrays

*** 58,67 **** --- 58,69 ---- _trim_ticks(), _surviving_young_words_base(NULL), _surviving_young_words(NULL), _surviving_words_length(young_cset_length + 1), _old_gen_is_full(false), + _objarray_scan_chunk_size(ParGCArrayScanChunk), + _objarray_length_offset_in_bytes(arrayOopDesc::length_offset_in_bytes()), _num_optional_regions(optional_cset_length), _numa(g1h->numa()), _obj_alloc_stat(NULL) { // We allocate number of young gen regions in the collection set plus one
*** 197,248 **** void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { oop from_obj = task.to_source_array(); assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); - objArrayOop from_obj_array = objArrayOop(from_obj); - // The from-space object contains the real length. - int length = from_obj_array->length(); - assert(from_obj->is_forwarded(), "must be forwarded"); oop to_obj = from_obj->forwardee(); assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); ! objArrayOop to_obj_array = objArrayOop(to_obj); ! // We keep track of the next start index in the length field of the ! // to-space object. ! int next_index = to_obj_array->length(); ! assert(0 <= next_index && next_index < length, ! "invariant, next index: %d, length: %d", next_index, length); ! ! int start = next_index; ! int end = length; ! int remainder = end - start; ! // We'll try not to push a range that's smaller than ParGCArrayScanChunk. ! if (remainder > 2 * ParGCArrayScanChunk) { ! end = start + ParGCArrayScanChunk; ! to_obj_array->set_length(end); ! // Push the remainder before we process the range in case another ! // worker has run out of things to do and can steal it. ! push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); ! } else { ! assert(length == end, "sanity"); ! // We'll process the final range for this object. Restore the length ! // so that the heap remains parsable in case of evacuation failure. ! to_obj_array->set_length(end); ! } ! HeapRegion* hr = _g1h->heap_region_containing(to_obj); G1ScanInYoungSetter x(&_scanner, hr->is_young()); ! // Process indexes [start,end). It will also process the header ! // along with the first chunk (i.e., the chunk with start == 0). ! // Note that at this point the length field of to_obj_array is not ! // correct given that we are using it to keep track of the next ! // start index. oop_iterate_range() (thankfully!) ignores the length ! // field and only relies on the start / end parameters. It does ! // however return the size of the object which will be incorrect. So ! // we have to ignore it even if we wanted to use it. ! to_obj_array->oop_iterate_range(&_scanner, start, end); } void G1ParScanThreadState::dispatch_task(ScannerTask task) { verify_task(task); if (task.is_narrow_oop_ptr()) { --- 199,278 ---- void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { oop from_obj = task.to_source_array(); assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); assert(from_obj->is_forwarded(), "must be forwarded"); + oop to_obj = from_obj->forwardee(); assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); ! assert(to_obj->is_objArray(), "must be obj array"); ! objArrayOop to_array = objArrayOop(to_obj); ! ! // The next chunk index is in the length field of the to-space object. ! // Atomically increment by the chunk size to claim the associated chunk. ! char* to_addr = cast_from_oop<char*>(to_array); ! char* length_addr_raw = (to_addr + _objarray_length_offset_in_bytes); ! volatile int* length_addr = reinterpret_cast<int*>(length_addr_raw); ! int end = Atomic::add(length_addr, _objarray_scan_chunk_size, memory_order_relaxed); ! #ifdef ASSERT ! // The from-space object contains the real length. ! int length = objArrayOop(from_obj)->length(); ! assert(end <= length, "invariant: end %d, length %d", end, length); ! assert(((length - end) % _objarray_scan_chunk_size) == 0, ! "invariant: end %d, length %d, chunk size %d", ! end, length, _objarray_scan_chunk_size); ! #endif // ASSERT ! HeapRegion* hr = _g1h->heap_region_containing(to_array); G1ScanInYoungSetter x(&_scanner, hr->is_young()); ! // Process claimed chunk. Note that the length field of ! // to_obj_array is not correct. Fortunately, the iteration ignores ! // the length and just relies on start / end. However, it does ! // return the (incorrect) length, but we ignore it. ! to_array->oop_iterate_range(&_scanner, end - _objarray_scan_chunk_size, end); ! } ! ! oop G1ParScanThreadState::start_partial_objArray(G1HeapRegionAttr dest_attr, ! oop from_obj, ! oop to_obj) { ! assert(from_obj->is_objArray(), "precondition"); ! assert(from_obj->is_forwarded(), "precondition"); ! assert(from_obj->forwardee() == to_obj, "precondition"); ! assert(from_obj != to_obj, "should not be scanning self-forwarded objects"); ! assert(to_obj->is_objArray(), "precondition"); ! ! objArrayOop to_array = objArrayOop(to_obj); ! ! int length = objArrayOop(from_obj)->length(); ! int chunks = length / _objarray_scan_chunk_size; ! int end = length % _objarray_scan_chunk_size; ! assert(end <= length, "invariant"); ! assert(((length - end) % _objarray_scan_chunk_size) == 0, "invariant"); ! // The value of end can be 0, either because of a 0-length array or ! // because length is a multiple of the chunk size. Both of those ! // are rare and handled in the normal course of the iteration, so ! // not worth doing anything special about here. ! ! // Set to's length to end of initial chunk. Partial tasks use that ! // length field as the start of the next chunk to process. Must be ! // done before enqueuing partial scan tasks, in case other threads ! // steal any of those tasks. ! to_array->set_length(end); ! // Push partial scan tasks for all but the initial chunk. Pushed ! // before processing the initial chunk to allow other workers to ! // steal while we're processing. ! for (int i = 0; i < chunks; ++i) { ! push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); ! } ! G1ScanInYoungSetter x(&_scanner, dest_attr.is_young()); ! // Process the initial chunk. No need to process the type in the ! // klass, as it will already be handled by processing the built-in ! // module. The length of to_array is not correct, but fortunately ! // the iteration ignores that length field and relies on start/end. ! to_array->oop_iterate_range(&_scanner, 0, end); ! return to_array; } void G1ParScanThreadState::dispatch_task(ScannerTask task) { verify_task(task); if (task.is_narrow_oop_ptr()) {
*** 392,402 **** oop const old, markWord const old_mark) { assert(region_attr.is_in_cset(), "Unexpected region attr type: %s", region_attr.get_type_str()); ! const size_t word_sz = old->size(); uint age = 0; G1HeapRegionAttr dest_attr = next_region_attr(region_attr, old_mark, age); HeapRegion* const from_region = _g1h->heap_region_containing(old); uint node_index = from_region->node_index(); --- 422,435 ---- oop const old, markWord const old_mark) { assert(region_attr.is_in_cset(), "Unexpected region attr type: %s", region_attr.get_type_str()); ! // Get the klass once. We'll need it again later, and this avoids ! // re-decoding when it's compressed. ! Klass* klass = old->klass(); ! const size_t word_sz = old->size_given_klass(klass); uint age = 0; G1HeapRegionAttr dest_attr = next_region_attr(region_attr, old_mark, age); HeapRegion* const from_region = _g1h->heap_region_containing(old); uint node_index = from_region->node_index();
*** 459,469 **** _age_table.add(age, word_sz); } else { obj->set_mark_raw(old_mark); } ! if (G1StringDedup::is_enabled()) { const bool is_from_young = region_attr.is_young(); const bool is_to_young = dest_attr.is_young(); assert(is_from_young == from_region->is_young(), "sanity"); assert(is_to_young == _g1h->heap_region_containing(obj)->is_young(), --- 492,517 ---- _age_table.add(age, word_sz); } else { obj->set_mark_raw(old_mark); } ! // Most objects are not arrays, so do one array check rather than both ! // typeArray and objArray checks for each object. ! if (klass->is_array_klass()) { ! if (klass->is_typeArray_klass()) { ! // Nothing needs to be done for typeArrays. Body doesn't contain ! // any oops to scan, and the type in the klass will already be handled ! // by processing the built-in module. ! return obj; ! } else if (klass->is_objArray_klass()) { ! // Do special handling for objArray. ! return start_partial_objArray(dest_attr, old, obj); ! } ! // Not a special array, so fall through to generic handling. ! } ! ! if (G1StringDedup::is_enabled() && (klass == SystemDictionary::String_klass())) { const bool is_from_young = region_attr.is_young(); const bool is_to_young = dest_attr.is_young(); assert(is_from_young == from_region->is_young(), "sanity"); assert(is_to_young == _g1h->heap_region_containing(obj)->is_young(),
*** 472,492 **** is_to_young, _worker_id, obj); } - if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) { - // We keep track of the next start index in the length field of - // the to-space object. The actual length can be found in the - // length field of the from-space object. - arrayOop(obj)->set_length(0); - do_partial_array(PartialArrayScanTask(old)); - } else { G1ScanInYoungSetter x(&_scanner, dest_attr.is_young()); obj->oop_iterate_backwards(&_scanner); - } return obj; } else { _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index); return forward_ptr; } } --- 520,533 ---- is_to_young, _worker_id, obj); } G1ScanInYoungSetter x(&_scanner, dest_attr.is_young()); obj->oop_iterate_backwards(&_scanner); return obj; + } else { _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index); return forward_ptr; } }
< prev index next >