bufferingOopClosure.hpp revision 8413:92457dfb91bd
1/*
2 * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_VM_GC_G1_BUFFERINGOOPCLOSURE_HPP
26#define SHARE_VM_GC_G1_BUFFERINGOOPCLOSURE_HPP
27
28#include "memory/iterator.hpp"
29#include "oops/oopsHierarchy.hpp"
30#include "runtime/os.hpp"
31#include "utilities/debug.hpp"
32
33// A BufferingOops closure tries to separate out the cost of finding roots
34// from the cost of applying closures to them.  It maintains an array of
35// ref-containing locations.  Until the array is full, applying the closure
36// to an oop* merely records that location in the array.  Since this
37// closure app cost is small, an elapsed timer can approximately attribute
38// all of this cost to the cost of finding the roots.  When the array fills
39// up, the wrapped closure is applied to all elements, keeping track of
40// this elapsed time of this process, and leaving the array empty.
41// The caller must be sure to call "done" to process any unprocessed
42// buffered entries.
43
44class BufferingOopClosure: public OopClosure {
45  friend class TestBufferingOopClosure;
46protected:
47  static const size_t BufferLength = 1024;
48
49  // We need to know if the buffered addresses contain oops or narrowOops.
50  // We can't tag the addresses the way StarTask does, because we need to
51  // be able to handle unaligned addresses coming from oops embedded in code.
52  //
53  // The addresses for the full-sized oops are filled in from the bottom,
54  // while the addresses for the narrowOops are filled in from the top.
55  OopOrNarrowOopStar  _buffer[BufferLength];
56  OopOrNarrowOopStar* _oop_top;
57  OopOrNarrowOopStar* _narrowOop_bottom;
58
59  OopClosure* _oc;
60  double      _closure_app_seconds;
61
62
63  bool is_buffer_empty() {
64    return _oop_top == _buffer && _narrowOop_bottom == (_buffer + BufferLength - 1);
65  }
66
67  bool is_buffer_full() {
68    return _narrowOop_bottom < _oop_top;
69  }
70
71  // Process addresses containing full-sized oops.
72  void process_oops() {
73    for (OopOrNarrowOopStar* curr = _buffer; curr < _oop_top; ++curr) {
74      _oc->do_oop((oop*)(*curr));
75    }
76    _oop_top = _buffer;
77  }
78
79  // Process addresses containing narrow oops.
80  void process_narrowOops() {
81    for (OopOrNarrowOopStar* curr = _buffer + BufferLength - 1; curr > _narrowOop_bottom; --curr) {
82      _oc->do_oop((narrowOop*)(*curr));
83    }
84    _narrowOop_bottom = _buffer + BufferLength - 1;
85  }
86
87  // Apply the closure to all oops and clear the buffer.
88  // Accumulate the time it took.
89  void process_buffer() {
90    double start = os::elapsedTime();
91
92    process_oops();
93    process_narrowOops();
94
95    _closure_app_seconds += (os::elapsedTime() - start);
96  }
97
98  void process_buffer_if_full() {
99    if (is_buffer_full()) {
100      process_buffer();
101    }
102  }
103
104  void add_narrowOop(narrowOop* p) {
105    assert(!is_buffer_full(), "Buffer should not be full");
106    *_narrowOop_bottom = (OopOrNarrowOopStar)p;
107    _narrowOop_bottom--;
108  }
109
110  void add_oop(oop* p) {
111    assert(!is_buffer_full(), "Buffer should not be full");
112    *_oop_top = (OopOrNarrowOopStar)p;
113    _oop_top++;
114  }
115
116public:
117  virtual void do_oop(narrowOop* p) {
118    process_buffer_if_full();
119    add_narrowOop(p);
120  }
121
122  virtual void do_oop(oop* p)       {
123    process_buffer_if_full();
124    add_oop(p);
125  }
126
127  void done() {
128    if (!is_buffer_empty()) {
129      process_buffer();
130    }
131  }
132
133  double closure_app_seconds() {
134    return _closure_app_seconds;
135  }
136
137  BufferingOopClosure(OopClosure *oc) :
138    _oc(oc),
139    _oop_top(_buffer),
140    _narrowOop_bottom(_buffer + BufferLength - 1),
141    _closure_app_seconds(0.0) { }
142};
143
144#endif // SHARE_VM_GC_G1_BUFFERINGOOPCLOSURE_HPP
145