/*
 * 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.
 *
 * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP

#include "memory/iterator.hpp"
#include "oops/oopsHierarchy.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 entriess.

class BufferingOopClosure: public OopClosure {
  friend class TestBufferingOopClosure;
protected:
  static const size_t BufferLength = 1024;

  // We need to know if the buffered addresses contain oops or narrowOops.
  // We can't tag the addresses the way StarTask does, because we need to
  // be able to handle unaligned addresses coming from oops embedded in code.
  //
  // The addresses for the full-sized oops are filled in from the bottom,
  // while the addresses for the narrowOops are filled in from the top.
  OopOrNarrowOopStar  _buffer[BufferLength];
  OopOrNarrowOopStar* _oop_top;
  OopOrNarrowOopStar* _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 _narrowOop_bottom < _oop_top;
  }

  // Process addresses containing full-sized oops.
  void process_oops() {
    for (OopOrNarrowOopStar* curr = _buffer; curr < _oop_top; ++curr) {
      _oc->do_oop((oop*)(*curr));
    }
    _oop_top = _buffer;
  }

  // Process addresses containing narrow oops.
  void process_narrowOops() {
    for (OopOrNarrowOopStar* 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 = (OopOrNarrowOopStar)p;
    _narrowOop_bottom--;
  }

  void add_oop(oop* p) {
    assert(!is_buffer_full(), "Buffer should not be full");
    *_oop_top = (OopOrNarrowOopStar)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
