152 } |
150 } |
153 |
151 |
154 template <class T> |
152 template <class T> |
155 inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) { |
153 inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) { |
156 oop obj = oopDesc::load_decode_heap_oop(p); |
154 oop obj = oopDesc::load_decode_heap_oop(p); |
|
155 if (obj == NULL) { |
|
156 return; |
|
157 } |
|
158 |
157 #ifdef ASSERT |
159 #ifdef ASSERT |
158 // can't do because of races |
160 // can't do because of races |
159 // assert(obj == NULL || obj->is_oop(), "expected an oop"); |
161 // assert(obj == NULL || obj->is_oop(), "expected an oop"); |
160 |
162 |
161 // Do the safe subset of is_oop |
163 // Do the safe subset of is_oop |
162 if (obj != NULL) { |
|
163 #ifdef CHECK_UNHANDLED_OOPS |
164 #ifdef CHECK_UNHANDLED_OOPS |
164 oopDesc* o = obj.obj(); |
165 oopDesc* o = obj.obj(); |
165 #else |
166 #else |
166 oopDesc* o = obj; |
167 oopDesc* o = obj; |
167 #endif // CHECK_UNHANDLED_OOPS |
168 #endif // CHECK_UNHANDLED_OOPS |
168 assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); |
169 assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); |
169 assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); |
170 assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); |
170 } |
|
171 #endif // ASSERT |
171 #endif // ASSERT |
172 |
172 |
173 assert(_from != NULL, "from region must be non-NULL"); |
173 assert(_from != NULL, "from region must be non-NULL"); |
174 assert(_from->is_in_reserved(p), "p is not in from"); |
174 assert(_from->is_in_reserved(p), "p is not in from"); |
175 |
175 |
176 HeapRegion* to = _g1->heap_region_containing(obj); |
176 HeapRegion* to = _g1->heap_region_containing(obj); |
177 if (to != NULL && _from != to) { |
177 if (_from == to) { |
178 // The _record_refs_into_cset flag is true during the RSet |
178 // Normally this closure should only be called with cross-region references. |
179 // updating part of an evacuation pause. It is false at all |
179 // But since Java threads are manipulating the references concurrently and we |
180 // other times: |
180 // reload the values things may have changed. |
181 // * rebuilding the remembered sets after a full GC |
181 return; |
182 // * during concurrent refinement. |
182 } |
183 // * updating the remembered sets of regions in the collection |
183 |
184 // set in the event of an evacuation failure (when deferred |
184 // The _record_refs_into_cset flag is true during the RSet |
185 // updates are enabled). |
185 // updating part of an evacuation pause. It is false at all |
186 |
186 // other times: |
187 if (_record_refs_into_cset && to->in_collection_set()) { |
187 // * rebuilding the remembered sets after a full GC |
188 // We are recording references that point into the collection |
188 // * during concurrent refinement. |
189 // set and this particular reference does exactly that... |
189 // * updating the remembered sets of regions in the collection |
190 // If the referenced object has already been forwarded |
190 // set in the event of an evacuation failure (when deferred |
191 // to itself, we are handling an evacuation failure and |
191 // updates are enabled). |
192 // we have already visited/tried to copy this object |
192 |
193 // there is no need to retry. |
193 if (_record_refs_into_cset && to->in_collection_set()) { |
194 if (!self_forwarded(obj)) { |
194 // We are recording references that point into the collection |
195 assert(_push_ref_cl != NULL, "should not be null"); |
195 // set and this particular reference does exactly that... |
196 // Push the reference in the refs queue of the G1ParScanThreadState |
196 // If the referenced object has already been forwarded |
197 // instance for this worker thread. |
197 // to itself, we are handling an evacuation failure and |
198 _push_ref_cl->do_oop(p); |
198 // we have already visited/tried to copy this object |
199 } |
199 // there is no need to retry. |
200 |
200 if (!self_forwarded(obj)) { |
201 // Deferred updates to the CSet are either discarded (in the normal case), |
201 assert(_push_ref_cl != NULL, "should not be null"); |
202 // or processed (if an evacuation failure occurs) at the end |
202 // Push the reference in the refs queue of the G1ParScanThreadState |
203 // of the collection. |
203 // instance for this worker thread. |
204 // See G1RemSet::cleanup_after_oops_into_collection_set_do(). |
204 _push_ref_cl->do_oop(p); |
205 return; |
205 } |
206 } |
206 |
207 |
207 // Deferred updates to the CSet are either discarded (in the normal case), |
|
208 // or processed (if an evacuation failure occurs) at the end |
|
209 // of the collection. |
|
210 // See G1RemSet::cleanup_after_oops_into_collection_set_do(). |
|
211 } else { |
208 // We either don't care about pushing references that point into the |
212 // We either don't care about pushing references that point into the |
209 // collection set (i.e. we're not during an evacuation pause) _or_ |
213 // collection set (i.e. we're not during an evacuation pause) _or_ |
210 // the reference doesn't point into the collection set. Either way |
214 // the reference doesn't point into the collection set. Either way |
211 // we add the reference directly to the RSet of the region containing |
215 // we add the reference directly to the RSet of the region containing |
212 // the referenced object. |
216 // the referenced object. |