--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp Thu Jun 05 15:57:56 2008 -0700
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// A BufferingOops closure tries to separate out the cost of finding roots
+// from the cost of applying closures to them. It maintains an array of
+// ref-containing locations. Until the array is full, applying the closure
+// to an oop* merely records that location in the array. Since this
+// closure app cost is small, an elapsed timer can approximately attribute
+// all of this cost to the cost of finding the roots. When the array fills
+// up, the wrapped closure is applied to all elements, keeping track of
+// this elapsed time of this process, and leaving the array empty.
+// The caller must be sure to call "done" to process any unprocessed
+// buffered entriess.
+
+class Generation;
+class HeapRegion;
+
+class BufferingOopClosure: public OopClosure {
+protected:
+ enum PrivateConstants {
+ BufferLength = 1024
+ };
+
+ oop *_buffer[BufferLength];
+ oop **_buffer_top;
+ oop **_buffer_curr;
+
+ OopClosure *_oc;
+ double _closure_app_seconds;
+
+ void process_buffer () {
+
+ double start = os::elapsedTime();
+ for (oop **curr = _buffer; curr < _buffer_curr; ++curr) {
+ _oc->do_oop(*curr);
+ }
+ _buffer_curr = _buffer;
+ _closure_app_seconds += (os::elapsedTime() - start);
+ }
+
+public:
+ virtual void do_oop(narrowOop* p) {
+ guarantee(false, "NYI");
+ }
+ virtual void do_oop(oop *p) {
+ if (_buffer_curr == _buffer_top) {
+ process_buffer();
+ }
+
+ *_buffer_curr = p;
+ ++_buffer_curr;
+ }
+ void done () {
+ if (_buffer_curr > _buffer) {
+ process_buffer();
+ }
+ }
+ double closure_app_seconds () {
+ return _closure_app_seconds;
+ }
+ BufferingOopClosure (OopClosure *oc) :
+ _oc(oc),
+ _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
+ _closure_app_seconds(0.0) { }
+};
+
+class BufferingOopsInGenClosure: public OopsInGenClosure {
+ BufferingOopClosure _boc;
+ OopsInGenClosure* _oc;
+public:
+ BufferingOopsInGenClosure(OopsInGenClosure *oc) :
+ _boc(oc), _oc(oc) {}
+
+ virtual void do_oop(narrowOop* p) {
+ guarantee(false, "NYI");
+ }
+
+ virtual void do_oop(oop* p) {
+ assert(generation()->is_in_reserved(p), "Must be in!");
+ _boc.do_oop(p);
+ }
+
+ void done() {
+ _boc.done();
+ }
+
+ double closure_app_seconds () {
+ return _boc.closure_app_seconds();
+ }
+
+ void set_generation(Generation* gen) {
+ OopsInGenClosure::set_generation(gen);
+ _oc->set_generation(gen);
+ }
+
+ void reset_generation() {
+ // Make sure we finish the current work with the current generation.
+ _boc.done();
+ OopsInGenClosure::reset_generation();
+ _oc->reset_generation();
+ }
+
+};
+
+
+class BufferingOopsInHeapRegionClosure: public OopsInHeapRegionClosure {
+private:
+ enum PrivateConstants {
+ BufferLength = 1024
+ };
+
+ oop *_buffer[BufferLength];
+ oop **_buffer_top;
+ oop **_buffer_curr;
+
+ HeapRegion *_hr_buffer[BufferLength];
+ HeapRegion **_hr_curr;
+
+ OopsInHeapRegionClosure *_oc;
+ double _closure_app_seconds;
+
+ void process_buffer () {
+
+ assert((_hr_curr - _hr_buffer) == (_buffer_curr - _buffer),
+ "the two lengths should be the same");
+
+ double start = os::elapsedTime();
+ HeapRegion **hr_curr = _hr_buffer;
+ HeapRegion *hr_prev = NULL;
+ for (oop **curr = _buffer; curr < _buffer_curr; ++curr) {
+ HeapRegion *region = *hr_curr;
+ if (region != hr_prev) {
+ _oc->set_region(region);
+ hr_prev = region;
+ }
+ _oc->do_oop(*curr);
+ ++hr_curr;
+ }
+ _buffer_curr = _buffer;
+ _hr_curr = _hr_buffer;
+ _closure_app_seconds += (os::elapsedTime() - start);
+ }
+
+public:
+ virtual void do_oop(narrowOop *p) {
+ guarantee(false, "NYI");
+ }
+
+ virtual void do_oop(oop *p) {
+ if (_buffer_curr == _buffer_top) {
+ assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
+ process_buffer();
+ }
+
+ *_buffer_curr = p;
+ ++_buffer_curr;
+ *_hr_curr = _from;
+ ++_hr_curr;
+ }
+ void done () {
+ if (_buffer_curr > _buffer) {
+ assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
+ process_buffer();
+ }
+ }
+ double closure_app_seconds () {
+ return _closure_app_seconds;
+ }
+ BufferingOopsInHeapRegionClosure (OopsInHeapRegionClosure *oc) :
+ _oc(oc),
+ _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
+ _hr_curr(_hr_buffer),
+ _closure_app_seconds(0.0) { }
+};