src/share/vm/gc_implementation/g1/bufferingOopClosure.hpp
Print this page
rev 5821 : imported patch changeBufferingOopClosures
*** 1,7 ****
/*
! * Copyright (c) 2001, 2010, Oracle and/or its affiliates. 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.
--- 1,7 ----
/*
! * Copyright (c) 2001, 2014, Oracle and/or its affiliates. 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.
*** 23,101 ****
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
! #include "memory/genOopClosures.hpp"
! #include "memory/generation.hpp"
#include "runtime/os.hpp"
! #include "utilities/taskqueue.hpp"
// 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
! };
!
! StarTask _buffer[BufferLength];
! StarTask* _buffer_top;
! StarTask* _buffer_curr;
OopClosure* _oc;
double _closure_app_seconds;
! void process_buffer () {
! double start = os::elapsedTime();
! for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) {
! if (curr->is_narrow()) {
! assert(UseCompressedOops, "Error");
! _oc->do_oop((narrowOop*)(*curr));
! } else {
_oc->do_oop((oop*)(*curr));
}
}
! _buffer_curr = _buffer;
_closure_app_seconds += (os::elapsedTime() - start);
}
! template <class T> inline void do_oop_work(T* p) {
! if (_buffer_curr == _buffer_top) {
process_buffer();
}
! StarTask new_ref(p);
! *_buffer_curr = new_ref;
! ++_buffer_curr;
}
public:
! virtual void do_oop(narrowOop* p) { do_oop_work(p); }
! virtual void do_oop(oop* p) { do_oop_work(p); }
! 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) { }
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
--- 23,139 ----
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
! #include "memory/iterator.hpp"
#include "runtime/os.hpp"
! #include "utilities/debug.hpp"
// 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 entries.
class BufferingOopClosure: public OopClosure {
+ friend class TestBufferingOopClosure;
protected:
! static const size_t BufferLength = 1024;
!
! // The full-sized oops are filled in from the bottom,
! // while the narrowOops are filled in from the top.
! void* _buffer[BufferLength];
! void** _oop_top;
! void** _narrowOop_bottom;
OopClosure* _oc;
double _closure_app_seconds;
!
! bool is_buffer_empty() {
! return _oop_top == _buffer && _narrowOop_bottom == (_buffer + BufferLength - 1);
! }
!
! bool is_buffer_full() {
! return (uintptr_t)_narrowOop_bottom < (uintptr_t)_oop_top;
! }
!
! // Process addresses containing full-sized oops.
! void process_oops() {
! for (void** curr = _buffer; curr < _oop_top; ++curr) {
_oc->do_oop((oop*)(*curr));
}
+ _oop_top = _buffer;
+ }
+
+ // Process addresses containing narrow oops.
+ void process_narrowOops() {
+ for (void** curr = _buffer + BufferLength - 1; curr > _narrowOop_bottom; --curr) {
+ _oc->do_oop((narrowOop*)(*curr));
+ }
+ _narrowOop_bottom = _buffer + BufferLength - 1;
}
!
! // Apply the closure to all oops and clear the buffer.
! // Accumulate the time it took.
! void process_buffer() {
! double start = os::elapsedTime();
!
! process_oops();
! process_narrowOops();
!
_closure_app_seconds += (os::elapsedTime() - start);
}
! void process_buffer_if_full() {
! if (is_buffer_full()) {
process_buffer();
}
! }
!
! void add_narrowOop(narrowOop* p) {
! assert(!is_buffer_full(), "Buffer should not be full");
! *_narrowOop_bottom = (void*)p;
! _narrowOop_bottom--;
! }
!
! void add_oop(oop* p) {
! assert(!is_buffer_full(), "Buffer should not be full");
! *_oop_top = (void*)p;
! _oop_top++;
}
public:
! virtual void do_oop(narrowOop* p) {
! process_buffer_if_full();
! add_narrowOop(p);
! }
!
! virtual void do_oop(oop* p) {
! process_buffer_if_full();
! add_oop(p);
! }
! void done() {
! if (!is_buffer_empty()) {
process_buffer();
}
}
!
! double closure_app_seconds() {
return _closure_app_seconds;
}
!
! BufferingOopClosure(OopClosure *oc) :
_oc(oc),
! _oop_top(_buffer),
! _narrowOop_bottom(_buffer + BufferLength - 1),
_closure_app_seconds(0.0) { }
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP