/*
 * Copyright (c) 2017, 2025, 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 "classfile/classLoaderData.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/gc_globals.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zCollectedHeap.hpp"
#include "gc/z/zGenerationId.hpp"
#include "gc/z/zGlobals.hpp"
#include "gc/z/zGranuleMap.inline.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zHeapIterator.hpp"
#include "gc/z/zLock.inline.hpp"
#include "gc/z/zNMethod.hpp"
#include "memory/iterator.inline.hpp"
#include "utilities/bitMap.inline.hpp"

class ZHeapIteratorBitMap : public CHeapObj<mtGC> {
private:
  CHeapBitMap _bitmap;

public:
  ZHeapIteratorBitMap(size_t size_in_bits)
    : _bitmap(size_in_bits, mtGC) {}

  bool try_set_bit(size_t index) {
    return _bitmap.par_set_bit(index);
  }
};

class ZHeapIteratorContext {
private:
  ObjectClosure* const                _object_cl;
  OopFieldClosure* const              _field_cl;
  const uint                          _worker_id;
  ZHeapIteratorQueue* const           _queue;
  ZHeapIteratorArrayChunkQueue* const _array_chunk_queue;

public:
  ZHeapIteratorContext(ObjectClosure* object_cl,
                       OopFieldClosure* field_cl,
                       uint worker_id,
                       ZHeapIteratorQueue* queue,
                       ZHeapIteratorArrayChunkQueue* array_chunk_queue)
    : _object_cl(object_cl),
      _field_cl(field_cl),
      _worker_id(worker_id),
      _queue(queue),
      _array_chunk_queue(array_chunk_queue) {}

  uint worker_id() const {
    return _worker_id;
  }

  void visit_field(oop base, oop* p) const {
    if (_field_cl != nullptr) {
      _field_cl->do_field(base, p);
    }
  }

  void visit_object(oop obj) const {
    _object_cl->do_object(obj);
  }

  void push(oop obj) const {
    _queue->push(obj);
  }

  void push_array_chunk(const ObjArrayTask& array_chunk) const {
    _array_chunk_queue->push(array_chunk);
  }

  bool pop(oop& obj) const {
    return _queue->pop_overflow(obj) || _queue->pop_local(obj);
  }

  bool pop_array_chunk(ObjArrayTask& array_chunk) const {
    return _array_chunk_queue->pop_overflow(array_chunk) || _array_chunk_queue->pop_local(array_chunk);
  }

  bool is_drained() const {
    return _queue->is_empty() && _array_chunk_queue->is_empty();
  }
};

template <bool Weak>
class ZHeapIteratorColoredRootOopClosure : public OopClosure {
private:
  ZHeapIterator* const        _iter;
  const ZHeapIteratorContext& _context;

  oop load_oop(oop* p) {
    if (Weak) {
      return NativeAccess<AS_NO_KEEPALIVE | ON_PHANTOM_OOP_REF>::oop_load(p);
    }

    return NativeAccess<AS_NO_KEEPALIVE>::oop_load(p);
  }

public:
  ZHeapIteratorColoredRootOopClosure(ZHeapIterator* iter,
                                     const ZHeapIteratorContext& context)
    : _iter(iter),
      _context(context) {}

  virtual void do_oop(oop* p) {
    _context.visit_field(nullptr, p);
    const oop obj = load_oop(p);
    _iter->mark_visit_and_push(_context, obj);
  }

  virtual void do_oop(narrowOop* p) {
    ShouldNotReachHere();
  }
};

class ZHeapIteratorUncoloredRootOopClosure : public OopClosure {
private:
  ZHeapIterator* const        _iter;
  const ZHeapIteratorContext& _context;

  oop load_oop(oop* p) {
    const oop o = Atomic::load(p);
    check_is_valid_zaddress(o);
    return RawAccess<>::oop_load(p);
  }

public:
  ZHeapIteratorUncoloredRootOopClosure(ZHeapIterator* iter,
                                       const ZHeapIteratorContext& context)
    : _iter(iter),
      _context(context) {}

  virtual void do_oop(oop* p) {
    _context.visit_field(nullptr, p);
    const oop obj = load_oop(p);
    _iter->mark_visit_and_push(_context, obj);
  }

  virtual void do_oop(narrowOop* p) {
    ShouldNotReachHere();
  }
};

class ZHeapIteratorCLDOopClosure : public OopClosure {
private:
  ZHeapIterator* const        _iter;
  const ZHeapIteratorContext& _context;

  oop load_oop(oop* p) {
    assert(!ZCollectedHeap::heap()->is_in(p), "Should not be in heap");
    return NativeAccess<AS_NO_KEEPALIVE>::oop_load(p);
  }

public:
  ZHeapIteratorCLDOopClosure(ZHeapIterator* iter,
                             const ZHeapIteratorContext& context)
    : _iter(iter),
      _context(context) {}

  virtual void do_oop(oop* p) {
    const oop obj = load_oop(p);
    _iter->mark_visit_and_push(_context, obj);
  }

  virtual void do_oop(narrowOop* p) {
    ShouldNotReachHere();
  }
};

template <bool VisitReferents>
class ZHeapIteratorOopClosure : public OopIterateClosure {
private:
  ZHeapIterator* const        _iter;
  const ZHeapIteratorContext& _context;
  const oop                   _base;

  oop load_oop(oop* p) {
    assert(ZCollectedHeap::heap()->is_in(p), "Should be in heap");

    if (VisitReferents) {
      return HeapAccess<AS_NO_KEEPALIVE | ON_UNKNOWN_OOP_REF>::oop_load_at(_base, (ptrdiff_t)_base->field_offset(p));
    }

    return HeapAccess<AS_NO_KEEPALIVE>::oop_load(p);
  }

public:
  ZHeapIteratorOopClosure(ZHeapIterator* iter,
                          const ZHeapIteratorContext& context,
                          oop base)
    : OopIterateClosure(),
      _iter(iter),
      _context(context),
      _base(base) {}

  virtual ReferenceIterationMode reference_iteration_mode() {
    return VisitReferents ? DO_FIELDS : DO_FIELDS_EXCEPT_REFERENT;
  }

  virtual void do_oop(oop* p) {
    _context.visit_field(_base, p);
    const oop obj = load_oop(p);
    _iter->mark_visit_and_push(_context, obj);
  }

  virtual void do_oop(narrowOop* p) {
    ShouldNotReachHere();
  }

  virtual bool do_metadata() {
    return true;
  }

  virtual void do_klass(Klass* k) {
    ClassLoaderData* const cld = k->class_loader_data();
    ZHeapIteratorOopClosure::do_cld(cld);
  }

  virtual void do_cld(ClassLoaderData* cld) {
    ZHeapIteratorCLDOopClosure cl(_iter, _context);
    cld->oops_do(&cl, ClassLoaderData::_claim_other);
  }

  // Don't follow loom stack metadata; it's already followed in other ways through CLDs
  virtual void do_nmethod(nmethod* nm) {}
  virtual void do_method(Method* m) {}
};

ZHeapIterator::ZHeapIterator(uint nworkers,
                             bool visit_weaks,
                             bool for_verify)
  : _visit_weaks(visit_weaks),
    _for_verify(for_verify),
    _bitmaps(ZAddressOffsetMax),
    _bitmaps_lock(),
    _queues(nworkers),
    _array_chunk_queues(nworkers),
    _roots_colored(ZGenerationIdOptional::none),
    _roots_uncolored(ZGenerationIdOptional::none),
    _roots_weak_colored(ZGenerationIdOptional::none),
    _terminator(nworkers, &_queues) {

  // Create queues
  for (uint i = 0; i < _queues.size(); i++) {
    ZHeapIteratorQueue* const queue = new ZHeapIteratorQueue();
    _queues.register_queue(i, queue);
  }

  // Create array chunk queues
  for (uint i = 0; i < _array_chunk_queues.size(); i++) {
    ZHeapIteratorArrayChunkQueue* const array_chunk_queue = new ZHeapIteratorArrayChunkQueue();
    _array_chunk_queues.register_queue(i, array_chunk_queue);
  }
}

ZHeapIterator::~ZHeapIterator() {
  // Destroy bitmaps
  ZHeapIteratorBitMapsIterator iter(&_bitmaps);
  for (ZHeapIteratorBitMap* bitmap; iter.next(&bitmap);) {
    delete bitmap;
  }

  // Destroy array chunk queues
  for (uint i = 0; i < _array_chunk_queues.size(); i++) {
    delete _array_chunk_queues.queue(i);
  }

  // Destroy queues
  for (uint i = 0; i < _queues.size(); i++) {
    delete _queues.queue(i);
  }

  // Clear claimed CLD bits
  ClassLoaderDataGraph::clear_claimed_marks(ClassLoaderData::_claim_other);
}

static size_t object_index_max() {
  return ZGranuleSize >> ZObjectAlignmentSmallShift;
}

static size_t object_index(oop obj) {
  const zaddress addr = to_zaddress(obj);
  const zoffset offset = ZAddress::offset(addr);
  const uintptr_t mask = ZGranuleSize - 1;
  return (untype(offset) & mask) >> ZObjectAlignmentSmallShift;
}

ZHeapIteratorBitMap* ZHeapIterator::object_bitmap(oop obj) {
  const zoffset offset = ZAddress::offset(to_zaddress(obj));
  ZHeapIteratorBitMap* bitmap = _bitmaps.get_acquire(offset);
  if (bitmap == nullptr) {
    ZLocker<ZLock> locker(&_bitmaps_lock);
    bitmap = _bitmaps.get(offset);
    if (bitmap == nullptr) {
      // Install new bitmap
      bitmap = new ZHeapIteratorBitMap(object_index_max());
      _bitmaps.release_put(offset, bitmap);
    }
  }

  return bitmap;
}

bool ZHeapIterator::should_visit_object_at_mark() const {
  // Verify wants to visit objects as soon as they are found.
  return _for_verify;
}

bool ZHeapIterator::should_visit_object_at_follow() const {
  // Non-verify code needs to be careful and visit the objects
  // during the follow stage, where we've completed the root
  // iteration. This prevents lock-ordering problems between
  // the root iterator and the visit closures.
  return !_for_verify;
}

bool ZHeapIterator::mark_object(oop obj) {
  if (obj == nullptr) {
    return false;
  }

  ZHeapIteratorBitMap* const bitmap = object_bitmap(obj);
  const size_t index = object_index(obj);
  return bitmap->try_set_bit(index);
}

typedef ClaimingCLDToOopClosure<ClassLoaderData::_claim_other> ZHeapIteratorCLDClosure;

class ZHeapIteratorNMethodClosure : public NMethodClosure {
private:
  OopClosure* const        _cl;
  BarrierSetNMethod* const _bs_nm;

public:
  ZHeapIteratorNMethodClosure(OopClosure* cl)
    : _cl(cl),
      _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {}

  virtual void do_nmethod(nmethod* nm) {
    // If ClassUnloading is turned off, all nmethods are considered strong,
    // not only those on the call stacks. The heap iteration might happen
    // before the concurrent processign of the code cache, make sure that
    // all nmethods have been processed before visiting the oops.
    _bs_nm->nmethod_entry_barrier(nm);

    ZNMethod::nmethod_oops_do(nm, _cl);
  }
};

class ZHeapIteratorThreadClosure : public ThreadClosure {
private:
  OopClosure* const     _cl;
  NMethodClosure* const _nm_cl;

public:
  ZHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl)
    : _cl(cl),
      _nm_cl(nm_cl) {}

  void do_thread(Thread* thread) {
    thread->oops_do(_cl, _nm_cl);
  }
};

void ZHeapIterator::push_strong_roots(const ZHeapIteratorContext& context) {
  {
    ZHeapIteratorColoredRootOopClosure<false /* Weak */> cl(this, context);
    ZHeapIteratorCLDClosure cld_cl(&cl);

    _roots_colored.apply(&cl,
                         &cld_cl);
  }

  {
    ZHeapIteratorUncoloredRootOopClosure cl(this, context);
    ZHeapIteratorNMethodClosure nm_cl(&cl);
    ZHeapIteratorThreadClosure thread_cl(&cl, &nm_cl);
    _roots_uncolored.apply(&thread_cl,
                           &nm_cl);
  }
}

void ZHeapIterator::push_weak_roots(const ZHeapIteratorContext& context) {
  ZHeapIteratorColoredRootOopClosure<true  /* Weak */> cl(this, context);
  _roots_weak_colored.apply(&cl);
}

template <bool VisitWeaks>
void ZHeapIterator::push_roots(const ZHeapIteratorContext& context) {
  push_strong_roots(context);
  if (VisitWeaks) {
    push_weak_roots(context);
  }
}

void ZHeapIterator::mark_visit_and_push(const ZHeapIteratorContext& context, oop obj) {
  if (mark_object(obj)) {
    if (should_visit_object_at_mark()) {
      context.visit_object(obj);
    }
    context.push(obj);
  }
}

template <bool VisitReferents>
void ZHeapIterator::follow_object(const ZHeapIteratorContext& context, oop obj) {
  ZHeapIteratorOopClosure<VisitReferents> cl(this, context, obj);
  ZIterator::oop_iterate(obj, &cl);
}

void ZHeapIterator::follow_array(const ZHeapIteratorContext& context, oop obj) {
  // Follow klass
  ZHeapIteratorOopClosure<false /* VisitReferents */> cl(this, context, obj);
  cl.do_klass(obj->klass());

  // Push array chunk
  context.push_array_chunk(ObjArrayTask(obj, 0 /* index */));
}

void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, const ObjArrayTask& array) {
  const objArrayOop obj = objArrayOop(array.obj());
  const int length = obj->length();
  const int start = array.index();
  const int stride = MIN2<int>(length - start, (int)ObjArrayMarkingStride);
  const int end = start + stride;

  // Push remaining array chunk first
  if (end < length) {
    context.push_array_chunk(ObjArrayTask(obj, end));
  }

  // Follow array chunk
  ZHeapIteratorOopClosure<false /* VisitReferents */> cl(this, context, obj);
  ZIterator::oop_iterate_range(obj, &cl, start, end);
}

template <bool VisitWeaks>
void ZHeapIterator::follow(const ZHeapIteratorContext& context, oop obj) {
  // Follow
  if (obj->is_objArray()) {
    follow_array(context, obj);
  } else {
    follow_object<VisitWeaks>(context, obj);
  }
}

template <bool VisitWeaks>
void ZHeapIterator::visit_and_follow(const ZHeapIteratorContext& context, oop obj) {
  if (should_visit_object_at_follow()) {
    context.visit_object(obj);
  }

  follow<VisitWeaks>(context, obj);
}

template <bool VisitWeaks>
void ZHeapIterator::drain(const ZHeapIteratorContext& context) {
  ObjArrayTask array;
  oop obj;

  do {
    while (context.pop(obj)) {
      visit_and_follow<VisitWeaks>(context, obj);
    }

    if (context.pop_array_chunk(array)) {
      follow_array_chunk(context, array);
    }
  } while (!context.is_drained());
}

template <bool VisitWeaks>
void ZHeapIterator::steal(const ZHeapIteratorContext& context) {
  ObjArrayTask array;
  oop obj;

  if (steal_array_chunk(context, array)) {
    follow_array_chunk(context, array);
  } else if (steal(context, obj)) {
    visit_and_follow<VisitWeaks>(context, obj);
  }
}

bool ZHeapIterator::steal(const ZHeapIteratorContext& context, oop& obj) {
  return _queues.steal(context.worker_id(), obj);
}

bool ZHeapIterator::steal_array_chunk(const ZHeapIteratorContext& context, ObjArrayTask& array) {
  return _array_chunk_queues.steal(context.worker_id(), array);
}

template <bool VisitWeaks>
void ZHeapIterator::drain_and_steal(const ZHeapIteratorContext& context) {
  do {
    drain<VisitWeaks>(context);
    steal<VisitWeaks>(context);
  } while (!context.is_drained() || !_terminator.offer_termination());
}

template <bool VisitWeaks>
void ZHeapIterator::object_iterate_inner(const ZHeapIteratorContext& context) {
  push_roots<VisitWeaks>(context);
  drain_and_steal<VisitWeaks>(context);
}

void ZHeapIterator::object_iterate(ObjectClosure* object_cl, uint worker_id) {
  object_and_field_iterate(object_cl, nullptr /* field_cl */, worker_id);
}

void ZHeapIterator::object_and_field_iterate(ObjectClosure* object_cl, OopFieldClosure* field_cl, uint worker_id) {
  const ZHeapIteratorContext context(object_cl,
                                     field_cl,
                                     worker_id,
                                     _queues.queue(worker_id),
                                     _array_chunk_queues.queue(worker_id));

  if (_visit_weaks) {
    object_iterate_inner<true /* VisitWeaks */>(context);
  } else {
    object_iterate_inner<false /* VisitWeaks */>(context);
  }
}
