/*
 * Copyright (c) 2021, 2023, 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.
 */

#include "precompiled.hpp"
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zBitMap.inline.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zPage.inline.hpp"
#include "gc/z/zRememberedSet.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
#include "utilities/globalDefinitions.hpp"

int ZRememberedSet::_current = 0;

void ZRememberedSet::flip() {
  _current ^= 1;
}

ZRememberedSet::ZRememberedSet()
  : _bitmap{ZMovableBitMap(), ZMovableBitMap()} {
  // Defer initialization of the bitmaps until the owning
  // page becomes old and its remembered set is initialized.
}

bool ZRememberedSet::is_initialized() const {
  return _bitmap[0].size() > 0;
}

void ZRememberedSet::initialize(size_t page_size) {
  assert(!is_initialized(), "precondition");
  const BitMap::idx_t size_in_bits = to_bit_size(page_size);
  _bitmap[0].initialize(size_in_bits, true /* clear */);
  _bitmap[1].initialize(size_in_bits, true /* clear */);
}

void ZRememberedSet::resize(size_t page_size) {
  // The bitmaps only need to be resized if remset has been
  // initialized, and hence the bitmaps have been initialized.
  if (is_initialized()) {
    const BitMap::idx_t size_in_bits = to_bit_size(page_size);

    // The bitmaps need to be cleared when free, but since this function is
    // only used for shrinking the clear argument is correct but not crucial.
    assert(size_in_bits <= _bitmap[0].size(), "Only used for shrinking");
    _bitmap[0].resize(size_in_bits, true /* clear */);
    _bitmap[1].resize(size_in_bits, true /* clear */);
  }
}

bool ZRememberedSet::is_cleared_current() const {
  return current()->is_empty();
}

bool ZRememberedSet::is_cleared_previous() const {
  return previous()->is_empty();
}

void ZRememberedSet::clear_all() {
  clear_current();
  clear_previous();
}

void ZRememberedSet::clear_current() {
  current()->clear_large();
}

void ZRememberedSet::clear_previous() {
  previous()->clear_large();
}

void ZRememberedSet::swap_remset_bitmaps() {
  assert(previous()->is_empty(), "Previous remset bits should be empty when swapping");
  current()->iterate([&](BitMap::idx_t index) {
    previous()->set_bit(index);
    return true;
  });
  current()->clear_large();
}

ZBitMap::ReverseIterator ZRememberedSet::iterator_reverse_previous() {
  return ZBitMap::ReverseIterator(previous());
}

BitMap::Iterator ZRememberedSet::iterator_limited_current(uintptr_t offset, size_t size) {
  const size_t index = to_index(offset);;
  const size_t bit_size = to_bit_size(size);

  return BitMap::Iterator(*current(), index, index + bit_size);
}

ZBitMap::Iterator ZRememberedSet::iterator_limited_previous(uintptr_t offset, size_t size) {
  const size_t index = to_index(offset);;
  const size_t bit_size = to_bit_size(size);

  return BitMap::Iterator(*previous(), index, index + bit_size);
}

size_t ZRememberedSetContainingIterator::to_index(zaddress_unsafe addr) {
  const uintptr_t local_offset = _page->local_offset(addr);
  return ZRememberedSet::to_index(local_offset);
}

zaddress_unsafe ZRememberedSetContainingIterator::to_addr(BitMap::idx_t index) {
  const uintptr_t local_offset = ZRememberedSet::to_offset(index);
  return ZOffset::address_unsafe(_page->global_offset(local_offset));
}

ZRememberedSetContainingIterator::ZRememberedSetContainingIterator(ZPage* page)
  : _page(page),
    _remset_iter(page->remset_reverse_iterator_previous()),
    _obj(zaddress_unsafe::null),
    _obj_remset_iter(page->remset_reverse_iterator_previous()) {}

bool ZRememberedSetContainingIterator::next(ZRememberedSetContaining* containing) {
  // Note: to skip having to read the contents of the heap, when collecting the
  // containing information, this code doesn't read the size of the objects and
  // therefore doesn't filter out remset bits that belong to dead objects.
  // The (addr, addr_field) pair will contain the nearest live object, of a
  // given remset bit. Users of 'containing' need to do the filtering.

  BitMap::idx_t index;

  if (!is_null(_obj)) {
    // We've already found a remset bit and likely owning object in the main
    // iterator. Now use that information to skip having to search for the
    // same object multiple times.

    if (_obj_remset_iter.next(&index)) {
      containing->_field_addr = to_addr(index);
      containing->_addr = _obj;

      log_develop_trace(gc, remset)("Remset Containing Obj  index: " PTR_FORMAT " base: " PTR_FORMAT " field: " PTR_FORMAT, index, untype(containing->_addr), untype(containing->_field_addr));

      return true;
    } else {
      // No more remset bits in the scanned object
      _obj = zaddress_unsafe::null;
    }
  }

  // At this point, we don't know where the nearest earlier object starts.
  // Search for the next earlier remset bit, and then search for the likely
  // owning object.
  if (_remset_iter.next(&index)) {
    containing->_field_addr = to_addr(index);
    containing->_addr = _page->find_base((volatile zpointer*)untype(containing->_field_addr));

    if (is_null(containing->_addr)) {
      // Found no live object
      return false;
    }

    // Found live object. Not necessarily the one that originally owned the remset bit.
    const BitMap::idx_t obj_index = to_index(containing->_addr);

    log_develop_trace(gc, remset)("Remset Containing Main index: " PTR_FORMAT " base: " PTR_FORMAT " field: " PTR_FORMAT, index, untype(containing->_addr), untype(containing->_field_addr));

    // Don't scan inside the object in the main iterator
    _remset_iter.reset(obj_index);

    // Scan inside the object iterator
    _obj = containing->_addr;
    _obj_remset_iter.reset(obj_index, index);

    return true;
  }

  return false;
}

ZRememberedSetContainingInLiveIterator::ZRememberedSetContainingInLiveIterator(ZPage* page)
  : _iter(page),
    _addr(zaddress::null),
    _addr_size(0),
    _count(0),
    _count_skipped(0),
    _page(page) {}

bool ZRememberedSetContainingInLiveIterator::next(ZRememberedSetContaining* containing) {
  ZRememberedSetContaining local;
  while (_iter.next(&local)) {
    const zaddress local_addr = safe(local._addr);
    if (local_addr != _addr) {
      _addr = local_addr;
      _addr_size = ZUtils::object_size(_addr);
    }

    const size_t field_offset = safe(local._field_addr) - _addr;
    if (field_offset < _addr_size) {
      *containing = local;
      _count++;
      return true;
    }

    // Skip field outside object
    _count_skipped++;
  }

  // No more entries found
  return false;
}

void ZRememberedSetContainingInLiveIterator::print_statistics() const {
  _page->log_msg(" (remembered iter count: " SIZE_FORMAT " skipped: " SIZE_FORMAT ")", _count, _count_skipped);
}
