products/sources/formale sprachen/Java/openjdk-20-36_src/src/hotspot/share/cds image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: filemap.cpp   Sprache: C

/*
 * Copyright (c) 2003, 2022, 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 "cds/archiveBuilder.hpp"
#include "cds/archiveHeapLoader.inline.hpp"
#include "cds/archiveUtils.inline.hpp"
#include "cds/cds_globals.hpp"
#include "cds/dynamicArchive.hpp"
#include "cds/filemap.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoader.inline.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "jvm.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "logging/logMessage.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.hpp"
#include "oops/compressedOops.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"
#include "services/memTracker.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/classpathStream.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/ostream.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/heapRegion.hpp"
#endif

include <sys/stat.h>
include <errno.h>

#ifndef O_BINARY       // if defined (Win32) use binary files.
#define O_BINARY 0     // otherwise do nothing.
#endif

// Complain and stop. All error conditions occurring during the writing of
// an archive file should stop the process.  Unrecoverable errors during
// the reading of the archive file should stop the process.

static void fail_exit(const char *msg, va_list ap) {
  // This occurs very early during initialization: tty is not initialized.
  jio_fprintf(defaultStream::error_stream(),
              "An error has occurred while processing the"
              " shared archive file.\n");
  jio_vfprintf(defaultStream::error_stream(), msg, ap);
  jio_fprintf(defaultStream::error_stream(), "\n");
  // Do not change the text of the below message because some tests check for it.
  vm_exit_during_initialization("Unable to use shared archive.", NULL);
}


void FileMapInfo::fail_stop(const char *msg, ...) {
        va_list ap;
  va_start(ap, msg);
  fail_exit(msg, ap);   // Never returns.
  va_end(ap);           // for completeness.
}


// Complain and continue.  Recoverable errors during the reading of the
// archive file may continue (with sharing disabled).
//
// If we continue, then disable shared spaces and close the file.

void FileMapInfo::fail_continue(const char *msg, ...) {
  va_list ap;
  va_start(ap, msg);
  fail_continue_impl(LogLevel::Info, msg, ap);
  va_end(ap);
}

void FileMapInfo::fail_continue(LogLevelType level, const char *msg, ...) {
  va_list ap;
  va_start(ap, msg);
  fail_continue_impl(level, msg, ap);
  va_end(ap);
}

void FileMapInfo::fail_continue_impl(LogLevelType level, const char *msg, va_list ap) {
  if (PrintSharedArchiveAndExit && _validating_shared_path_table) {
    // If we are doing PrintSharedArchiveAndExit and some of the classpath entries
    // do not validate, we can still continue "limping" to validate the remaining
    // entries. No need to quit.
    tty->print("[");
    tty->vprint(msg, ap);
    tty->print_cr("]");
  } else {
    if (RequireSharedSpaces) {
      fail_exit(msg, ap);
    } else {
      LogMessage(cds) lm;
      lm.vwrite(level, msg, ap);
    }
  }
}

// Fill in the fileMapInfo structure with data about this VM instance.

// This method copies the vm version info into header_version.  If the version is too
// long then a truncated version, which has a hash code appended to it, is copied.
//
// Using a template enables this method to verify that header_version is an array of
// length JVM_IDENT_MAX.  This ensures that the code that writes to the CDS file and
// the code that reads the CDS file will both use the same size buffer.  Hence, will
// use identical truncation.  This is necessary for matching of truncated versions.
template <int N> static void get_header_version(char (&header_version) [N]) {
  assert(N == JVM_IDENT_MAX, "Bad header_version size");

  const char *vm_version = VM_Version::internal_vm_info_string();
  const int version_len = (int)strlen(vm_version);

  memset(header_version, 0, JVM_IDENT_MAX);

  if (version_len < (JVM_IDENT_MAX-1)) {
    strcpy(header_version, vm_version);

  } else {
    // Get the hash value.  Use a static seed because the hash needs to return the same
    // value over multiple jvm invocations.
    uint32_t hash = AltHashing::halfsiphash_32(8191, (const uint8_t*)vm_version, version_len);

    // Truncate the ident, saving room for the 8 hex character hash value.
    strncpy(header_version, vm_version, JVM_IDENT_MAX-9);

    // Append the hash code as eight hex digits.
    sprintf(&header_version[JVM_IDENT_MAX-9], "%08x", hash);
    header_version[JVM_IDENT_MAX-1] = 0;  // Null terminate.
  }

  assert(header_version[JVM_IDENT_MAX-1] == 0, "must be");
}

FileMapInfo::FileMapInfo(const char* full_path, bool is_static) :
  _is_static(is_static), _file_open(false), _is_mapped(false), _fd(-1), _file_offset(0),
  _full_path(full_path), _base_archive_name(nullptr), _header(nullptr) {
  if (_is_static) {
    assert(_current_info == NULL, "must be singleton"); // not thread safe
    _current_info = this;
  } else {
    assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
    _dynamic_archive_info = this;
  }
}

FileMapInfo::~FileMapInfo() {
  if (_is_static) {
    assert(_current_info == this"must be singleton"); // not thread safe
    _current_info = NULL;
  } else {
    assert(_dynamic_archive_info == this"must be singleton"); // not thread safe
    _dynamic_archive_info = NULL;
  }

  if (_header != nullptr) {
    os::free(_header);
  }

  if (_file_open) {
    ::close(_fd);
  }
}

void FileMapInfo::populate_header(size_t core_region_alignment) {
  assert(_header == NULL, "Sanity check");
  size_t c_header_size;
  size_t header_size;
  size_t base_archive_name_size = 0;
  size_t base_archive_name_offset = 0;
  size_t longest_common_prefix_size = 0;
  if (is_static()) {
    c_header_size = sizeof(FileMapHeader);
    header_size = c_header_size;
  } else {
    // dynamic header including base archive name for non-default base archive
    c_header_size = sizeof(DynamicArchiveHeader);
    header_size = c_header_size;

    const char* default_base_archive_name = Arguments::get_default_shared_archive_path();
    const char* current_base_archive_name = Arguments::GetSharedArchivePath();
    if (!os::same_files(current_base_archive_name, default_base_archive_name)) {
      base_archive_name_size = strlen(current_base_archive_name) + 1;
      header_size += base_archive_name_size;
      base_archive_name_offset = c_header_size;
    }
    FREE_C_HEAP_ARRAY(const char, default_base_archive_name);
  }
  ResourceMark rm;
  GrowableArray<const char*>* app_cp_array = create_dumptime_app_classpath_array();
  int len = app_cp_array->length();
  longest_common_prefix_size = longest_common_app_classpath_prefix_len(len, app_cp_array);
  _header = (FileMapHeader*)os::malloc(header_size, mtInternal);
  memset((void*)_header, 0, header_size);
  _header->populate(this,
                    core_region_alignment,
                    header_size,
                    base_archive_name_size,
                    base_archive_name_offset,
                    longest_common_prefix_size);
}

void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
                             size_t header_size, size_t base_archive_name_size,
                             size_t base_archive_name_offset, size_t common_app_classpath_prefix_size) {
  // 1. We require _generic_header._magic to be at the beginning of the file
  // 2. FileMapHeader also assumes that _generic_header is at the beginning of the file
  assert(offset_of(FileMapHeader, _generic_header) == 0, "must be");
  set_header_size((unsigned int)header_size);
  set_base_archive_name_offset((unsigned int)base_archive_name_offset);
  set_base_archive_name_size((unsigned int)base_archive_name_size);
  set_common_app_classpath_prefix_size((unsigned int)common_app_classpath_prefix_size);
  set_magic(DynamicDumpSharedSpaces ? CDS_DYNAMIC_ARCHIVE_MAGIC : CDS_ARCHIVE_MAGIC);
  set_version(CURRENT_CDS_ARCHIVE_VERSION);

  if (!info->is_static() && base_archive_name_size != 0) {
    // copy base archive name
    copy_base_archive_name(Arguments::GetSharedArchivePath());
  }
  _core_region_alignment = core_region_alignment;
  _obj_alignment = ObjectAlignmentInBytes;
  _compact_strings = CompactStrings;
  if (DumpSharedSpaces && HeapShared::can_write()) {
    _narrow_oop_mode = CompressedOops::mode();
    _narrow_oop_base = CompressedOops::base();
    _narrow_oop_shift = CompressedOops::shift();
    if (UseCompressedOops) {
      _heap_begin = CompressedOops::begin();
      _heap_end = CompressedOops::end();
    } else {
#if INCLUDE_G1GC
      address start = (address)G1CollectedHeap::heap()->reserved().start();
      address end = (address)G1CollectedHeap::heap()->reserved().end();
      _heap_begin = HeapShared::to_requested_address(start);
      _heap_end = HeapShared::to_requested_address(end);
#endif
    }
  }
  _compressed_oops = UseCompressedOops;
  _compressed_class_ptrs = UseCompressedClassPointers;
  _max_heap_size = MaxHeapSize;
  _narrow_klass_shift = CompressedKlassPointers::shift();
  _use_optimized_module_handling = MetaspaceShared::use_optimized_module_handling();
  _use_full_module_graph = MetaspaceShared::use_full_module_graph();

  // The following fields are for sanity checks for whether this archive
  // will function correctly with this JVM and the bootclasspath it's
  // invoked with.

  // JVM version string ... changes on each build.
  get_header_version(_jvm_ident);

  _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
  _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
  _num_module_paths = ClassLoader::num_module_path_entries();
  _max_used_path_index = ClassLoaderExt::max_used_path_index();

  _verify_local = BytecodeVerificationLocal;
  _verify_remote = BytecodeVerificationRemote;
  _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
  _has_non_jar_in_classpath = ClassLoaderExt::has_non_jar_in_classpath();
  _requested_base_address = (char*)SharedBaseAddress;
  _mapped_base_address = (char*)SharedBaseAddress;
  _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;

  if (!DynamicDumpSharedSpaces) {
    set_shared_path_table(info->_shared_path_table);
  }
}

void FileMapHeader::copy_base_archive_name(const char* archive) {
  assert(base_archive_name_size() != 0, "_base_archive_name_size not set");
  assert(base_archive_name_offset() != 0, "_base_archive_name_offset not set");
  assert(header_size() > sizeof(*this), "_base_archive_name_size not included in header size?");
  memcpy((char*)this + base_archive_name_offset(), archive, base_archive_name_size());
}

void FileMapHeader::print(outputStream* st) {
  ResourceMark rm;

  st->print_cr("- magic: 0x%08x", magic());
  st->print_cr("- crc: 0x%08x", crc());
  st->print_cr("- version: 0x%x", version());
  st->print_cr("- header_size: " UINT32_FORMAT, header_size());
  st->print_cr("- common_app_classpath_size: " UINT32_FORMAT, common_app_classpath_prefix_size());
  st->print_cr("- base_archive_name_offset: " UINT32_FORMAT, base_archive_name_offset());
  st->print_cr("- base_archive_name_size: " UINT32_FORMAT, base_archive_name_size());

  for (int i = 0; i < NUM_CDS_REGIONS; i++) {
    FileMapRegion* r = region_at(i);
    r->print(st, i);
  }
  st->print_cr("============ end regions ======== ");

  st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment);
  st->print_cr("- obj_alignment: %d", _obj_alignment);
  st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
  st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
  st->print_cr("- narrow_oop_shift %d", _narrow_oop_shift);
  st->print_cr("- compact_strings: %d", _compact_strings);
  st->print_cr("- max_heap_size: " UINTX_FORMAT, _max_heap_size);
  st->print_cr("- narrow_oop_mode: %d", _narrow_oop_mode);
  st->print_cr("- narrow_klass_shift: %d", _narrow_klass_shift);
  st->print_cr("- compressed_oops: %d", _compressed_oops);
  st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs);
  st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_X, _cloned_vtables_offset);
  st->print_cr("- serialized_data_offset: " SIZE_FORMAT_X, _serialized_data_offset);
  st->print_cr("- heap_begin: " INTPTR_FORMAT, p2i(_heap_begin));
  st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
  st->print_cr("- jvm_ident: %s", _jvm_ident);
  st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset);
  st->print_cr("- shared_path_table_size: %d", _shared_path_table_size);
  st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index);
  st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index);
  st->print_cr("- num_module_paths: %d", _num_module_paths);
  st->print_cr("- max_used_path_index: %d", _max_used_path_index);
  st->print_cr("- verify_local: %d", _verify_local);
  st->print_cr("- verify_remote: %d", _verify_remote);
  st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes);
  st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath);
  st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
  st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
  st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
  st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
  st->print_cr("- use_full_module_graph %d", _use_full_module_graph);
  st->print_cr("- ptrmap_size_in_bits: " SIZE_FORMAT, _ptrmap_size_in_bits);
}

void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
  _type = non_existent_entry;
  set_name(path, CHECK);
}

void SharedClassPathEntry::init(bool is_modules_image,
                                bool is_module_path,
                                ClassPathEntry* cpe, TRAPS) {
  Arguments::assert_is_dumping_archive();
  _timestamp = 0;
  _filesize  = 0;
  _from_class_path_attr = false;

  struct stat st;
  if (os::stat(cpe->name(), &st) == 0) {
    if ((st.st_mode & S_IFMT) == S_IFDIR) {
      _type = dir_entry;
    } else {
      // The timestamp of the modules_image is not checked at runtime.
      if (is_modules_image) {
        _type = modules_image_entry;
      } else {
        _type = jar_entry;
        _timestamp = st.st_mtime;
        _from_class_path_attr = cpe->from_class_path_attr();
      }
      _filesize = st.st_size;
      _is_module_path = is_module_path;
    }
  } else {
    // The file/dir must exist, or it would not have been added
    // into ClassLoader::classpath_entry().
    //
    // If we can't access a jar file in the boot path, then we can't
    // make assumptions about where classes get loaded from.
    FileMapInfo::fail_stop("Unable to open file %s.", cpe->name());
  }

  // No need to save the name of the module file, as it will be computed at run time
  // to allow relocation of the JDK directory.
  const char* name = is_modules_image  ? "" : cpe->name();
  set_name(name, CHECK);
}

void SharedClassPathEntry::set_name(const char* name, TRAPS) {
  size_t len = strlen(name) + 1;
  _name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, CHECK);
  strcpy(_name->data(), name);
}

void SharedClassPathEntry::copy_from(SharedClassPathEntry* ent, ClassLoaderData* loader_data, TRAPS) {
  _type = ent->_type;
  _is_module_path = ent->_is_module_path;
  _timestamp = ent->_timestamp;
  _filesize = ent->_filesize;
  _from_class_path_attr = ent->_from_class_path_attr;
  set_name(ent->name(), CHECK);

  if (ent->is_jar() && !ent->is_signed() && ent->manifest() != NULL) {
    Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
                                                    ent->manifest_size(),
                                                    CHECK);
    char* p = (char*)(buf->data());
    memcpy(p, ent->manifest(), ent->manifest_size());
    set_manifest(buf);
  }
}

const char* SharedClassPathEntry::name() const {
  if (UseSharedSpaces && is_modules_image()) {
    // In order to validate the runtime modules image file size against the archived
    // size information, we need to obtain the runtime modules image path. The recorded
    // dump time modules image path in the archive may be different from the runtime path
    // if the JDK image has beed moved after generating the archive.
    return ClassLoader::get_jrt_entry()->name();
  } else {
    return _name->data();
  }
}

bool SharedClassPathEntry::validate(bool is_class_path) const {
  assert(UseSharedSpaces, "runtime only");

  struct stat st;
  const char* name = this->name();

  bool ok = true;
  log_info(class, path)("checking shared classpath entry: %s", name);
  if (os::stat(name, &st) != 0 && is_class_path) {
    // If the archived module path entry does not exist at runtime, it is not fatal
    // (no need to invalid the shared archive) because the shared runtime visibility check
    // filters out any archived module classes that do not have a matching runtime
    // module path location.
    FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name);
    ok = false;
  } else if (is_dir()) {
    if (!os::dir_is_empty(name)) {
      FileMapInfo::fail_continue("directory is not empty: %s", name);
      ok = false;
    }
  } else if ((has_timestamp() && _timestamp != st.st_mtime) ||
             _filesize != st.st_size) {
    ok = false;
    if (PrintSharedArchiveAndExit) {
      FileMapInfo::fail_continue(_timestamp != st.st_mtime ?
                                 "Timestamp mismatch" :
                                 "File size mismatch");
    } else {
      const char* bad_jar_msg = "A jar file is not the one used while building the shared archive file:";
      FileMapInfo::fail_continue("%s %s", bad_jar_msg, name);
      if (!log_is_enabled(Info, cds)) {
        log_warning(cds)("%s %s", bad_jar_msg, name);
      }
      if (_timestamp != st.st_mtime) {
        log_warning(cds)("%s timestamp has changed.", name);
      } else {
        log_warning(cds)("%s size has changed.", name);
      }
    }
  }

  if (PrintSharedArchiveAndExit && !ok) {
    // If PrintSharedArchiveAndExit is enabled, don't report failure to the
    // caller. Please see above comments for more details.
    ok = true;
    MetaspaceShared::set_archive_loading_failed();
  }
  return ok;
}

bool SharedClassPathEntry::check_non_existent() const {
  assert(_type == non_existent_entry, "must be");
  log_info(class, path)("should be non-existent: %s", name());
  struct stat st;
  if (os::stat(name(), &st) != 0) {
    log_info(class, path)("ok");
    return true// file doesn't exist
  } else {
    return false;
  }
}


void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
  it->push(&_name);
  it->push(&_manifest);
}

void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
  it->push(&_table);
  for (int i=0; i<_size; i++) {
    path_at(i)->metaspace_pointers_do(it);
  }
}

void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) {
  size_t entry_size = sizeof(SharedClassPathEntry);
  int num_entries = 0;
  num_entries += ClassLoader::num_boot_classpath_entries();
  num_entries += ClassLoader::num_app_classpath_entries();
  num_entries += ClassLoader::num_module_path_entries();
  num_entries += FileMapInfo::num_non_existent_class_paths();
  size_t bytes = entry_size * num_entries;

  _table = MetadataFactory::new_array<u8>(loader_data, (int)bytes, CHECK);
  _size = num_entries;
}

// Make a copy of the _shared_path_table for use during dynamic CDS dump.
// It is needed because some Java code continues to execute after dynamic dump has finished.
// However, during dynamic dump, we have modified FileMapInfo::_shared_path_table so
// FileMapInfo::shared_path(i) returns incorrect information in ClassLoader::record_result().
void FileMapInfo::copy_shared_path_table(ClassLoaderData* loader_data, TRAPS) {
  size_t entry_size = sizeof(SharedClassPathEntry);
  size_t bytes = entry_size * _shared_path_table.size();

  Array<u8>* array = MetadataFactory::new_array<u8>(loader_data, (int)bytes, CHECK);
  _saved_shared_path_table = SharedPathTable(array, _shared_path_table.size());

  for (int i = 0; i < _shared_path_table.size(); i++) {
    _saved_shared_path_table.path_at(i)->copy_from(shared_path(i), loader_data, CHECK);
  }
  _saved_shared_path_table_array = array;
}

void FileMapInfo::clone_shared_path_table(TRAPS) {
  Arguments::assert_is_dumping_archive();

  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
  ClassPathEntry* jrt = ClassLoader::get_jrt_entry();

  assert(jrt != NULL,
         "No modular java runtime image present when allocating the CDS classpath entry table");

  if (_saved_shared_path_table_array != NULL) {
    MetadataFactory::free_array<u8>(loader_data, _saved_shared_path_table_array);
    _saved_shared_path_table_array = NULL;
  }

  copy_shared_path_table(loader_data, CHECK);
}

void FileMapInfo::allocate_shared_path_table(TRAPS) {
  Arguments::assert_is_dumping_archive();

  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
  ClassPathEntry* jrt = ClassLoader::get_jrt_entry();

  assert(jrt != NULL,
         "No modular java runtime image present when allocating the CDS classpath entry table");

  _shared_path_table.dumptime_init(loader_data, CHECK);

  // 1. boot class path
  int i = 0;
  i = add_shared_classpaths(i, "boot",   jrt, CHECK);
  i = add_shared_classpaths(i, "app",    ClassLoader::app_classpath_entries(), CHECK);
  i = add_shared_classpaths(i, "module", ClassLoader::module_path_entries(), CHECK);

  for (int x = 0; x < num_non_existent_class_paths(); x++, i++) {
    const char* path = _non_existent_class_paths->at(x);
    shared_path(i)->init_as_non_existent(path, CHECK);
  }

  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
  clone_shared_path_table(CHECK);
}

int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) {
  while (cpe != NULL) {
    bool is_jrt = (cpe == ClassLoader::get_jrt_entry());
    bool is_module_path = i >= ClassLoaderExt::app_module_paths_start_index();
    const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
    log_info(class, path)("add %s shared path (%s) %s", which, type, cpe->name());
    SharedClassPathEntry* ent = shared_path(i);
    ent->init(is_jrt, is_module_path, cpe, CHECK_0);
    if (cpe->is_jar_file()) {
      update_jar_manifest(cpe, ent, CHECK_0);
    }
    if (is_jrt) {
      cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
    } else {
      cpe = cpe->next();
    }
    i++;
  }

  return i;
}

void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
  Arguments::assert_is_dumping_archive();

  bool has_nonempty_dir = false;

  int last = _shared_path_table.size() - 1;
  if (last > ClassLoaderExt::max_used_path_index()) {
     // no need to check any path beyond max_used_path_index
     last = ClassLoaderExt::max_used_path_index();
  }

  for (int i = 0; i <= last; i++) {
    SharedClassPathEntry *e = shared_path(i);
    if (e->is_dir()) {
      const char* path = e->name();
      if (!os::dir_is_empty(path)) {
        log_error(cds)("Error: non-empty directory '%s'", path);
        has_nonempty_dir = true;
      }
    }
  }

  if (has_nonempty_dir) {
    ClassLoader::exit_with_path_failure("Cannot have non-empty directory in paths", NULL);
  }
}

void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
  Arguments::assert_is_dumping_archive();
  log_info(class, path)("non-existent Class-Path entry %s", path);
  if (_non_existent_class_paths == NULL) {
    _non_existent_class_paths = new (mtClass) GrowableArray<const char*>(10, mtClass);
  }
  _non_existent_class_paths->append(os::strdup(path));
}

int FileMapInfo::num_non_existent_class_paths() {
  Arguments::assert_is_dumping_archive();
  if (_non_existent_class_paths != NULL) {
    return _non_existent_class_paths->length();
  } else {
    return 0;
  }
}

int FileMapInfo::get_module_shared_path_index(Symbol* location) {
  if (location->starts_with("jrt:", 4) && get_number_of_shared_paths() > 0) {
    assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
    return 0;
  }

  if (ClassLoaderExt::app_module_paths_start_index() >= get_number_of_shared_paths()) {
    // The archive(s) were created without --module-path option
    return -1;
  }

  if (!location->starts_with("file:", 5)) {
    return -1;
  }

  // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table()
  ResourceMark rm;
  const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
  for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
    SharedClassPathEntry* ent = shared_path(i);
    assert(ent->in_named_module(), "must be");
    bool cond = strcmp(file, ent->name()) == 0;
    log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i,
                           location->as_C_string(), ent->name(), cond ? "same" : "different");
    if (cond) {
      return i;
    }
  }

  return -1;
}

class ManifestStream: public ResourceObj {
  private:
  u1*   _buffer_start; // Buffer bottom
  u1*   _buffer_end;   // Buffer top (one past last element)
  u1*   _current;      // Current buffer position

 public:
  // Constructor
  ManifestStream(u1* buffer, int length) : _buffer_start(buffer),
                                           _current(buffer) {
    _buffer_end = buffer + length;
  }

  static bool is_attr(u1* attr, const char* name) {
    return strncmp((const char*)attr, name, strlen(name)) == 0;
  }

  static char* copy_attr(u1* value, size_t len) {
    char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
    strncpy(buf, (char*)value, len);
    buf[len] = 0;
    return buf;
  }

  // The return value indicates if the JAR is signed or not
  bool check_is_signed() {
    u1* attr = _current;
    bool isSigned = false;
    while (_current < _buffer_end) {
      if (*_current == '\n') {
        *_current = '\0';
        u1* value = (u1*)strchr((char*)attr, ':');
        if (value != NULL) {
          assert(*(value+1) == ' '"Unrecognized format" );
          if (strstr((char*)attr, "-Digest") != NULL) {
            isSigned = true;
            break;
          }
        }
        *_current = '\n'// restore
        attr = _current + 1;
      }
      _current ++;
    }
    return isSigned;
  }
};

void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
  ResourceMark rm(THREAD);
  jint manifest_size;

  assert(cpe->is_jar_file() && ent->is_jar(), "the shared class path entry is not a JAR file");
  char* manifest = ClassLoaderExt::read_manifest(THREAD, cpe, &manifest_size);
  if (manifest != NULL) {
    ManifestStream* stream = new ManifestStream((u1*)manifest,
                                                manifest_size);
    if (stream->check_is_signed()) {
      ent->set_is_signed();
    } else {
      // Copy the manifest into the shared archive
      manifest = ClassLoaderExt::read_raw_manifest(THREAD, cpe, &manifest_size);
      Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
                                                      manifest_size,
                                                      CHECK);
      char* p = (char*)(buf->data());
      memcpy(p, manifest, manifest_size);
      ent->set_manifest(buf);
    }
  }
}

char* FileMapInfo::skip_first_path_entry(const char* path) {
  size_t path_sep_len = strlen(os::path_separator());
  char* p = strstr((char*)path, os::path_separator());
  if (p != NULL) {
    debug_only( {
      size_t image_name_len = strlen(MODULES_IMAGE_NAME);
      assert(strncmp(p - image_name_len, MODULES_IMAGE_NAME, image_name_len) == 0,
             "first entry must be the modules image");
    } );
    p += path_sep_len;
  } else {
    debug_only( {
      assert(ClassLoader::string_ends_with(path, MODULES_IMAGE_NAME),
             "first entry must be the modules image");
    } );
  }
  return p;
}

int FileMapInfo::num_paths(const char* path) {
  if (path == NULL) {
    return 0;
  }
  int npaths = 1;
  char* p = (char*)path;
  while (p != NULL) {
    char* prev = p;
    p = strstr((char*)p, os::path_separator());
    if (p != NULL) {
      p++;
      // don't count empty path
      if ((p - prev) > 1) {
       npaths++;
      }
    }
  }
  return npaths;
}

// Returns true if a path within the paths exists and has non-zero size.
bool FileMapInfo::check_paths_existence(const char* paths) {
  ClasspathStream cp_stream(paths);
  bool exist = false;
  struct stat st;
  while (cp_stream.has_next()) {
    const char* path = cp_stream.get_next();
    if (os::stat(path, &st) == 0 && st.st_size > 0) {
      exist = true;
      break;
    }
  }
  return exist;
}

GrowableArray<const char*>* FileMapInfo::create_dumptime_app_classpath_array() {
  Arguments::assert_is_dumping_archive();
  GrowableArray<const char*>* path_array = new GrowableArray<const char*>(10);
  ClassPathEntry* cpe = ClassLoader::app_classpath_entries();
  while (cpe != NULL) {
    path_array->append(cpe->name());
    cpe = cpe->next();
  }
  return path_array;
}

GrowableArray<const char*>* FileMapInfo::create_path_array(const char* paths) {
  GrowableArray<const char*>* path_array = new GrowableArray<const char*>(10);
  JavaThread* current = JavaThread::current();
  ClasspathStream cp_stream(paths);
  bool non_jar_in_cp = header()->has_non_jar_in_classpath();
  while (cp_stream.has_next()) {
    const char* path = cp_stream.get_next();
    if (!non_jar_in_cp) {
      struct stat st;
      if (os::stat(path, &st) == 0) {
        path_array->append(path);
      }
    } else {
      const char* canonical_path = ClassLoader::get_canonical_path(path, current);
      if (canonical_path != NULL) {
        char* error_msg = NULL;
        jzfile* zip = ClassLoader::open_zip_file(canonical_path, &error_msg, current);
        if (zip != NULL && error_msg == NULL) {
          path_array->append(path);
        }
      }
    }
  }
  return path_array;
}

bool FileMapInfo::classpath_failure(const char* msg, const char* name) {
  ClassLoader::trace_class_path(msg, name);
  if (PrintSharedArchiveAndExit) {
    MetaspaceShared::set_archive_loading_failed();
  }
  return false;
}

unsigned int FileMapInfo::longest_common_app_classpath_prefix_len(int num_paths,
                                                                  GrowableArray<const char*>* rp_array) {
  if (num_paths == 0) {
    return 0;
  }
  unsigned int pos;
  for (pos = 0; ; pos++) {
    for (int i = 0; i < num_paths; i++) {
      if (rp_array->at(i)[pos] != '\0' && rp_array->at(i)[pos] == rp_array->at(0)[pos]) {
        continue;
      }

      // search backward for the pos before the file separator char
      while (pos > 0 && rp_array->at(0)[--pos] != *os::file_separator());
      // return the file separator char position
      return pos + 1;
    }
  }
  return 0;
}

bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, GrowableArray<const char*>* rp_array,
                              unsigned int dumptime_prefix_len, unsigned int runtime_prefix_len) {
  int i = 0;
  int j = shared_path_start_idx;
  while (i < num_paths) {
    while (shared_path(j)->from_class_path_attr()) {
      // shared_path(j) was expanded from the JAR file attribute "Class-Path:"
      // during dump time. It's not included in the -classpath VM argument.
      j++;
    }
    assert(strlen(shared_path(j)->name()) > (size_t)dumptime_prefix_len, "sanity");
    const char* dumptime_path = shared_path(j)->name() + dumptime_prefix_len;
    assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity");
    const char* runtime_path = rp_array->at(i)  + runtime_prefix_len;
    if (!os::same_files(dumptime_path, runtime_path)) {
      return true;
    }
    i++;
    j++;
  }
  return false;
}

bool FileMapInfo::validate_boot_class_paths() {
  //
  // - Archive contains boot classes only - relaxed boot path check:
  //   Extra path elements appended to the boot path at runtime are allowed.
  //
  // - Archive contains application or platform classes - strict boot path check:
  //   Validate the entire runtime boot path, which must be compatible
  //   with the dump time boot path. Appending boot path at runtime is not
  //   allowed.
  //

  // The first entry in boot path is the modules_image (guaranteed by
  // ClassLoader::setup_boot_search_path()). Skip the first entry. The
  // path of the runtime modules_image may be different from the dump
  // time path (e.g. the JDK image is copied to a different location
  // after generating the shared archive), which is acceptable. For most
  // common cases, the dump time boot path might contain modules_image only.
  char* runtime_boot_path = Arguments::get_boot_class_path();
  char* rp = skip_first_path_entry(runtime_boot_path);
  assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
  int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image
  bool mismatch = false;

  bool relaxed_check = !header()->has_platform_or_app_classes();
  if (dp_len == 0 && rp == NULL) {
    return true;   // ok, both runtime and dump time boot paths have modules_images only
  } else if (dp_len == 0 && rp != NULL) {
    if (relaxed_check) {
      return true;   // ok, relaxed check, runtime has extra boot append path entries
    } else {
      ResourceMark rm;
      if (check_paths_existence(rp)) {
        // If a path exists in the runtime boot paths, it is considered a mismatch
        // since there's no boot path specified during dump time.
        mismatch = true;
      }
    }
  } else if (dp_len > 0 && rp != NULL) {
    int num;
    ResourceMark rm;
    GrowableArray<const char*>* rp_array = create_path_array(rp);
    int rp_len = rp_array->length();
    if (rp_len >= dp_len) {
      if (relaxed_check) {
        // only check the leading entries in the runtime boot path, up to
        // the length of the dump time boot path
        num = dp_len;
      } else {
        // check the full runtime boot path, must match with dump time
        num = rp_len;
      }
      mismatch = check_paths(1, num, rp_array, 0, 0);
    } else {
      // create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths
      // are the same initially, after the call to create_path_array(), the runtime boot classpath length could become
      // shorter. We consider boot classpath mismatch in this case.
      mismatch = true;
    }
  }

  if (mismatch) {
    // The paths are different
    return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path);
  }
  return true;
}

bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
  const char *appcp = Arguments::get_appclasspath();
  assert(appcp != NULL, "NULL app classpath");
  int rp_len = num_paths(appcp);
  bool mismatch = false;
  if (rp_len < shared_app_paths_len) {
    return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp);
  }
  if (shared_app_paths_len != 0 && rp_len != 0) {
    // Prefix is OK: E.g., dump with -cp foo.jar, but run with -cp foo.jar:bar.jar.
    ResourceMark rm;
    GrowableArray<const char*>* rp_array = create_path_array(appcp);
    if (rp_array->length() == 0) {
      // None of the jar file specified in the runtime -cp exists.
      return classpath_failure("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp);
    }
    if (rp_array->length() < shared_app_paths_len) {
      // create_path_array() ignores non-existing paths. Although the dump time and runtime app classpath lengths
      // are the same initially, after the call to create_path_array(), the runtime app classpath length could become
      // shorter. We consider app classpath mismatch in this case.
      return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp);
    }

    // Handling of non-existent entries in the classpath: we eliminate all the non-existent
    // entries from both the dump time classpath (ClassLoader::update_class_path_entry_list)
    // and the runtime classpath (FileMapInfo::create_path_array), and check the remaining
    // entries. E.g.:
    //
    // dump : -cp a.jar:NE1:NE2:b.jar  -> a.jar:b.jar -> recorded in archive.
    // run 1: -cp NE3:a.jar:NE4:b.jar  -> a.jar:b.jar -> matched
    // run 2: -cp x.jar:NE4:b.jar      -> x.jar:b.jar -> mismatched

    int j = header()->app_class_paths_start_index();
    mismatch = check_paths(j, shared_app_paths_len, rp_array, 0, 0);
    if (mismatch) {
      // To facilitate app deployment, we allow the JAR files to be moved *together* to
      // a different location, as long as they are still stored under the same directory
      // structure. E.g., the following is OK.
      //     java -Xshare:dump -cp /a/Foo.jar:/a/b/Bar.jar  ...
      //     java -Xshare:auto -cp /x/y/Foo.jar:/x/y/b/Bar.jar  ...
      unsigned int dumptime_prefix_len = header()->common_app_classpath_prefix_size();
      unsigned int runtime_prefix_len = longest_common_app_classpath_prefix_len(shared_app_paths_len, rp_array);
      mismatch = check_paths(j, shared_app_paths_len, rp_array,
                             dumptime_prefix_len, runtime_prefix_len);
      if (mismatch) {
        return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp);
      }
    }
  }
  return true;
}

void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
  LogTarget(Info, class, path) lt;
  if (lt.is_enabled()) {
    LogStream ls(lt);
    ls.print("%s", msg);
    const char* prefix = "";
    for (int i = start_idx; i < end_idx; i++) {
      ls.print("%s%s", prefix, shared_path(i)->name());
      prefix = os::path_separator();
    }
    ls.cr();
  }
}

bool FileMapInfo::check_module_paths() {
  const char* rp = Arguments::get_property("jdk.module.path");
  int num_paths = Arguments::num_archives(rp);
  if (num_paths != header()->num_module_paths()) {
    return false;
  }
  ResourceMark rm;
  GrowableArray<const char*>* rp_array = create_path_array(rp);
  return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array, 0, 0);
}

bool FileMapInfo::validate_shared_path_table() {
  assert(UseSharedSpaces, "runtime only");

  _validating_shared_path_table = true;

  // Load the shared path table info from the archive header
  _shared_path_table = header()->shared_path_table();
  if (DynamicDumpSharedSpaces) {
    // Only support dynamic dumping with the usage of the default CDS archive
    // or a simple base archive.
    // If the base layer archive contains additional path component besides
    // the runtime image and the -cp, dynamic dumping is disabled.
    //
    // When dynamic archiving is enabled, the _shared_path_table is overwritten
    // to include the application path and stored in the top layer archive.
    assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
    if (header()->app_class_paths_start_index() > 1) {
      DynamicDumpSharedSpaces = false;
      warning(
        "Dynamic archiving is disabled because base layer archive has appended boot classpath");
    }
    if (header()->num_module_paths() > 0) {
      if (!check_module_paths()) {
        DynamicDumpSharedSpaces = false;
        warning(
          "Dynamic archiving is disabled because base layer archive has a different module path");
      }
    }
  }

  log_paths("Expecting BOOT path=", 0, header()->app_class_paths_start_index());
  log_paths("Expecting -Djava.class.path=", header()->app_class_paths_start_index(), header()->app_module_paths_start_index());

  int module_paths_start_index = header()->app_module_paths_start_index();
  int shared_app_paths_len = 0;

  // validate the path entries up to the _max_used_path_index
  for (int i=0; i < header()->max_used_path_index() + 1; i++) {
    if (i < module_paths_start_index) {
      if (shared_path(i)->validate()) {
        // Only count the app class paths not from the "Class-path" attribute of a jar manifest.
        if (!shared_path(i)->from_class_path_attr() && i >= header()->app_class_paths_start_index()) {
          shared_app_paths_len++;
        }
        log_info(class, path)("ok");
      } else {
        if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
          assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
        }
        return false;
      }
    } else if (i >= module_paths_start_index) {
      if (shared_path(i)->validate(false /* not a class path entry */)) {
        log_info(class, path)("ok");
      } else {
        if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
          assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
        }
        return false;
      }
    }
  }

  if (header()->max_used_path_index() == 0) {
    // default archive only contains the module image in the bootclasspath
    assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
  } else {
    if (!validate_boot_class_paths() || !validate_app_class_paths(shared_app_paths_len)) {
      const char* mismatch_msg = "shared class paths mismatch";
      const char* hint_msg = log_is_enabled(Info, class, path) ?
          "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)";
      fail_continue(LogLevel::Warning, "%s%s", mismatch_msg, hint_msg);
      return false;
    }
  }

  validate_non_existent_class_paths();

  _validating_shared_path_table = false;

#if INCLUDE_JVMTI
  if (_classpath_entries_for_jvmti != NULL) {
    os::free(_classpath_entries_for_jvmti);
  }
  size_t sz = sizeof(ClassPathEntry*) * get_number_of_shared_paths();
  _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass);
  memset((void*)_classpath_entries_for_jvmti, 0, sz);
#endif

  return true;
}

void FileMapInfo::validate_non_existent_class_paths() {
  // All of the recorded non-existent paths came from the Class-Path: attribute from the JAR
  // files on the app classpath. If any of these are found to exist during runtime,
  // it will change how classes are loading for the app loader. For safety, disable
  // loading of archived platform/app classes (currently there's no way to disable just the
  // app classes).

  assert(UseSharedSpaces, "runtime only");
  for (int i = header()->app_module_paths_start_index() + header()->num_module_paths();
       i < get_number_of_shared_paths();
       i++) {
    SharedClassPathEntry* ent = shared_path(i);
    if (!ent->check_non_existent()) {
      warning("Archived non-system classes are disabled because the "
              "file %s exists", ent->name());
      header()->set_has_platform_or_app_classes(false);
    }
  }
}

// A utility class for reading/validating the GenericCDSFileMapHeader portion of
// a CDS archive's header. The file header of all CDS archives with versions from
// CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12) are guaranteed to always start
// with GenericCDSFileMapHeader. This makes it possible to read important information
// from a CDS archive created by a different version of HotSpot, so that we can
// automatically regenerate the archive as necessary (JDK-8261455).
class FileHeaderHelper {
  int _fd;
  bool _is_valid;
  bool _is_static;
  GenericCDSFileMapHeader* _header;
  const char* _archive_name;
  const char* _base_archive_name;

public:
  FileHeaderHelper(const char* archive_name, bool is_static) {
    _fd = -1;
    _is_valid = false;
    _header = nullptr;
    _base_archive_name = nullptr;
    _archive_name = archive_name;
    _is_static = is_static;
  }

  ~FileHeaderHelper() {
    if (_header != nullptr) {
      FREE_C_HEAP_ARRAY(char, _header);
    }
    if (_fd != -1) {
      ::close(_fd);
    }
  }

  bool initialize() {
    assert(_archive_name != nullptr, "Archive name is NULL");
    _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0);
    if (_fd < 0) {
      FileMapInfo::fail_continue("Specified shared archive not found (%s)", _archive_name);
      return false;
    }
    return initialize(_fd);
  }

  // for an already opened file, do not set _fd
  bool initialize(int fd) {
    assert(_archive_name != nullptr, "Archive name is NULL");
    assert(fd != -1, "Archive must be opened already");
    // First read the generic header so we know the exact size of the actual header.
    GenericCDSFileMapHeader gen_header;
    size_t size = sizeof(GenericCDSFileMapHeader);
    os::lseek(fd, 0, SEEK_SET);
    size_t n = ::read(fd, (void*)&gen_header, (unsigned int)size);
    if (n != size) {
      FileMapInfo::fail_continue("Unable to read generic CDS file map header from shared archive");
      return false;
    }

    if (gen_header._magic != CDS_ARCHIVE_MAGIC &&
        gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
      FileMapInfo::fail_continue("The shared archive file has a bad magic number: %#x", gen_header._magic);
      return false;
    }

    if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) {
      FileMapInfo::fail_continue("Cannot handle shared archive file version 0x%x. Must be at least 0x%x.",
                                 gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION);
      return false;
    }

    if (gen_header._version !=  CURRENT_CDS_ARCHIVE_VERSION) {
      FileMapInfo::fail_continue("The shared archive file version 0x%x does not match the required version 0x%x.",
                                 gen_header._version, CURRENT_CDS_ARCHIVE_VERSION);
    }

    size_t filelen = os::lseek(fd, 0, SEEK_END);
    if (gen_header._header_size >= filelen) {
      FileMapInfo::fail_continue("Archive file header larger than archive file");
      return false;
    }

    // Read the actual header and perform more checks
    size = gen_header._header_size;
    _header = (GenericCDSFileMapHeader*)NEW_C_HEAP_ARRAY(char, size, mtInternal);
    os::lseek(fd, 0, SEEK_SET);
    n = ::read(fd, (void*)_header, (unsigned int)size);
    if (n != size) {
      FileMapInfo::fail_continue("Unable to read actual CDS file map header from shared archive");
      return false;
    }

    if (!check_crc()) {
      return false;
    }

    if (!check_and_init_base_archive_name()) {
      return false;
    }

    // All fields in the GenericCDSFileMapHeader has been validated.
    _is_valid = true;
    return true;
  }

  GenericCDSFileMapHeader* get_generic_file_header() {
    assert(_header != nullptr && _is_valid, "must be a valid archive file");
    return _header;
  }

  const char* base_archive_name() {
    assert(_header != nullptr && _is_valid, "must be a valid archive file");
    return _base_archive_name;
  }

 private:
  bool check_crc() {
    if (VerifySharedSpaces) {
      FileMapHeader* header = (FileMapHeader*)_header;
      int actual_crc = header->compute_crc();
      if (actual_crc != header->crc()) {
        log_info(cds)("_crc expected: %d", header->crc());
        log_info(cds)(" actual: %d", actual_crc);
        FileMapInfo::fail_continue("Header checksum verification failed.");
        return false;
      }
    }
    return true;
  }

  bool check_and_init_base_archive_name() {
    unsigned int name_offset = _header->_base_archive_name_offset;
    unsigned int name_size   = _header->_base_archive_name_size;
    unsigned int header_size = _header->_header_size;

    if (name_offset + name_size < name_offset) {
      FileMapInfo::fail_continue("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT,
                                 name_offset, name_size);
      return false;
    }
    if (_header->_magic == CDS_ARCHIVE_MAGIC) {
      if (name_offset != 0) {
        FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_offset");
        return false;
      }
      if (name_size != 0) {
        FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_size");
        return false;
      }
    } else {
      assert(_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC, "must be");
      if ((name_size == 0 && name_offset != 0) ||
          (name_size != 0 && name_offset == 0)) {
        // If either is zero, both must be zero. This indicates that we are using the default base archive.
        FileMapInfo::fail_continue("Invalid base_archive_name offset/size: " UINT32_FORMA"/" UINT32_FORMAT,
                                   name_offset, name_size);
        return false;
      }
      if (name_size > 0) {
        if (name_offset + name_size > header_size) {
          FileMapInfo::fail_continue("Invalid base_archive_name offset/size (out of range): "
                                     UINT32_FORMAT " + " UINT32_FORMAT " > " UINT32_FORMAT ,
                                     name_offset, name_size, header_size);
          return false;
        }
        const char* name = ((const char*)_header) + _header->_base_archive_name_offset;
        if (name[name_size - 1] != '\0' || strlen(name) != name_size - 1) {
          FileMapInfo::fail_continue("Base archive name is damaged");
          return false;
        }
        if (!os::file_exists(name)) {
          FileMapInfo::fail_continue("Base archive %s does not exist", name);
          return false;
        }
        _base_archive_name = name;
      }
    }

    return true;
  }
};

// Return value:
// false:
//      <archive_name> is not a valid archive. *base_archive_name is set to null.
// true && (*base_archive_name) == NULL:
//      <archive_name> is a valid static archive.
// true && (*base_archive_name) != NULL:
//      <archive_name> is a valid dynamic archive.
bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
                                                    char** base_archive_name) {
  FileHeaderHelper file_helper(archive_name, false);
  *base_archive_name = NULL;

  if (!file_helper.initialize()) {
    return false;
  }
  GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
  if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
    assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be");
    if (AutoCreateSharedArchive) {
     log_warning(cds)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name);
    }
    return true;
  }

  const char* base = file_helper.base_archive_name();
  if (base == nullptr) {
    *base_archive_name = Arguments::get_default_shared_archive_path();
  } else {
    *base_archive_name = os::strdup_check_oom(base);
  }

  return true;
}

// Read the FileMapInfo information from the file.

bool FileMapInfo::init_from_file(int fd) {
  FileHeaderHelper file_helper(_full_path, _is_static);
  if (!file_helper.initialize(fd)) {
    fail_continue("Unable to read the file header.");
    return false;
  }
  GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header();

  if (_is_static) {
    if (gen_header->_magic != CDS_ARCHIVE_MAGIC) {
      FileMapInfo::fail_continue("Not a base shared archive: %s", _full_path);
      return false;
    }
  } else {
    if (gen_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
      FileMapInfo::fail_continue("Not a top shared archive: %s", _full_path);
      return false;
    }
  }

  _header = (FileMapHeader*)os::malloc(gen_header->_header_size, mtInternal);
  os::lseek(fd, 0, SEEK_SET); // reset to begin of the archive
  size_t size = gen_header->_header_size;
  size_t n = ::read(fd, (void*)_header, (unsigned int)size);
  if (n != size) {
    fail_continue("Failed to read file header from the top archive file\n");
    return false;
  }

  if (header()->version() != CURRENT_CDS_ARCHIVE_VERSION) {
    log_info(cds)("_version expected: 0x%x", CURRENT_CDS_ARCHIVE_VERSION);
    log_info(cds)(" actual: 0x%x", header()->version());
    fail_continue("The shared archive file has the wrong version.");
    return false;
  }

  int common_path_size = header()->common_app_classpath_prefix_size();
  if (common_path_size < 0) {
      FileMapInfo::fail_continue("common app classpath prefix len < 0");
      return false;
  }

  unsigned int base_offset = header()->base_archive_name_offset();
  unsigned int name_size = header()->base_archive_name_size();
  unsigned int header_size = header()->header_size();
  if (base_offset != 0 && name_size != 0) {
    if (header_size != base_offset + name_size) {
      log_info(cds)("_header_size: " UINT32_FORMAT, header_size);
      log_info(cds)("common_app_classpath_size: " UINT32_FORMAT, header()->common_app_classpath_prefix_size());
      log_info(cds)("base_archive_name_size: " UINT32_FORMAT, header()->base_archive_name_size());
      log_info(cds)("base_archive_name_offset: " UINT32_FORMAT, header()->base_archive_name_offset());
      FileMapInfo::fail_continue("The shared archive file has an incorrect header size.");
      return false;
    }
  }

  const char* actual_ident = header()->jvm_ident();

  if (actual_ident[JVM_IDENT_MAX-1] != 0) {
    FileMapInfo::fail_continue("JVM version identifier is corrupted.");
    return false;
  }

  char expected_ident[JVM_IDENT_MAX];
  get_header_version(expected_ident);
  if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) {
    log_info(cds)("_jvm_ident expected: %s", expected_ident);
    log_info(cds)(" actual: %s", actual_ident);
    FileMapInfo::fail_continue("The shared archive file was created by a different"
                  " version or build of HotSpot");
    return false;
  }

  _file_offset = header()->header_size(); // accounts for the size of _base_archive_name

  size_t len = os::lseek(fd, 0, SEEK_END);

  for (int i = 0; i <= MetaspaceShared::last_valid_region; i++) {
    FileMapRegion* r = region_at(i);
    if (r->file_offset() > len || len - r->file_offset() < r->used()) {
      fail_continue("The shared archive file has been truncated.");
      return false;
    }
  }

  return true;
}

void FileMapInfo::seek_to_position(size_t pos) {
  if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) {
    fail_stop("Unable to seek to position " SIZE_FORMAT, pos);
  }
}

// Read the FileMapInfo information from the file.
bool FileMapInfo::open_for_read() {
  if (_file_open) {
    return true;
  }
  log_info(cds)("trying to map %s", _full_path);
  int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
  if (fd < 0) {
    if (errno == ENOENT) {
      fail_continue("Specified shared archive not found (%s)", _full_path);
    } else {
      fail_continue("Failed to open shared archive file (%s)",
                    os::strerror(errno));
    }
    return false;
  } else {
    log_info(cds)("Opened archive %s.", _full_path);
  }

  _fd = fd;
  _file_open = true;
  return true;
}

// Write the FileMapInfo information to the file.

void FileMapInfo::open_for_write() {
  LogMessage(cds) msg;
  if (msg.is_info()) {
    msg.info("Dumping shared data to file: ");
    msg.info(" %s", _full_path);
  }

#ifdef _WINDOWS  // On Windows, need WRITE permission to remove the file.
    chmod(_full_path, _S_IREAD | _S_IWRITE);
#endif

  // Use remove() to delete the existing file because, on Unix, this will
  // allow processes that have it open continued access to the file.
  remove(_full_path);
  int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444);
  if (fd < 0) {
    fail_stop("Unable to create shared archive file %s: (%s).", _full_path,
              os::strerror(errno));
  }
  _fd = fd;
  _file_open = true;

  // Seek past the header. We will write the header after all regions are written
  // and their CRCs computed.
  size_t header_bytes = header()->header_size();

  header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment());
  _file_offset = header_bytes;
  seek_to_position(_file_offset);
}

// Write the header to the file, seek to the next allocation boundary.

void FileMapInfo::write_header() {
  _file_offset = 0;
  seek_to_position(_file_offset);
  assert(is_file_position_aligned(), "must be");
  write_bytes(header(), header()->header_size());
}

size_t FileMapRegion::used_aligned() const {
  return align_up(used(), MetaspaceShared::core_region_alignment());
}

void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, bool read_only,
                         bool allow_exec, int crc) {
  _is_heap_region = HeapShared::is_heap_region(region_index);
  _is_bitmap_region = (region_index == MetaspaceShared::bm);
  _mapping_offset = mapping_offset;
  _used = size;
  _read_only = read_only;
  _allow_exec = allow_exec;
  _crc = crc;
  _mapped_from_file = false;
  _mapped_base = NULL;
}

void FileMapRegion::init_bitmaps(ArchiveHeapBitmapInfo oopmap, ArchiveHeapBitmapInfo ptrmap) {
  _oopmap_offset = oopmap._bm_region_offset;
  _oopmap_size_in_bits = oopmap._size_in_bits;

  _ptrmap_offset = ptrmap._bm_region_offset;
  _ptrmap_size_in_bits = ptrmap._size_in_bits;
}

BitMapView FileMapRegion::bitmap_view(bool is_oopmap) {
  char* bitmap_base = FileMapInfo::current_info()->map_bitmap_region();
  bitmap_base += is_oopmap ? _oopmap_offset : _ptrmap_offset;
  size_t size_in_bits = is_oopmap ? _oopmap_size_in_bits : _ptrmap_size_in_bits;
  return BitMapView((BitMap::bm_word_t*)(bitmap_base), size_in_bits);
}

BitMapView FileMapRegion::oopmap_view() {
  return bitmap_view(true);
}

BitMapView FileMapRegion::ptrmap_view() {
  assert(has_ptrmap(), "must be");
  return bitmap_view(false);
}

static const char* region_name(int region_index) {
  static const char* names[] = {
    "rw""ro""bm""ca0""ca1""oa0""oa1"
  };
  const int num_regions = sizeof(names)/sizeof(names[0]);
  assert(0 <= region_index && region_index < num_regions, "sanity");

  return names[region_index];
}

void FileMapRegion::print(outputStream* st, int region_index) {
  st->print_cr("============ region ============= %d \"%s\"", region_index, region_name(region_index));
  st->print_cr("- crc: 0x%08x", _crc);
  st->print_cr("- read_only: %d", _read_only);
  st->print_cr("- allow_exec: %d", _allow_exec);
  st->print_cr("- is_heap_region: %d", _is_heap_region);
  st->print_cr("- is_bitmap_region: %d", _is_bitmap_region);
  st->print_cr("- mapped_from_file: %d", _mapped_from_file);
  st->print_cr("- file_offset: " SIZE_FORMAT_X, _file_offset);
  st->print_cr("- mapping_offset: " SIZE_FORMAT_X, _mapping_offset);
  st->print_cr("- used: " SIZE_FORMAT, _used);
  st->print_cr("- oopmap_offset: " SIZE_FORMAT_X, _oopmap_offset);
  st->print_cr("- oopmap_size_in_bits: " SIZE_FORMAT, _oopmap_size_in_bits);
  st->print_cr("- mapped_base: " INTPTR_FORMAT, p2i(_mapped_base));
}

void FileMapInfo::write_region(int region, char* base, size_t size,
                               bool read_only, bool allow_exec) {
  Arguments::assert_is_dumping_archive();

  FileMapRegion* r = region_at(region);
  char* requested_base;
  size_t mapping_offset = 0;

  if (region == MetaspaceShared::bm) {
    requested_base = NULL; // always NULL for bm region
  } else if (size == 0) {
    // This is an unused region (e.g., a heap region when !INCLUDE_CDS_JAVA_HEAP)
    requested_base = NULL;
  } else if (HeapShared::is_heap_region(region)) {
    assert(!DynamicDumpSharedSpaces, "must be");
    requested_base = base;
    if (UseCompressedOops) {
      mapping_offset = (size_t)((address)base - CompressedOops::base());
      assert((mapping_offset >> CompressedOops::shift()) << CompressedOops::shift() == mapping_offset, "must be");
    } else {
#if INCLUDE_G1GC
      mapping_offset = requested_base - (char*)G1CollectedHeap::heap()->reserved().start();
#endif
    }
  } else {
    char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address();
    requested_base = ArchiveBuilder::current()->to_requested(base);
    assert(requested_base >= requested_SharedBaseAddress, "must be");
    mapping_offset = requested_base - requested_SharedBaseAddress;
  }

  r->set_file_offset(_file_offset);
  int crc = ClassLoader::crc32(0, base, (jint)size);
  if (size > 0) {
    log_info(cds)("Shared file region (%-3s) %d: " SIZE_FORMAT_W(8)
                   " bytes, addr " INTPTR_FORMAT " file offset 0x%08" PRIxPTR
                   " crc 0x%08x",
                   region_name(region), region, size, p2i(requested_base), _file_offset, crc);
  }

  r->init(region, mapping_offset, size, read_only, allow_exec, crc);

  if (base != NULL) {
    write_bytes_aligned(base, size);
  }
}

size_t FileMapInfo::set_bitmaps_offset(GrowableArray<ArchiveHeapBitmapInfo>* bitmaps, size_t curr_size) {
  for (int i = 0; i < bitmaps->length(); i++) {
    bitmaps->at(i)._bm_region_offset = curr_size;
    curr_size += bitmaps->at(i)._size_in_bytes;
  }
  return curr_size;
}

size_t FileMapInfo::write_bitmaps(GrowableArray<ArchiveHeapBitmapInfo>* bitmaps, size_t curr_offset, char* buffer) {
  for (int i = 0; i < bitmaps->length(); i++) {
    memcpy(buffer + curr_offset, bitmaps->at(i)._map, bitmaps->at(i)._size_in_bytes);
    curr_offset += bitmaps->at(i)._size_in_bytes;
  }
  return curr_offset;
}

char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap,
                                       GrowableArray<ArchiveHeapBitmapInfo>* closed_bitmaps,
                                       GrowableArray<ArchiveHeapBitmapInfo>* open_bitmaps,
                                       size_t &size_in_bytes) {
  size_t size_in_bits = ptrmap->size();
  size_in_bytes = ptrmap->size_in_bytes();

  if (closed_bitmaps != NULL && open_bitmaps != NULL) {
    size_in_bytes = set_bitmaps_offset(closed_bitmaps, size_in_bytes);
    size_in_bytes = set_bitmaps_offset(open_bitmaps, size_in_bytes);
  }

  char* buffer = NEW_C_HEAP_ARRAY(char, size_in_bytes, mtClassShared);
  ptrmap->write_to((BitMap::bm_word_t*)buffer, ptrmap->size_in_bytes());
  header()->set_ptrmap_size_in_bits(size_in_bits);

  if (closed_bitmaps != NULL && open_bitmaps != NULL) {
    size_t curr_offset = write_bitmaps(closed_bitmaps, ptrmap->size_in_bytes(), buffer);
    write_bitmaps(open_bitmaps, curr_offset, buffer);
  }

  write_region(MetaspaceShared::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false);
  return buffer;
}

// Write out the given archive heap memory regions.  GC code combines multiple
// consecutive archive GC regions into one MemRegion whenever possible and
// produces the 'regions' array.
//
--> --------------------

--> maximum size reached

--> --------------------

¤ Dauer der Verarbeitung: 0.35 Sekunden  (vorverarbeitet)  ¤





Kontakt
Drucken
Kontakt
sprechenden Kalenders

in der Quellcodebibliothek suchen




schauen Sie vor die Tür

Fenster


Die Firma ist wie angegeben erreichbar.

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff