Mon, 08 Dec 2014 18:57:33 +0100
8067655: Clean up G1 remembered set oop iteration
Summary: Pass on the static type G1ParPushHeapRSClosure to allow oop_iterate devirtualization
Reviewed-by: jmasa, kbarrett
tschatzl@6937 | 1 | /* |
tschatzl@6937 | 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
tschatzl@6937 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
tschatzl@6937 | 4 | * |
tschatzl@6937 | 5 | * This code is free software; you can redistribute it and/or modify it |
tschatzl@6937 | 6 | * under the terms of the GNU General Public License version 2 only, as |
tschatzl@6937 | 7 | * published by the Free Software Foundation. |
tschatzl@6937 | 8 | * |
tschatzl@6937 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
tschatzl@6937 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
tschatzl@6937 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
tschatzl@6937 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
tschatzl@6937 | 13 | * accompanied this code). |
tschatzl@6937 | 14 | * |
tschatzl@6937 | 15 | * You should have received a copy of the GNU General Public License version |
tschatzl@6937 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
tschatzl@6937 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
tschatzl@6937 | 18 | * |
tschatzl@6937 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
tschatzl@6937 | 20 | * or visit www.oracle.com if you need additional information or have any |
tschatzl@6937 | 21 | * questions. |
tschatzl@6937 | 22 | * |
tschatzl@6937 | 23 | */ |
tschatzl@6937 | 24 | |
tschatzl@6937 | 25 | #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1PARSCANTHREADSTATE_HPP |
tschatzl@6937 | 26 | #define SHARE_VM_GC_IMPLEMENTATION_G1_G1PARSCANTHREADSTATE_HPP |
tschatzl@6937 | 27 | |
tschatzl@6937 | 28 | #include "gc_implementation/g1/dirtyCardQueue.hpp" |
tschatzl@6937 | 29 | #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" |
tschatzl@6937 | 30 | #include "gc_implementation/g1/g1CollectedHeap.hpp" |
tschatzl@6937 | 31 | #include "gc_implementation/g1/g1CollectorPolicy.hpp" |
tschatzl@6937 | 32 | #include "gc_implementation/g1/g1OopClosures.hpp" |
tschatzl@6937 | 33 | #include "gc_implementation/g1/g1RemSet.hpp" |
tschatzl@6937 | 34 | #include "gc_implementation/shared/ageTable.hpp" |
tschatzl@6937 | 35 | #include "memory/allocation.hpp" |
tschatzl@6937 | 36 | #include "oops/oop.hpp" |
tschatzl@6937 | 37 | |
tschatzl@6937 | 38 | class HeapRegion; |
tschatzl@6937 | 39 | class outputStream; |
tschatzl@6937 | 40 | |
tschatzl@6937 | 41 | class G1ParScanThreadState : public StackObj { |
tschatzl@6938 | 42 | private: |
tschatzl@6937 | 43 | G1CollectedHeap* _g1h; |
tschatzl@6937 | 44 | RefToScanQueue* _refs; |
tschatzl@6937 | 45 | DirtyCardQueue _dcq; |
tschatzl@6937 | 46 | G1SATBCardTableModRefBS* _ct_bs; |
tschatzl@6937 | 47 | G1RemSet* _g1_rem; |
tschatzl@6937 | 48 | |
sjohanss@7118 | 49 | G1ParGCAllocator* _g1_par_allocator; |
sjohanss@7118 | 50 | |
tschatzl@6937 | 51 | ageTable _age_table; |
tschatzl@6937 | 52 | |
tschatzl@6937 | 53 | G1ParScanClosure _scanner; |
tschatzl@6937 | 54 | |
tschatzl@6937 | 55 | size_t _alloc_buffer_waste; |
tschatzl@6937 | 56 | size_t _undo_waste; |
tschatzl@6937 | 57 | |
tschatzl@6937 | 58 | OopsInHeapRegionClosure* _evac_failure_cl; |
tschatzl@6937 | 59 | |
tschatzl@6937 | 60 | int _hash_seed; |
tschatzl@6937 | 61 | uint _queue_num; |
tschatzl@6937 | 62 | |
tschatzl@6937 | 63 | size_t _term_attempts; |
tschatzl@6937 | 64 | |
tschatzl@6937 | 65 | double _start; |
tschatzl@6937 | 66 | double _start_strong_roots; |
tschatzl@6937 | 67 | double _strong_roots_time; |
tschatzl@6937 | 68 | double _start_term; |
tschatzl@6937 | 69 | double _term_time; |
tschatzl@6937 | 70 | |
tschatzl@6937 | 71 | // Map from young-age-index (0 == not young, 1 is youngest) to |
tschatzl@6937 | 72 | // surviving words. base is what we get back from the malloc call |
tschatzl@6937 | 73 | size_t* _surviving_young_words_base; |
tschatzl@6937 | 74 | // this points into the array, as we use the first few entries for padding |
tschatzl@6937 | 75 | size_t* _surviving_young_words; |
tschatzl@6937 | 76 | |
tschatzl@6937 | 77 | #define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t)) |
tschatzl@6937 | 78 | |
tschatzl@6937 | 79 | void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; } |
tschatzl@6937 | 80 | void add_to_undo_waste(size_t waste) { _undo_waste += waste; } |
tschatzl@6937 | 81 | |
tschatzl@6937 | 82 | DirtyCardQueue& dirty_card_queue() { return _dcq; } |
tschatzl@6937 | 83 | G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } |
tschatzl@6937 | 84 | |
tschatzl@6938 | 85 | public: |
tschatzl@6937 | 86 | G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp); |
tschatzl@6938 | 87 | ~G1ParScanThreadState(); |
tschatzl@6937 | 88 | |
tschatzl@6937 | 89 | ageTable* age_table() { return &_age_table; } |
tschatzl@6937 | 90 | |
tschatzl@6937 | 91 | #ifdef ASSERT |
tschatzl@6938 | 92 | bool queue_is_empty() const { return _refs->is_empty(); } |
tschatzl@6938 | 93 | |
tschatzl@6937 | 94 | bool verify_ref(narrowOop* ref) const; |
tschatzl@6937 | 95 | bool verify_ref(oop* ref) const; |
tschatzl@6937 | 96 | bool verify_task(StarTask ref) const; |
tschatzl@6937 | 97 | #endif // ASSERT |
tschatzl@6937 | 98 | |
tschatzl@6937 | 99 | template <class T> void push_on_queue(T* ref) { |
tschatzl@6937 | 100 | assert(verify_ref(ref), "sanity"); |
tschatzl@6938 | 101 | _refs->push(ref); |
tschatzl@6937 | 102 | } |
tschatzl@6937 | 103 | |
tschatzl@7218 | 104 | template <class T> void update_rs(HeapRegion* from, T* p, int tid) { |
tschatzl@7218 | 105 | // If the new value of the field points to the same region or |
tschatzl@7218 | 106 | // is the to-space, we don't need to include it in the Rset updates. |
tschatzl@7218 | 107 | if (!from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && !from->is_survivor()) { |
tschatzl@7218 | 108 | size_t card_index = ctbs()->index_for(p); |
tschatzl@7218 | 109 | // If the card hasn't been added to the buffer, do it. |
tschatzl@7218 | 110 | if (ctbs()->mark_card_deferred(card_index)) { |
tschatzl@7218 | 111 | dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index)); |
tschatzl@7218 | 112 | } |
tschatzl@7218 | 113 | } |
tschatzl@7218 | 114 | } |
tschatzl@6938 | 115 | public: |
tschatzl@6937 | 116 | |
tschatzl@6937 | 117 | void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) { |
tschatzl@6937 | 118 | _evac_failure_cl = evac_failure_cl; |
tschatzl@6937 | 119 | } |
tschatzl@6938 | 120 | |
tschatzl@6938 | 121 | OopsInHeapRegionClosure* evac_failure_closure() { return _evac_failure_cl; } |
tschatzl@6937 | 122 | |
tschatzl@6937 | 123 | int* hash_seed() { return &_hash_seed; } |
tschatzl@6937 | 124 | uint queue_num() { return _queue_num; } |
tschatzl@6937 | 125 | |
tschatzl@6937 | 126 | size_t term_attempts() const { return _term_attempts; } |
tschatzl@6937 | 127 | void note_term_attempt() { _term_attempts++; } |
tschatzl@6937 | 128 | |
tschatzl@6937 | 129 | void start_strong_roots() { |
tschatzl@6937 | 130 | _start_strong_roots = os::elapsedTime(); |
tschatzl@6937 | 131 | } |
tschatzl@6937 | 132 | void end_strong_roots() { |
tschatzl@6937 | 133 | _strong_roots_time += (os::elapsedTime() - _start_strong_roots); |
tschatzl@6937 | 134 | } |
tschatzl@6937 | 135 | double strong_roots_time() const { return _strong_roots_time; } |
tschatzl@6937 | 136 | |
tschatzl@6937 | 137 | void start_term_time() { |
tschatzl@6937 | 138 | note_term_attempt(); |
tschatzl@6937 | 139 | _start_term = os::elapsedTime(); |
tschatzl@6937 | 140 | } |
tschatzl@6937 | 141 | void end_term_time() { |
tschatzl@6937 | 142 | _term_time += (os::elapsedTime() - _start_term); |
tschatzl@6937 | 143 | } |
tschatzl@6937 | 144 | double term_time() const { return _term_time; } |
tschatzl@6937 | 145 | |
tschatzl@6937 | 146 | double elapsed_time() const { |
tschatzl@6937 | 147 | return os::elapsedTime() - _start; |
tschatzl@6937 | 148 | } |
tschatzl@6937 | 149 | |
tschatzl@6938 | 150 | static void print_termination_stats_hdr(outputStream* const st = gclog_or_tty); |
tschatzl@6938 | 151 | void print_termination_stats(int i, outputStream* const st = gclog_or_tty) const; |
tschatzl@6937 | 152 | |
tschatzl@6937 | 153 | size_t* surviving_young_words() { |
tschatzl@6937 | 154 | // We add on to hide entry 0 which accumulates surviving words for |
tschatzl@6937 | 155 | // age -1 regions (i.e. non-young ones) |
tschatzl@6937 | 156 | return _surviving_young_words; |
tschatzl@6937 | 157 | } |
tschatzl@6937 | 158 | |
tschatzl@6937 | 159 | private: |
tschatzl@6937 | 160 | #define G1_PARTIAL_ARRAY_MASK 0x2 |
tschatzl@6937 | 161 | |
tschatzl@6937 | 162 | inline bool has_partial_array_mask(oop* ref) const { |
tschatzl@6937 | 163 | return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; |
tschatzl@6937 | 164 | } |
tschatzl@6937 | 165 | |
tschatzl@6937 | 166 | // We never encode partial array oops as narrowOop*, so return false immediately. |
tschatzl@6937 | 167 | // This allows the compiler to create optimized code when popping references from |
tschatzl@6937 | 168 | // the work queue. |
tschatzl@6937 | 169 | inline bool has_partial_array_mask(narrowOop* ref) const { |
tschatzl@6937 | 170 | assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); |
tschatzl@6937 | 171 | return false; |
tschatzl@6937 | 172 | } |
tschatzl@6937 | 173 | |
tschatzl@6937 | 174 | // Only implement set_partial_array_mask() for regular oops, not for narrowOops. |
tschatzl@6937 | 175 | // We always encode partial arrays as regular oop, to allow the |
tschatzl@6937 | 176 | // specialization for has_partial_array_mask() for narrowOops above. |
tschatzl@6937 | 177 | // This means that unintentional use of this method with narrowOops are caught |
tschatzl@6937 | 178 | // by the compiler. |
tschatzl@6937 | 179 | inline oop* set_partial_array_mask(oop obj) const { |
tschatzl@6937 | 180 | assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); |
tschatzl@6937 | 181 | return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); |
tschatzl@6937 | 182 | } |
tschatzl@6937 | 183 | |
tschatzl@6937 | 184 | inline oop clear_partial_array_mask(oop* ref) const { |
tschatzl@6937 | 185 | return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); |
tschatzl@6937 | 186 | } |
tschatzl@6937 | 187 | |
tschatzl@6937 | 188 | inline void do_oop_partial_array(oop* p); |
tschatzl@6937 | 189 | |
tschatzl@6937 | 190 | // This method is applied to the fields of the objects that have just been copied. |
tschatzl@6938 | 191 | template <class T> inline void do_oop_evac(T* p, HeapRegion* from); |
tschatzl@6937 | 192 | |
tschatzl@6938 | 193 | template <class T> inline void deal_with_reference(T* ref_to_scan); |
tschatzl@6937 | 194 | |
tschatzl@6938 | 195 | inline void dispatch_reference(StarTask ref); |
tschatzl@6938 | 196 | public: |
tschatzl@6937 | 197 | |
tschatzl@6937 | 198 | oop copy_to_survivor_space(oop const obj); |
tschatzl@6937 | 199 | |
tschatzl@6938 | 200 | void trim_queue(); |
tschatzl@6937 | 201 | |
tschatzl@6938 | 202 | inline void steal_and_trim_queue(RefToScanQueueSet *task_queues); |
tschatzl@6937 | 203 | }; |
tschatzl@6937 | 204 | |
tschatzl@6937 | 205 | #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1PARSCANTHREADSTATE_HPP |