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

#ifndef SHARE_CDS_ARCHIVEHEAPLOADER_HPP
#define SHARE_CDS_ARCHIVEHEAPLOADER_HPP

#include "gc/shared/gc_globals.hpp"
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "memory/memRegion.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/globals.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/macros.hpp"

class  FileMapInfo;
struct LoadedArchiveHeapRegion;

class ArchiveHeapLoader : AllStatic {
public:
  // At runtime, the heap region in the CDS archive can be used in two different ways,
  // depending on the GC type:
  // - Mapped: (G1 only) the region is directly mapped into the Java heap
  // - Loaded: At VM start-up, the objects in the heap region are copied into the
  //           Java heap. This is easier to implement than mapping but
  //           slightly less efficient, as the embedded pointers need to be relocated.
  static bool can_use() { return can_map() || can_load(); }

  // Can this VM map archived heap region? Currently only G1+compressed{oops,cp}
  static bool can_map() {
    CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);)
    NOT_CDS_JAVA_HEAP(return false;)
  }

  // Can this VM load the objects from archived heap region into the heap at start-up?
  static bool can_load()  NOT_CDS_JAVA_HEAP_RETURN_(false);
  static void finish_initialization() NOT_CDS_JAVA_HEAP_RETURN;
  static bool is_loaded() {
    CDS_JAVA_HEAP_ONLY(return _is_loaded;)
    NOT_CDS_JAVA_HEAP(return false;)
  }

  static bool is_in_use() {
    return is_loaded() || is_mapped();
  }

  static ptrdiff_t mapped_heap_delta() {
    CDS_JAVA_HEAP_ONLY(assert(!is_loaded(), "must be"));
    CDS_JAVA_HEAP_ONLY(assert(_mapped_heap_relocation_initialized, "must be"));
    CDS_JAVA_HEAP_ONLY(return _mapped_heap_delta;)
    NOT_CDS_JAVA_HEAP_RETURN_(0L);
  }

  static void set_mapped() {
    CDS_JAVA_HEAP_ONLY(_is_mapped = true;)
    NOT_CDS_JAVA_HEAP_RETURN;
  }
  static bool is_mapped() {
    CDS_JAVA_HEAP_ONLY(return _is_mapped;)
    NOT_CDS_JAVA_HEAP_RETURN_(false);
  }

  // NarrowOops stored in the CDS archive may use a different encoding scheme
  // than CompressedOops::{base,shift} -- see FileMapInfo::map_heap_region_impl.
  // To decode them, do not use CompressedOops::decode_not_null. Use this
  // function instead.
  inline static oop decode_from_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);

  // More efficient version, but works only when ArchiveHeap is mapped.
  inline static oop decode_from_mapped_archive(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);

  static void patch_compressed_embedded_pointers(BitMapView bm,
                                                 FileMapInfo* info,
                                                 MemRegion region) NOT_CDS_JAVA_HEAP_RETURN;

  static void patch_embedded_pointers(FileMapInfo* info,
                                      MemRegion region, address oopmap,
                                      size_t oopmap_size_in_bits) NOT_CDS_JAVA_HEAP_RETURN;

  static void fixup_region() NOT_CDS_JAVA_HEAP_RETURN;

#if INCLUDE_CDS_JAVA_HEAP
  static void init_mapped_heap_info(address mapped_heap_bottom, ptrdiff_t delta, int dumptime_oop_shift);
private:
  static bool _is_mapped;
  static bool _is_loaded;

  // Support for loaded archived heap. These are cached values from
  // LoadedArchiveHeapRegion's.
  static uintptr_t _dumptime_base;
  static uintptr_t _dumptime_top;
  static intx _runtime_offset;

  static uintptr_t _loaded_heap_bottom;
  static uintptr_t _loaded_heap_top;
  static bool _loading_failed;

  // UseCompressedOops only: Used by decode_from_archive
  static bool    _narrow_oop_base_initialized;
  static address _narrow_oop_base;
  static int     _narrow_oop_shift;

  // is_mapped() only: the mapped address of each region is offset by this amount from
  // their requested address.
  static uintptr_t _mapped_heap_bottom;
  static ptrdiff_t _mapped_heap_delta;
  static bool      _mapped_heap_relocation_initialized;

  static void init_narrow_oop_decoding(address base, int shift);
  static bool init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region,
                                 MemRegion& archive_space);
  static bool load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region, uintptr_t buffer);
  static void init_loaded_heap_relocation(LoadedArchiveHeapRegion* reloc_info);
  static void patch_native_pointers();
  static void finish_loaded_heap();
  static void verify_loaded_heap();
  static void fill_failed_loaded_heap();

  static bool is_in_loaded_heap(uintptr_t o) {
    return (_loaded_heap_bottom <= o && o < _loaded_heap_top);
  }

  template<bool IS_MAPPED>
  inline static oop decode_from_archive_impl(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);

  class PatchLoadedRegionPointers;
  class PatchUncompressedLoadedRegionPointers;

public:

  static bool load_heap_region(FileMapInfo* mapinfo);
  static void assert_in_loaded_heap(uintptr_t o) {
    assert(is_in_loaded_heap(o), "must be");
  }
#endif // INCLUDE_CDS_JAVA_HEAP

};

#endif // SHARE_CDS_ARCHIVEHEAPLOADER_HPP
