src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp

Thu, 07 Apr 2011 09:53:20 -0700

author
johnc
date
Thu, 07 Apr 2011 09:53:20 -0700
changeset 2781
e1162778c1c8
parent 2314
f95d63e2154a
child 6231
889068b9a088
permissions
-rw-r--r--

7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes

ysr@777 1 /*
stefank@2314 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
stefank@2314 26 #define SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
stefank@2314 27
stefank@2314 28 #include "memory/genOopClosures.hpp"
stefank@2314 29 #include "memory/generation.hpp"
stefank@2314 30 #include "runtime/os.hpp"
stefank@2314 31 #include "utilities/taskqueue.hpp"
stefank@2314 32
ysr@777 33 // A BufferingOops closure tries to separate out the cost of finding roots
ysr@777 34 // from the cost of applying closures to them. It maintains an array of
ysr@777 35 // ref-containing locations. Until the array is full, applying the closure
ysr@777 36 // to an oop* merely records that location in the array. Since this
ysr@777 37 // closure app cost is small, an elapsed timer can approximately attribute
ysr@777 38 // all of this cost to the cost of finding the roots. When the array fills
ysr@777 39 // up, the wrapped closure is applied to all elements, keeping track of
ysr@777 40 // this elapsed time of this process, and leaving the array empty.
ysr@777 41 // The caller must be sure to call "done" to process any unprocessed
ysr@777 42 // buffered entriess.
ysr@777 43
ysr@777 44 class Generation;
ysr@777 45 class HeapRegion;
ysr@777 46
ysr@777 47 class BufferingOopClosure: public OopClosure {
ysr@777 48 protected:
ysr@777 49 enum PrivateConstants {
ysr@777 50 BufferLength = 1024
ysr@777 51 };
ysr@777 52
ysr@1280 53 StarTask _buffer[BufferLength];
ysr@1280 54 StarTask* _buffer_top;
ysr@1280 55 StarTask* _buffer_curr;
ysr@777 56
ysr@1280 57 OopClosure* _oc;
ysr@1280 58 double _closure_app_seconds;
ysr@777 59
ysr@777 60 void process_buffer () {
ysr@777 61 double start = os::elapsedTime();
ysr@1280 62 for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) {
ysr@1280 63 if (curr->is_narrow()) {
ysr@1280 64 assert(UseCompressedOops, "Error");
ysr@1280 65 _oc->do_oop((narrowOop*)(*curr));
ysr@1280 66 } else {
ysr@1280 67 _oc->do_oop((oop*)(*curr));
ysr@1280 68 }
ysr@777 69 }
ysr@777 70 _buffer_curr = _buffer;
ysr@777 71 _closure_app_seconds += (os::elapsedTime() - start);
ysr@777 72 }
ysr@777 73
ysr@1280 74 template <class T> inline void do_oop_work(T* p) {
ysr@777 75 if (_buffer_curr == _buffer_top) {
ysr@777 76 process_buffer();
ysr@777 77 }
ysr@1280 78 StarTask new_ref(p);
ysr@1280 79 *_buffer_curr = new_ref;
ysr@777 80 ++_buffer_curr;
ysr@777 81 }
ysr@1280 82
ysr@1280 83 public:
ysr@1280 84 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
ysr@1280 85 virtual void do_oop(oop* p) { do_oop_work(p); }
ysr@1280 86
ysr@777 87 void done () {
ysr@777 88 if (_buffer_curr > _buffer) {
ysr@777 89 process_buffer();
ysr@777 90 }
ysr@777 91 }
ysr@777 92 double closure_app_seconds () {
ysr@777 93 return _closure_app_seconds;
ysr@777 94 }
ysr@777 95 BufferingOopClosure (OopClosure *oc) :
ysr@777 96 _oc(oc),
ysr@777 97 _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
ysr@777 98 _closure_app_seconds(0.0) { }
ysr@777 99 };
ysr@777 100
ysr@777 101 class BufferingOopsInGenClosure: public OopsInGenClosure {
ysr@777 102 BufferingOopClosure _boc;
ysr@777 103 OopsInGenClosure* _oc;
ysr@1280 104 protected:
ysr@1280 105 template <class T> inline void do_oop_work(T* p) {
ysr@1280 106 assert(generation()->is_in_reserved((void*)p), "Must be in!");
ysr@1280 107 _boc.do_oop(p);
ysr@1280 108 }
ysr@1280 109 public:
ysr@777 110 BufferingOopsInGenClosure(OopsInGenClosure *oc) :
ysr@777 111 _boc(oc), _oc(oc) {}
ysr@777 112
ysr@1280 113 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
ysr@1280 114 virtual void do_oop(oop* p) { do_oop_work(p); }
ysr@777 115
ysr@777 116 void done() {
ysr@777 117 _boc.done();
ysr@777 118 }
ysr@777 119
ysr@777 120 double closure_app_seconds () {
ysr@777 121 return _boc.closure_app_seconds();
ysr@777 122 }
ysr@777 123
ysr@777 124 void set_generation(Generation* gen) {
ysr@777 125 OopsInGenClosure::set_generation(gen);
ysr@777 126 _oc->set_generation(gen);
ysr@777 127 }
ysr@777 128
ysr@777 129 void reset_generation() {
ysr@777 130 // Make sure we finish the current work with the current generation.
ysr@777 131 _boc.done();
ysr@777 132 OopsInGenClosure::reset_generation();
ysr@777 133 _oc->reset_generation();
ysr@777 134 }
ysr@777 135
ysr@777 136 };
ysr@777 137
ysr@777 138
ysr@777 139 class BufferingOopsInHeapRegionClosure: public OopsInHeapRegionClosure {
ysr@777 140 private:
ysr@777 141 enum PrivateConstants {
ysr@777 142 BufferLength = 1024
ysr@777 143 };
ysr@777 144
ysr@1280 145 StarTask _buffer[BufferLength];
ysr@1280 146 StarTask* _buffer_top;
ysr@1280 147 StarTask* _buffer_curr;
ysr@777 148
ysr@1280 149 HeapRegion* _hr_buffer[BufferLength];
ysr@1280 150 HeapRegion** _hr_curr;
ysr@777 151
ysr@1280 152 OopsInHeapRegionClosure* _oc;
ysr@777 153 double _closure_app_seconds;
ysr@777 154
ysr@777 155 void process_buffer () {
ysr@777 156
ysr@777 157 assert((_hr_curr - _hr_buffer) == (_buffer_curr - _buffer),
ysr@777 158 "the two lengths should be the same");
ysr@777 159
ysr@777 160 double start = os::elapsedTime();
ysr@1280 161 HeapRegion** hr_curr = _hr_buffer;
ysr@1280 162 HeapRegion* hr_prev = NULL;
ysr@1280 163 for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) {
ysr@1280 164 HeapRegion* region = *hr_curr;
ysr@777 165 if (region != hr_prev) {
ysr@777 166 _oc->set_region(region);
ysr@777 167 hr_prev = region;
ysr@777 168 }
ysr@1280 169 if (curr->is_narrow()) {
ysr@1280 170 assert(UseCompressedOops, "Error");
ysr@1280 171 _oc->do_oop((narrowOop*)(*curr));
ysr@1280 172 } else {
ysr@1280 173 _oc->do_oop((oop*)(*curr));
ysr@1280 174 }
ysr@777 175 ++hr_curr;
ysr@777 176 }
ysr@777 177 _buffer_curr = _buffer;
ysr@777 178 _hr_curr = _hr_buffer;
ysr@777 179 _closure_app_seconds += (os::elapsedTime() - start);
ysr@777 180 }
ysr@777 181
ysr@777 182 public:
ysr@1280 183 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
ysr@1280 184 virtual void do_oop( oop* p) { do_oop_work(p); }
ysr@777 185
ysr@1280 186 template <class T> void do_oop_work(T* p) {
ysr@777 187 if (_buffer_curr == _buffer_top) {
ysr@777 188 assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
ysr@777 189 process_buffer();
ysr@777 190 }
ysr@1280 191 StarTask new_ref(p);
ysr@1280 192 *_buffer_curr = new_ref;
ysr@777 193 ++_buffer_curr;
ysr@777 194 *_hr_curr = _from;
ysr@777 195 ++_hr_curr;
ysr@777 196 }
ysr@777 197 void done () {
ysr@777 198 if (_buffer_curr > _buffer) {
ysr@777 199 assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
ysr@777 200 process_buffer();
ysr@777 201 }
ysr@777 202 }
ysr@777 203 double closure_app_seconds () {
ysr@777 204 return _closure_app_seconds;
ysr@777 205 }
ysr@777 206 BufferingOopsInHeapRegionClosure (OopsInHeapRegionClosure *oc) :
ysr@777 207 _oc(oc),
ysr@777 208 _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
ysr@777 209 _hr_curr(_hr_buffer),
ysr@777 210 _closure_app_seconds(0.0) { }
ysr@777 211 };
stefank@2314 212
stefank@2314 213 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP

mercurial