Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quellcode-Bibliothek

© Kompilation durch diese Firma

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

Datei: arguments.cpp   Sprache: C

/*
 * Copyright (c) 1997, 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/cds_globals.hpp"
#include "cds/filemap.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "compiler/compilerDefinitions.hpp"
#include "gc/shared/gcArguments.hpp"
#include "gc/shared/gcConfig.hpp"
#include "gc/shared/stringdedup/stringDedup.hpp"
#include "gc/shared/tlab_globals.hpp"
#include "jvm.h"
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
#include "logging/logStream.hpp"
#include "logging/logTag.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/flags/jvmFlag.hpp"
#include "runtime/flags/jvmFlagAccess.hpp"
#include "runtime/flags/jvmFlagLimit.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/vm_version.hpp"
#include "services/management.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
#include "utilities/parseInteger.hpp"
#include "utilities/powerOfTwo.hpp"
#include "utilities/stringUtils.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif

#include <limits>

#define DEFAULT_JAVA_LAUNCHER  "generic"

char*  Arguments::_jvm_flags_file               = NULL;
char** Arguments::_jvm_flags_array              = NULL;
int    Arguments::_num_jvm_flags                = 0;
char** Arguments::_jvm_args_array               = NULL;
int    Arguments::_num_jvm_args                 = 0;
char*  Arguments::_java_command                 = NULL;
SystemProperty* Arguments::_system_properties   = NULL;
size_t Arguments::_conservative_max_heap_alignment = 0;
Arguments::Mode Arguments::_mode                = _mixed;
bool   Arguments::_java_compiler                = false;
bool   Arguments::_xdebug_mode                  = false;
const char*  Arguments::_java_vendor_url_bug    = NULL;
const char*  Arguments::_sun_java_launcher      = DEFAULT_JAVA_LAUNCHER;
bool   Arguments::_sun_java_launcher_is_altjvm  = false;

// These parameters are reset in method parse_vm_init_args()
bool   Arguments::_AlwaysCompileLoopMethods     = AlwaysCompileLoopMethods;
bool   Arguments::_UseOnStackReplacement        = UseOnStackReplacement;
bool   Arguments::_BackgroundCompilation        = BackgroundCompilation;
bool   Arguments::_ClipInlining                 = ClipInlining;
size_t Arguments::_default_SharedBaseAddress    = SharedBaseAddress;

bool   Arguments::_enable_preview               = false;

char*  Arguments::SharedArchivePath             = NULL;
char*  Arguments::SharedDynamicArchivePath      = NULL;

LegacyGCLogging Arguments::_legacyGCLogging     = { 0, 0 };

AgentLibraryList Arguments::_libraryList;
AgentLibraryList Arguments::_agentList;

// These are not set by the JDK's built-in launchers, but they can be set by
// programs that embed the JVM using JNI_CreateJavaVM. See comments around
// JavaVMOption in jni.h.
abort_hook_t     Arguments::_abort_hook         = NULL;
exit_hook_t      Arguments::_exit_hook          = NULL;
vfprintf_hook_t  Arguments::_vfprintf_hook      = NULL;


SystemProperty *Arguments::_sun_boot_library_path = NULL;
SystemProperty *Arguments::_java_library_path = NULL;
SystemProperty *Arguments::_java_home = NULL;
SystemProperty *Arguments::_java_class_path = NULL;
SystemProperty *Arguments::_jdk_boot_class_path_append = NULL;
SystemProperty *Arguments::_vm_info = NULL;

GrowableArray<ModulePatchPath*> *Arguments::_patch_mod_prefix = NULL;
PathString *Arguments::_boot_class_path = NULL;
bool Arguments::_has_jimage = false;

char* Arguments::_ext_dirs = NULL;

// True if -Xshare:auto option was specified.
static bool xshare_auto_cmd_line = false;

bool PathString::set_value(const char *value, AllocFailType alloc_failmode) {
  char* new_value = AllocateHeap(strlen(value)+1, mtArguments, alloc_failmode);
  if (new_value == NULL) {
    assert(alloc_failmode == AllocFailStrategy::RETURN_NULL, "must be");
    return false;
  }
  if (_value != NULL) {
    FreeHeap(_value);
  }
  _value = new_value;
  strcpy(_value, value);
  return true;
}

void PathString::append_value(const char *value) {
  char *sp;
  size_t len = 0;
  if (value != NULL) {
    len = strlen(value);
    if (_value != NULL) {
      len += strlen(_value);
    }
    sp = AllocateHeap(len+2, mtArguments);
    assert(sp != NULL, "Unable to allocate space for new append path value");
    if (sp != NULL) {
      if (_value != NULL) {
        strcpy(sp, _value);
        strcat(sp, os::path_separator());
        strcat(sp, value);
        FreeHeap(_value);
      } else {
        strcpy(sp, value);
      }
      _value = sp;
    }
  }
}

PathString::PathString(const char* value) {
  if (value == NULL) {
    _value = NULL;
  } else {
    _value = AllocateHeap(strlen(value)+1, mtArguments);
    strcpy(_value, value);
  }
}

PathString::~PathString() {
  if (_value != NULL) {
    FreeHeap(_value);
    _value = NULL;
  }
}

ModulePatchPath::ModulePatchPath(const char* module_name, const char* path) {
  assert(module_name != NULL && path != NULL, "Invalid module name or path value");
  size_t len = strlen(module_name) + 1;
  _module_name = AllocateHeap(len, mtInternal);
  strncpy(_module_name, module_name, len); // copy the trailing null
  _path =  new PathString(path);
}

ModulePatchPath::~ModulePatchPath() {
  if (_module_name != NULL) {
    FreeHeap(_module_name);
    _module_name = NULL;
  }
  if (_path != NULL) {
    delete _path;
    _path = NULL;
  }
}

SystemProperty::SystemProperty(const char* key, const char* value, bool writeable, bool internal) : PathString(value) {
  if (key == NULL) {
    _key = NULL;
  } else {
    _key = AllocateHeap(strlen(key)+1, mtArguments);
    strcpy(_key, key);
  }
  _next = NULL;
  _internal = internal;
  _writeable = writeable;
}

AgentLibrary::AgentLibrary(const char* name, const char* options,
               bool is_absolute_path, void* os_lib,
               bool instrument_lib) {
  _name = AllocateHeap(strlen(name)+1, mtArguments);
  strcpy(_name, name);
  if (options == NULL) {
    _options = NULL;
  } else {
    _options = AllocateHeap(strlen(options)+1, mtArguments);
    strcpy(_options, options);
  }
  _is_absolute_path = is_absolute_path;
  _os_lib = os_lib;
  _next = NULL;
  _state = agent_invalid;
  _is_static_lib = false;
  _is_instrument_lib = instrument_lib;
}

// Check if head of 'option' matches 'name', and sets 'tail' to the remaining
// part of the option string.
static bool match_option(const JavaVMOption *option, const char* name,
                         const char** tail) {
  size_t len = strlen(name);
  if (strncmp(option->optionString, name, len) == 0) {
    *tail = option->optionString + len;
    return true;
  } else {
    return false;
  }
}

// Check if 'option' matches 'name'. No "tail" is allowed.
static bool match_option(const JavaVMOption *option, const char* name) {
  const char* tail = NULL;
  bool result = match_option(option, name, &tail);
  if (tail != NULL && *tail == '\0') {
    return result;
  } else {
    return false;
  }
}

// Return true if any of the strings in null-terminated array 'names' matches.
// If tail_allowed is true, then the tail must begin with a colon; otherwise,
// the option must match exactly.
static bool match_option(const JavaVMOption* option, const char** names, const char** tail,
  bool tail_allowed) {
  for (/* empty */; *names != NULL; ++names) {
  if (match_option(option, *names, tail)) {
      if (**tail == '\0' || (tail_allowed && **tail == ':')) {
        return true;
      }
    }
  }
  return false;
}

#if INCLUDE_JFR
static bool _has_jfr_option = false;  // is using JFR

// return true on failure
static bool match_jfr_option(const JavaVMOption** option) {
  assert((*option)->optionString != NULL, "invariant");
  char* tail = NULL;
  if (match_option(*option, "-XX:StartFlightRecording", (const char**)&tail)) {
    _has_jfr_option = true;
    return Jfr::on_start_flight_recording_option(option, tail);
  } else if (match_option(*option, "-XX:FlightRecorderOptions", (const char**)&tail)) {
    _has_jfr_option = true;
    return Jfr::on_flight_recorder_option(option, tail);
  }
  return false;
}

bool Arguments::has_jfr_option() {
  return _has_jfr_option;
}
#endif

static void logOption(const char* opt) {
  if (PrintVMOptions) {
    jio_fprintf(defaultStream::output_stream(), "VM option '%s'\n", opt);
  }
}

bool needs_module_property_warning = false;

#define MODULE_PROPERTY_PREFIX "jdk.module."
#define MODULE_PROPERTY_PREFIX_LEN 11
#define ADDEXPORTS "addexports"
#define ADDEXPORTS_LEN 10
#define ADDREADS "addreads"
#define ADDREADS_LEN 8
#define ADDOPENS "addopens"
#define ADDOPENS_LEN 8
#define PATCH "patch"
#define PATCH_LEN 5
#define ADDMODS "addmods"
#define ADDMODS_LEN 7
#define LIMITMODS "limitmods"
#define LIMITMODS_LEN 9
#define PATH "path"
#define PATH_LEN 4
#define UPGRADE_PATH "upgrade.path"
#define UPGRADE_PATH_LEN 12
#define ENABLE_NATIVE_ACCESS "enable.native.access"
#define ENABLE_NATIVE_ACCESS_LEN 20

void Arguments::add_init_library(const char* name, char* options) {
  _libraryList.add(new AgentLibrary(name, options, false, NULL));
}

void Arguments::add_init_agent(const char* name, char* options, bool absolute_path) {
  _agentList.add(new AgentLibrary(name, options, absolute_path, NULL));
}

void Arguments::add_instrument_agent(const char* name, char* options, bool absolute_path) {
  _agentList.add(new AgentLibrary(name, options, absolute_path, NULL, true));
}

// Late-binding agents not started via arguments
void Arguments::add_loaded_agent(AgentLibrary *agentLib) {
  _agentList.add(agentLib);
}

// Return TRUE if option matches 'property', or 'property=', or 'property.'.
static bool matches_property_suffix(const char* option, const char* property, size_t len) {
  return ((strncmp(option, property, len) == 0) &&
          (option[len] == '=' || option[len] == '.' || option[len] == '\0'));
}

// Return true if property starts with "jdk.module." and its ensuing chars match
// any of the reserved module properties.
// property should be passed without the leading "-D".
bool Arguments::is_internal_module_property(const char* property) {
  assert((strncmp(property, "-D", 2) != 0), "Unexpected leading -D");
  if  (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) {
    const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN;
    if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) ||
        matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) ||
        matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) ||
        matches_property_suffix(property_suffix, PATCH, PATCH_LEN) ||
        matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) ||
        matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) ||
        matches_property_suffix(property_suffix, PATH, PATH_LEN) ||
        matches_property_suffix(property_suffix, UPGRADE_PATH, UPGRADE_PATH_LEN) ||
        matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) {
      return true;
    }
  }
  return false;
}

// Process java launcher properties.
void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) {
  // See if sun.java.launcher or sun.java.launcher.is_altjvm is defined.
  // Must do this before setting up other system properties,
  // as some of them may depend on launcher type.
  for (int index = 0; index < args->nOptions; index++) {
    const JavaVMOption* option = args->options + index;
    const char* tail;

    if (match_option(option, "-Dsun.java.launcher=", &tail)) {
      process_java_launcher_argument(tail, option->extraInfo);
      continue;
    }
    if (match_option(option, "-Dsun.java.launcher.is_altjvm=", &tail)) {
      if (strcmp(tail, "true") == 0) {
        _sun_java_launcher_is_altjvm = true;
      }
      continue;
    }
  }
}

// Initialize system properties key and value.
void Arguments::init_system_properties() {

  // Set up _boot_class_path which is not a property but
  // relies heavily on argument processing and the jdk.boot.class.path.append
  // property. It is used to store the underlying boot class path.
  _boot_class_path = new PathString(NULL);

  PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name",
                                                           "Java Virtual Machine Specification",  false));
  PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(),  false));
  PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(),  false));
  PropertyList_add(&_system_properties, new SystemProperty("jdk.debug", VM_Version::jdk_debug_level(),  false));

  // Initialize the vm.info now, but it will need updating after argument parsing.
  _vm_info = new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true);

  // Following are JVMTI agent writable properties.
  // Properties values are set to NULL and they are
  // os specific they are initialized in os::init_system_properties_values().
  _sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL,  true);
  _java_library_path = new SystemProperty("java.library.path", NULL,  true);
  _java_home =  new SystemProperty("java.home", NULL,  true);
  _java_class_path = new SystemProperty("java.class.path""",  true);
  // jdk.boot.class.path.append is a non-writeable, internal property.
  // It can only be set by either:
  //    - -Xbootclasspath/a:
  //    - AddToBootstrapClassLoaderSearch during JVMTI OnLoad phase
  _jdk_boot_class_path_append = new SystemProperty("jdk.boot.class.path.append", NULL, falsetrue);

  // Add to System Property list.
  PropertyList_add(&_system_properties, _sun_boot_library_path);
  PropertyList_add(&_system_properties, _java_library_path);
  PropertyList_add(&_system_properties, _java_home);
  PropertyList_add(&_system_properties, _java_class_path);
  PropertyList_add(&_system_properties, _jdk_boot_class_path_append);
  PropertyList_add(&_system_properties, _vm_info);

  // Set OS specific system properties values
  os::init_system_properties_values();
}

// Update/Initialize System properties after JDK version number is known
void Arguments::init_version_specific_system_properties() {
  enum { bufsz = 16 };
  char buffer[bufsz];
  const char* spec_vendor = "Oracle Corporation";
  uint32_t spec_version = JDK_Version::current().major_version();

  jio_snprintf(buffer, bufsz, UINT32_FORMAT, spec_version);

  PropertyList_add(&_system_properties,
      new SystemProperty("java.vm.specification.vendor",  spec_vendor, false));
  PropertyList_add(&_system_properties,
      new SystemProperty("java.vm.specification.version", buffer, false));
  PropertyList_add(&_system_properties,
      new SystemProperty("java.vm.vendor", VM_Version::vm_vendor(),  false));
}

/*
 *  -XX argument processing:
 *
 *  -XX arguments are defined in several places, such as:
 *      globals.hpp, globals_<cpu>.hpp, globals_<os>.hpp, <compiler>_globals.hpp, or <gc>_globals.hpp.
 *  -XX arguments are parsed in parse_argument().
 *  -XX argument bounds checking is done in check_vm_args_consistency().
 *
 * Over time -XX arguments may change. There are mechanisms to handle common cases:
 *
 *      ALIASED: An option that is simply another name for another option. This is often
 *               part of the process of deprecating a flag, but not all aliases need
 *               to be deprecated.
 *
 *               Create an alias for an option by adding the old and new option names to the
 *               "aliased_jvm_flags" table. Delete the old variable from globals.hpp (etc).
 *
 *   DEPRECATED: An option that is supported, but a warning is printed to let the user know that
 *               support may be removed in the future. Both regular and aliased options may be
 *               deprecated.
 *
 *               Add a deprecation warning for an option (or alias) by adding an entry in the
 *               "special_jvm_flags" table and setting the "deprecated_in" field.
 *               Often an option "deprecated" in one major release will
 *               be made "obsolete" in the next. In this case the entry should also have its
 *               "obsolete_in" field set.
 *
 *     OBSOLETE: An option that has been removed (and deleted from globals.hpp), but is still accepted
 *               on the command line. A warning is printed to let the user know that option might not
 *               be accepted in the future.
 *
 *               Add an obsolete warning for an option by adding an entry in the "special_jvm_flags"
 *               table and setting the "obsolete_in" field.
 *
 *      EXPIRED: A deprecated or obsolete option that has an "accept_until" version less than or equal
 *               to the current JDK version. The system will flatly refuse to admit the existence of
 *               the flag. This allows a flag to die automatically over JDK releases.
 *
 *               Note that manual cleanup of expired options should be done at major JDK version upgrades:
 *                  - Newly expired options should be removed from the special_jvm_flags and aliased_jvm_flags tables.
 *                  - Newly obsolete or expired deprecated options should have their global variable
 *                    definitions removed (from globals.hpp, etc) and related implementations removed.
 *
 * Recommended approach for removing options:
 *
 * To remove options commonly used by customers (e.g. product -XX options), use
 * the 3-step model adding major release numbers to the deprecate, obsolete and expire columns.
 *
 * To remove internal options (e.g. diagnostic, experimental, develop options), use
 * a 2-step model adding major release numbers to the obsolete and expire columns.
 *
 * To change the name of an option, use the alias table as well as a 2-step
 * model adding major release numbers to the deprecate and expire columns.
 * Think twice about aliasing commonly used customer options.
 *
 * There are times when it is appropriate to leave a future release number as undefined.
 *
 * Tests:  Aliases should be tested in VMAliasOptions.java.
 *         Deprecated options should be tested in VMDeprecatedOptions.java.
 */


// The special_jvm_flags table declares options that are being deprecated and/or obsoleted. The
// "deprecated_in" or "obsolete_in" fields may be set to "undefined", but not both.
// When the JDK version reaches 'deprecated_in' limit, the JVM will process this flag on
// the command-line as usual, but will issue a warning.
// When the JDK version reaches 'obsolete_in' limit, the JVM will continue accepting this flag on
// the command-line, while issuing a warning and ignoring the flag value.
// Once the JDK version reaches 'expired_in' limit, the JVM will flatly refuse to admit the
// existence of the flag.
//
// MANUAL CLEANUP ON JDK VERSION UPDATES:
// This table ensures that the handling of options will update automatically when the JDK
// version is incremented, but the source code needs to be cleanup up manually:
// - As "deprecated" options age into "obsolete" or "expired" options, the associated "globals"
//   variable should be removed, as well as users of the variable.
// - As "deprecated" options age into "obsolete" options, move the entry into the
//   "Obsolete Flags" section of the table.
// - All expired options should be removed from the table.
static SpecialFlag const special_jvm_flags[] = {
  // -------------- Deprecated Flags --------------
  // --- Non-alias flags - sorted by obsolete_in then expired_in:
  { "MaxGCMinorPauseMillis",        JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
  { "MaxRAMFraction",               JDK_Version::jdk(10),  JDK_Version::undefined(), JDK_Version::undefined() },
  { "MinRAMFraction",               JDK_Version::jdk(10),  JDK_Version::undefined(), JDK_Version::undefined() },
  { "InitialRAMFraction",           JDK_Version::jdk(10),  JDK_Version::undefined(), JDK_Version::undefined() },
  { "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
  { "FlightRecorder",               JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
  { "DumpSharedSpaces",             JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() },
  { "DynamicDumpSharedSpaces",      JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() },
  { "RequireSharedSpaces",          JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() },
  { "UseSharedSpaces",              JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() },
  { "EnableWaitForParallelLoad",    JDK_Version::jdk(20), JDK_Version::jdk(21), JDK_Version::jdk(22) },

  // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
  { "DefaultMaxRAMFraction",        JDK_Version::jdk(8),  JDK_Version::undefined(), JDK_Version::undefined() },
  { "CreateMinidumpOnCrash",        JDK_Version::jdk(9),  JDK_Version::undefined(), JDK_Version::undefined() },
  { "TLABStats",                    JDK_Version::jdk(12), JDK_Version::undefined(), JDK_Version::undefined() },

  // -------------- Obsolete Flags - sorted by expired_in --------------

  { "ExtendedDTraceProbes",         JDK_Version::jdk(19), JDK_Version::jdk(20), JDK_Version::jdk(21) },
  { "UseContainerCpuShares",        JDK_Version::jdk(19), JDK_Version::jdk(20), JDK_Version::jdk(21) },
  { "PreferContainerQuotaForCPUCount", JDK_Version::jdk(19), JDK_Version::jdk(20), JDK_Version::jdk(21) },
  { "AliasLevel",                   JDK_Version::jdk(19), JDK_Version::jdk(20), JDK_Version::jdk(21) },
  { "UseCodeAging",                 JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::jdk(21) },
  { "PrintSharedDictionary",          JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::jdk(21) },

  { "G1ConcRefinementGreenZone",    JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },
  { "G1ConcRefinementYellowZone",   JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },
  { "G1ConcRefinementRedZone",      JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },
  { "G1ConcRefinementThresholdStep", JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },
  { "G1UseAdaptiveConcRefinement",  JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },
  { "G1ConcRefinementServiceIntervalMillis", JDK_Version::undefined(), JDK_Version::jdk(20), JDK_Version::undefined() },

#ifdef ASSERT
  { "DummyObsoleteTestFlag",        JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() },
#endif

#ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
  // These entries will generate build errors.  Their purpose is to test the macros.
  { "dep > obs",                    JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() },
  { "dep > exp ",                   JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(8) },
  { "obs > exp ",                   JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(8) },
  { "obs > exp",                    JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::jdk(10) },
  { "not deprecated or obsolete",   JDK_Version::undefined(), JDK_Version::undefined(), JDK_Version::jdk(9) },
  { "dup option",                   JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
  { "dup option",                   JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
#endif

  { NULL, JDK_Version(0), JDK_Version(0) }
};

// Flags that are aliases for other flags.
typedef struct {
  const char* alias_name;
  const char* real_name;
} AliasedFlag;

static AliasedFlag const aliased_jvm_flags[] = {
  { "DefaultMaxRAMFraction",    "MaxRAMFraction"    },
  { "CreateMinidumpOnCrash",    "CreateCoredumpOnCrash" },
  { NULL, NULL}
};

// Return true if "v" is less than "other", where "other" may be "undefined".
static bool version_less_than(JDK_Version v, JDK_Version other) {
  assert(!v.is_undefined(), "must be defined");
  if (!other.is_undefined() && v.compare(other) >= 0) {
    return false;
  } else {
    return true;
  }
}

static bool lookup_special_flag(const char *flag_name, SpecialFlag& flag) {
  for (size_t i = 0; special_jvm_flags[i].name != NULL; i++) {
    if ((strcmp(special_jvm_flags[i].name, flag_name) == 0)) {
      flag = special_jvm_flags[i];
      return true;
    }
  }
  return false;
}

bool Arguments::is_obsolete_flag(const char *flag_name, JDK_Version* version) {
  assert(version != NULL, "Must provide a version buffer");
  SpecialFlag flag;
  if (lookup_special_flag(flag_name, flag)) {
    if (!flag.obsolete_in.is_undefined()) {
      if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) {
        *version = flag.obsolete_in;
        // This flag may have been marked for obsoletion in this version, but we may not
        // have actually removed it yet. Rather than ignoring it as soon as we reach
        // this version we allow some time for the removal to happen. So if the flag
        // still actually exists we process it as normal, but issue an adjusted warning.
        const JVMFlag *real_flag = JVMFlag::find_declared_flag(flag_name);
        if (real_flag != NULL) {
          char version_str[256];
          version->to_string(version_str, sizeof(version_str));
          warning("Temporarily processing option %s; support is scheduled for removal in %s",
                  flag_name, version_str);
          return false;
        }
        return true;
      }
    }
  }
  return false;
}

int Arguments::is_deprecated_flag(const char *flag_name, JDK_Version* version) {
  assert(version != NULL, "Must provide a version buffer");
  SpecialFlag flag;
  if (lookup_special_flag(flag_name, flag)) {
    if (!flag.deprecated_in.is_undefined()) {
      if (version_less_than(JDK_Version::current(), flag.obsolete_in) &&
          version_less_than(JDK_Version::current(), flag.expired_in)) {
        *version = flag.deprecated_in;
        return 1;
      } else {
        return -1;
      }
    }
  }
  return 0;
}

const char* Arguments::real_flag_name(const char *flag_name) {
  for (size_t i = 0; aliased_jvm_flags[i].alias_name != NULL; i++) {
    const AliasedFlag& flag_status = aliased_jvm_flags[i];
    if (strcmp(flag_status.alias_name, flag_name) == 0) {
        return flag_status.real_name;
    }
  }
  return flag_name;
}

#ifdef ASSERT
static bool lookup_special_flag(const char *flag_name, size_t skip_index) {
  for (size_t i = 0; special_jvm_flags[i].name != NULL; i++) {
    if ((i != skip_index) && (strcmp(special_jvm_flags[i].name, flag_name) == 0)) {
      return true;
    }
  }
  return false;
}

// Verifies the correctness of the entries in the special_jvm_flags table.
// If there is a semantic error (i.e. a bug in the table) such as the obsoletion
// version being earlier than the deprecation version, then a warning is issued
// and verification fails - by returning false. If it is detected that the table
// is out of date, with respect to the current version, then ideally a warning is
// issued but verification does not fail. This allows the VM to operate when the
// version is first updated, without needing to update all the impacted flags at
// the same time. In practice we can't issue the warning immediately when the version
// is updated as it occurs for every test and some tests are not prepared to handle
// unexpected output - see 8196739. Instead we only check if the table is up-to-date
// if the check_globals flag is true, and in addition allow a grace period and only
// check for stale flags when we hit build 25 (which is far enough into the 6 month
// release cycle that all flag updates should have been processed, whilst still
// leaving time to make the change before RDP2).
// We use a gtest to call this, passing true, so that we can detect stale flags before
// the end of the release cycle.

static const int SPECIAL_FLAG_VALIDATION_BUILD = 25;

bool Arguments::verify_special_jvm_flags(bool check_globals) {
  bool success = true;
  for (size_t i = 0; special_jvm_flags[i].name != NULL; i++) {
    const SpecialFlag& flag = special_jvm_flags[i];
    if (lookup_special_flag(flag.name, i)) {
      warning("Duplicate special flag declaration \"%s\"", flag.name);
      success = false;
    }
    if (flag.deprecated_in.is_undefined() &&
        flag.obsolete_in.is_undefined()) {
      warning("Special flag entry \"%s\" must declare version deprecated and/or obsoleted in.", flag.name);
      success = false;
    }

    if (!flag.deprecated_in.is_undefined()) {
      if (!version_less_than(flag.deprecated_in, flag.obsolete_in)) {
        warning("Special flag entry \"%s\" must be deprecated before obsoleted.", flag.name);
        success = false;
      }

      if (!version_less_than(flag.deprecated_in, flag.expired_in)) {
        warning("Special flag entry \"%s\" must be deprecated before expired.", flag.name);
        success = false;
      }
    }

    if (!flag.obsolete_in.is_undefined()) {
      if (!version_less_than(flag.obsolete_in, flag.expired_in)) {
        warning("Special flag entry \"%s\" must be obsoleted before expired.", flag.name);
        success = false;
      }

      // if flag has become obsolete it should not have a "globals" flag defined anymore.
      if (check_globals && VM_Version::vm_build_number() >= SPECIAL_FLAG_VALIDATION_BUILD &&
          !version_less_than(JDK_Version::current(), flag.obsolete_in)) {
        if (JVMFlag::find_declared_flag(flag.name) != NULL) {
          warning("Global variable for obsolete special flag entry \"%s\" should be removed", flag.name);
          success = false;
        }
      }

    } else if (!flag.expired_in.is_undefined()) {
      warning("Special flag entry \"%s\" must be explicitly obsoleted before expired.", flag.name);
      success = false;
    }

    if (!flag.expired_in.is_undefined()) {
      // if flag has become expired it should not have a "globals" flag defined anymore.
      if (check_globals && VM_Version::vm_build_number() >= SPECIAL_FLAG_VALIDATION_BUILD &&
          !version_less_than(JDK_Version::current(), flag.expired_in)) {
        if (JVMFlag::find_declared_flag(flag.name) != NULL) {
          warning("Global variable for expired flag entry \"%s\" should be removed", flag.name);
          success = false;
        }
      }
    }
  }
  return success;
}
#endif

bool Arguments::atojulong(const char *s, julong* result) {
  return parse_integer(s, result);
}

Arguments::ArgsRange Arguments::check_memory_size(julong size, julong min_size, julong max_size) {
  if (size < min_size) return arg_too_small;
  if (size > max_size) return arg_too_big;
  return arg_in_range;
}

// Describe an argument out of range error
void Arguments::describe_range_error(ArgsRange errcode) {
  switch(errcode) {
  case arg_too_big:
    jio_fprintf(defaultStream::error_stream(),
                "The specified size exceeds the maximum "
                "representable size.\n");
    break;
  case arg_too_small:
  case arg_unreadable:
  case arg_in_range:
    // do nothing for now
    break;
  default:
    ShouldNotReachHere();
  }
}

static bool set_bool_flag(JVMFlag* flag, bool value, JVMFlagOrigin origin) {
  if (JVMFlagAccess::set_bool(flag, &value, origin) == JVMFlag::SUCCESS) {
    return true;
  } else {
    return false;
  }
}

static bool set_fp_numeric_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) {
  // strtod allows leading whitespace, but our flag format does not.
  if (*value == '\0' || isspace(*value)) {
    return false;
  }
  char* end;
  errno = 0;
  double v = strtod(value, &end);
  if ((errno != 0) || (*end != 0)) {
    return false;
  }
  if (g_isnan(v) || !g_isfinite(v)) {
    // Currently we cannot handle these special values.
    return false;
  }

  if (JVMFlagAccess::set_double(flag, &v, origin) == JVMFlag::SUCCESS) {
    return true;
  }
  return false;
}

static bool set_numeric_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) {
  JVMFlag::Error result = JVMFlag::WRONG_FORMAT;

  if (flag->is_int()) {
    int v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_int(flag, &v, origin);
    }
  } else if (flag->is_uint()) {
    uint v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_uint(flag, &v, origin);
    }
  } else if (flag->is_intx()) {
    intx v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_intx(flag, &v, origin);
    }
  } else if (flag->is_uintx()) {
    uintx v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_uintx(flag, &v, origin);
    }
  } else if (flag->is_uint64_t()) {
    uint64_t v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_uint64_t(flag, &v, origin);
    }
  } else if (flag->is_size_t()) {
    size_t v;
    if (parse_integer(value, &v)) {
      result = JVMFlagAccess::set_size_t(flag, &v, origin);
    }
  }

  return result == JVMFlag::SUCCESS;
}

static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) {
  if (value[0] == '\0') {
    value = NULL;
  }
  if (JVMFlagAccess::set_ccstr(flag, &value, origin) != JVMFlag::SUCCESS) return false;
  // Contract:  JVMFlag always returns a pointer that needs freeing.
  FREE_C_HEAP_ARRAY(char, value);
  return true;
}

static bool append_to_string_flag(JVMFlag* flag, const char* new_value, JVMFlagOrigin origin) {
  const char* old_value = "";
  if (JVMFlagAccess::get_ccstr(flag, &old_value) != JVMFlag::SUCCESS) return false;
  size_t old_len = old_value != NULL ? strlen(old_value) : 0;
  size_t new_len = strlen(new_value);
  const char* value;
  char* free_this_too = NULL;
  if (old_len == 0) {
    value = new_value;
  } else if (new_len == 0) {
    value = old_value;
  } else {
     size_t length = old_len + 1 + new_len + 1;
     char* buf = NEW_C_HEAP_ARRAY(char, length, mtArguments);
    // each new setting adds another LINE to the switch:
    jio_snprintf(buf, length, "%s\n%s", old_value, new_value);
    value = buf;
    free_this_too = buf;
  }
  (void) JVMFlagAccess::set_ccstr(flag, &value, origin);
  // JVMFlag always returns a pointer that needs freeing.
  FREE_C_HEAP_ARRAY(char, value);
  // JVMFlag made its own copy, so I must delete my own temp. buffer.
  FREE_C_HEAP_ARRAY(char, free_this_too);
  return true;
}

const char* Arguments::handle_aliases_and_deprecation(const char* arg) {
  const char* real_name = real_flag_name(arg);
  JDK_Version since = JDK_Version();
  switch (is_deprecated_flag(arg, &since)) {
  case -1: {
      // Obsolete or expired, so don't process normally,
      // but allow for an obsolete flag we're still
      // temporarily allowing.
      if (!is_obsolete_flag(arg, &since)) {
        return real_name;
      }
      // Note if we're not considered obsolete then we can't be expired either
      // as obsoletion must come first.
      return NULL;
    }
    case 0:
      return real_name;
    case 1: {
      char version[256];
      since.to_string(version, sizeof(version));
      if (real_name != arg) {
        warning("Option %s was deprecated in version %s and will likely be removed in a future release. Use option %s instead.",
                arg, version, real_name);
      } else {
        warning("Option %s was deprecated in version %s and will likely be removed in a future release.",
                arg, version);
      }
      return real_name;
    }
  }
  ShouldNotReachHere();
  return NULL;
}

#define BUFLEN 255

JVMFlag* Arguments::find_jvm_flag(const char* name, size_t name_length) {
  char name_copied[BUFLEN+1];
  if (name[name_length] != 0) {
    if (name_length > BUFLEN) {
      return NULL;
    } else {
      strncpy(name_copied, name, name_length);
      name_copied[name_length] = '\0';
      name = name_copied;
    }
  }

  const char* real_name = Arguments::handle_aliases_and_deprecation(name);
  if (real_name == NULL) {
    return NULL;
  }
  JVMFlag* flag = JVMFlag::find_flag(real_name);
  return flag;
}

bool Arguments::parse_argument(const char* arg, JVMFlagOrigin origin) {
  bool is_bool = false;
  bool bool_val = false;
  char c = *arg;
  if (c == '+' || c == '-') {
    is_bool = true;
    bool_val = (c == '+');
    arg++;
  }

  const char* name = arg;
  while (true) {
    c = *arg;
    if (isalnum(c) || (c == '_')) {
      ++arg;
    } else {
      break;
    }
  }

  size_t name_len = size_t(arg - name);
  if (name_len == 0) {
    return false;
  }

  JVMFlag* flag = find_jvm_flag(name, name_len);
  if (flag == NULL) {
    return false;
  }

  if (is_bool) {
    if (*arg != 0) {
      // Error -- extra characters such as -XX:+BoolFlag=123
      return false;
    }
    return set_bool_flag(flag, bool_val, origin);
  }

  if (arg[0] == '=') {
    const char* value = arg + 1;
    if (flag->is_ccstr()) {
      if (flag->ccstr_accumulates()) {
        return append_to_string_flag(flag, value, origin);
      } else {
        return set_string_flag(flag, value, origin);
      }
    } else if (flag->is_double()) {
      return set_fp_numeric_flag(flag, value, origin);
    } else {
      return set_numeric_flag(flag, value, origin);
    }
  }

  if (arg[0] == ':' && arg[1] == '=') {
    // -XX:Foo:=xxx will reset the string flag to the given value.
    const char* value = arg + 2;
    return set_string_flag(flag, value, origin);
  }

  return false;
}

void Arguments::add_string(char*** bldarray, int* count, const char* arg) {
  assert(bldarray != NULL, "illegal argument");

  if (arg == NULL) {
    return;
  }

  int new_count = *count + 1;

  // expand the array and add arg to the last element
  if (*bldarray == NULL) {
    *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtArguments);
  } else {
    *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtArguments);
  }
  (*bldarray)[*count] = os::strdup_check_oom(arg);
  *count = new_count;
}

void Arguments::build_jvm_args(const char* arg) {
  add_string(&_jvm_args_array, &_num_jvm_args, arg);
}

void Arguments::build_jvm_flags(const char* arg) {
  add_string(&_jvm_flags_array, &_num_jvm_flags, arg);
}

// utility function to return a string that concatenates all
// strings in a given char** array
const char* Arguments::build_resource_string(char** args, int count) {
  if (args == NULL || count == 0) {
    return NULL;
  }
  size_t length = 0;
  for (int i = 0; i < count; i++) {
    length += strlen(args[i]) + 1; // add 1 for a space or NULL terminating character
  }
  char* s = NEW_RESOURCE_ARRAY(char, length);
  char* dst = s;
  for (int j = 0; j < count; j++) {
    size_t offset = strlen(args[j]) + 1; // add 1 for a space or NULL terminating character
    jio_snprintf(dst, length, "%s ", args[j]); // jio_snprintf will replace the last space character with NULL character
    dst += offset;
    length -= offset;
  }
  return (const char*) s;
}

void Arguments::print_on(outputStream* st) {
  st->print_cr("VM Arguments:");
  if (num_jvm_flags() > 0) {
    st->print("jvm_flags: "); print_jvm_flags_on(st);
    st->cr();
  }
  if (num_jvm_args() > 0) {
    st->print("jvm_args: "); print_jvm_args_on(st);
    st->cr();
  }
  st->print_cr("java_command: %s", java_command() ? java_command() : "");
  if (_java_class_path != NULL) {
    char* path = _java_class_path->value();
    size_t len = strlen(path);
    st->print("java_class_path (initial): ");
    // Avoid using st->print_cr() because path length maybe longer than O_BUFLEN.
    if (len == 0) {
      st->print_raw_cr("");
    } else {
      st->print_raw_cr(path, len);
    }
  }
  st->print_cr("Launcher Type: %s", _sun_java_launcher);
}

void Arguments::print_summary_on(outputStream* st) {
  // Print the command line.  Environment variables that are helpful for
  // reproducing the problem are written later in the hs_err file.
  // flags are from setting file
  if (num_jvm_flags() > 0) {
    st->print_raw("Settings File: ");
    print_jvm_flags_on(st);
    st->cr();
  }
  // args are the command line and environment variable arguments.
  st->print_raw("Command Line: ");
  if (num_jvm_args() > 0) {
    print_jvm_args_on(st);
  }
  // this is the classfile and any arguments to the java program
  if (java_command() != NULL) {
    st->print("%s", java_command());
  }
  st->cr();
}

void Arguments::print_jvm_flags_on(outputStream* st) {
  if (_num_jvm_flags > 0) {
    for (int i=0; i < _num_jvm_flags; i++) {
      st->print("%s ", _jvm_flags_array[i]);
    }
  }
}

void Arguments::print_jvm_args_on(outputStream* st) {
  if (_num_jvm_args > 0) {
    for (int i=0; i < _num_jvm_args; i++) {
      st->print("%s ", _jvm_args_array[i]);
    }
  }
}

bool Arguments::process_argument(const char* arg,
                                 jboolean ignore_unrecognized,
                                 JVMFlagOrigin origin) {
  JDK_Version since = JDK_Version();

  if (parse_argument(arg, origin)) {
    return true;
  }

  // Determine if the flag has '+', '-', or '=' characters.
  bool has_plus_minus = (*arg == '+' || *arg == '-');
  const charconst argname = has_plus_minus ? arg + 1 : arg;

  size_t arg_len;
  const char* equal_sign = strchr(argname, '=');
  if (equal_sign == NULL) {
    arg_len = strlen(argname);
  } else {
    arg_len = equal_sign - argname;
  }

  // Only make the obsolete check for valid arguments.
  if (arg_len <= BUFLEN) {
    // Construct a string which consists only of the argument name without '+', '-', or '='.
    char stripped_argname[BUFLEN+1]; // +1 for '\0'
    jio_snprintf(stripped_argname, arg_len+1, "%s", argname); // +1 for '\0'
    if (is_obsolete_flag(stripped_argname, &since)) {
      char version[256];
      since.to_string(version, sizeof(version));
      warning("Ignoring option %s; support was removed in %s", stripped_argname, version);
      return true;
    }
  }

  // For locked flags, report a custom error message if available.
  // Otherwise, report the standard unrecognized VM option.
  const JVMFlag* found_flag = JVMFlag::find_declared_flag((const char*)argname, arg_len);
  if (found_flag != NULL) {
    char locked_message_buf[BUFLEN];
    JVMFlag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN);
    if (strlen(locked_message_buf) == 0) {
      if (found_flag->is_bool() && !has_plus_minus) {
        jio_fprintf(defaultStream::error_stream(),
          "Missing +/- setting for VM option '%s'\n", argname);
      } else if (!found_flag->is_bool() && has_plus_minus) {
        jio_fprintf(defaultStream::error_stream(),
          "Unexpected +/- setting in VM option '%s'\n", argname);
      } else {
        jio_fprintf(defaultStream::error_stream(),
          "Improperly specified VM option '%s'\n", argname);
      }
    } else {
#ifdef PRODUCT
      bool mismatched = ((msg_type == JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) ||
                         (msg_type == JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD));
      if (ignore_unrecognized && mismatched) {
        return true;
      }
#endif
      jio_fprintf(defaultStream::error_stream(), "%s", locked_message_buf);
    }
  } else {
    if (ignore_unrecognized) {
      return true;
    }
    jio_fprintf(defaultStream::error_stream(),
                "Unrecognized VM option '%s'\n", argname);
    JVMFlag* fuzzy_matched = JVMFlag::fuzzy_match((const char*)argname, arg_len, true);
    if (fuzzy_matched != NULL) {
      jio_fprintf(defaultStream::error_stream(),
                  "Did you mean '%s%s%s'? ",
                  (fuzzy_matched->is_bool()) ? "(+/-)" : "",
                  fuzzy_matched->name(),
                  (fuzzy_matched->is_bool()) ? "" : "=");
    }
  }

  // allow for commandline "commenting out" options like -XX:#+Verbose
  return arg[0] == '#';
}

bool Arguments::process_settings_file(const char* file_name, bool should_exist, jboolean ignore_unrecognized) {
  FILE* stream = os::fopen(file_name, "rb");
  if (stream == NULL) {
    if (should_exist) {
      jio_fprintf(defaultStream::error_stream(),
                  "Could not open settings file %s\n", file_name);
      return false;
    } else {
      return true;
    }
  }

  char token[1024];
  int  pos = 0;

  bool in_white_space = true;
  bool in_comment     = false;
  bool in_quote       = false;
  char quote_c        = 0;
  bool result         = true;

  int c = getc(stream);
  while(c != EOF && pos < (int)(sizeof(token)-1)) {
    if (in_white_space) {
      if (in_comment) {
        if (c == '\n') in_comment = false;
      } else {
        if (c == '#') in_comment = true;
        else if (!isspace(c)) {
          in_white_space = false;
          token[pos++] = c;
        }
      }
    } else {
      if (c == '\n' || (!in_quote && isspace(c))) {
        // token ends at newline, or at unquoted whitespace
        // this allows a way to include spaces in string-valued options
        token[pos] = '\0';
        logOption(token);
        result &= process_argument(token, ignore_unrecognized, JVMFlagOrigin::CONFIG_FILE);
        build_jvm_flags(token);
        pos = 0;
        in_white_space = true;
        in_quote = false;
      } else if (!in_quote && (c == '\'' || c == '"')) {
        in_quote = true;
        quote_c = c;
      } else if (in_quote && (c == quote_c)) {
        in_quote = false;
      } else {
        token[pos++] = c;
      }
    }
    c = getc(stream);
  }
  if (pos > 0) {
    token[pos] = '\0';
    result &= process_argument(token, ignore_unrecognized, JVMFlagOrigin::CONFIG_FILE);
    build_jvm_flags(token);
  }
  fclose(stream);
  return result;
}

//=============================================================================================================
// Parsing of properties (-D)

const char* Arguments::get_property(const char* key) {
  return PropertyList_get_value(system_properties(), key);
}

bool Arguments::add_property(const char* prop, PropertyWriteable writeable, PropertyInternal internal) {
  const char* eq = strchr(prop, '=');
  const char* key;
  const char* value = "";

  if (eq == NULL) {
    // property doesn't have a value, thus use passed string
    key = prop;
  } else {
    // property have a value, thus extract it and save to the
    // allocated string
    size_t key_len = eq - prop;
    char* tmp_key = AllocateHeap(key_len + 1, mtArguments);

    jio_snprintf(tmp_key, key_len + 1, "%s", prop);
    key = tmp_key;

    value = &prop[key_len + 1];
  }

#if INCLUDE_CDS
  if (is_internal_module_property(key) ||
      strcmp(key, "jdk.module.main") == 0) {
    MetaspaceShared::disable_optimized_module_handling();
    log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
  }
  if (strcmp(key, "jdk.module.showModuleResolution") == 0 ||
      strcmp(key, "jdk.module.validation") == 0 ||
      strcmp(key, "java.system.class.loader") == 0) {
    MetaspaceShared::disable_full_module_graph();
    log_info(cds)("full module graph: disabled due to incompatible property: %s=%s"key, value);
  }
#endif

  if (strcmp(key, "java.compiler") == 0) {
    process_java_compiler_argument(value);
    // Record value in Arguments, but let it get passed to Java.
  } else if (strcmp(key, "sun.java.launcher.is_altjvm") == 0) {
    // sun.java.launcher.is_altjvm property is
    // private and is processed in process_sun_java_launcher_properties();
    // the sun.java.launcher property is passed on to the java application
  } else if (strcmp(key, "sun.boot.library.path") == 0) {
    // append is true, writable is true, internal is false
    PropertyList_unique_add(&_system_properties, key, value, AppendProperty,
                            WriteableProperty, ExternalProperty);
  } else {
    if (strcmp(key, "sun.java.command") == 0) {
      char *old_java_command = _java_command;
      _java_command = os::strdup_check_oom(value, mtArguments);
      if (old_java_command != NULL) {
        os::free(old_java_command);
      }
    } else if (strcmp(key, "java.vendor.url.bug") == 0) {
      // If this property is set on the command line then its value will be
      // displayed in VM error logs as the URL at which to submit such logs.
      // Normally the URL displayed in error logs is different from the value
      // of this system property, so a different property should have been
      // used here, but we leave this as-is in case someone depends upon it.
      const char* old_java_vendor_url_bug = _java_vendor_url_bug;
      // save it in _java_vendor_url_bug, so JVM fatal error handler can access
      // its value without going through the property list or making a Java call.
      _java_vendor_url_bug = os::strdup_check_oom(value, mtArguments);
      if (old_java_vendor_url_bug != NULL) {
        os::free((void *)old_java_vendor_url_bug);
      }
    }

    // Create new property and add at the end of the list
    PropertyList_unique_add(&_system_properties, key, value, AddProperty, writeable, internal);
  }

  if (key != prop) {
    // SystemProperty copy passed value, thus free previously allocated
    // memory
    FreeHeap((void *)key);
  }

  return true;
}

#if INCLUDE_CDS
const char* unsupported_properties[] = { "jdk.module.limitmods",
                                         "jdk.module.upgrade.path",
                                         "jdk.module.patch.0" };
const char* unsupported_options[] = { "--limit-modules",
                                      "--upgrade-module-path",
                                      "--patch-module"
                                    };
void Arguments::check_unsupported_dumping_properties() {
  assert(is_dumping_archive(),
         "this function is only used with CDS dump time");
  assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
  // If a vm option is found in the unsupported_options array, vm will exit with an error message.
  SystemProperty* sp = system_properties();
  while (sp != NULL) {
    for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
      if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
        vm_exit_during_initialization(
          "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
      }
    }
    sp = sp->next();
  }

  // Check for an exploded module build in use with -Xshare:dump.
  if (!has_jimage()) {
    vm_exit_during_initialization("Dumping the shared archive is not supported with an exploded module build");
  }
}

bool Arguments::check_unsupported_cds_runtime_properties() {
  assert(UseSharedSpaces, "this function is only used with -Xshare:{on,auto}");
  assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
  if (ArchiveClassesAtExit != NULL) {
    // dynamic dumping, just return false for now.
    // check_unsupported_dumping_properties() will be called later to check the same set of
    // properties, and will exit the VM with the correct error message if the unsupported properties
    // are used.
    return false;
  }
  for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
    if (get_property(unsupported_properties[i]) != NULL) {
      if (RequireSharedSpaces) {
        warning("CDS is disabled when the %s option is specified.", unsupported_options[i]);
      } else {
        log_info(cds)("CDS is disabled when the %s option is specified.", unsupported_options[i]);
      }
      return true;
    }
  }
  return false;
}
#endif

//===========================================================================================================
// Setting int/mixed/comp mode flags

void Arguments::set_mode_flags(Mode mode) {
  // Set up default values for all flags.
  // If you add a flag to any of the branches below,
  // add a default value for it here.
  set_java_compiler(false);
  _mode                      = mode;

  // Ensure Agent_OnLoad has the correct initial values.
  // This may not be the final mode; mode may change later in onload phase.
  PropertyList_unique_add(&_system_properties, "java.vm.info",
                          VM_Version::vm_info_string(), AddProperty, UnwriteableProperty, ExternalProperty);

  UseInterpreter             = true;
  UseCompiler                = true;
  UseLoopCounter             = true;

  // Default values may be platform/compiler dependent -
  // use the saved values
  ClipInlining               = Arguments::_ClipInlining;
  AlwaysCompileLoopMethods   = Arguments::_AlwaysCompileLoopMethods;
  UseOnStackReplacement      = Arguments::_UseOnStackReplacement;
  BackgroundCompilation      = Arguments::_BackgroundCompilation;

  // Change from defaults based on mode
  switch (mode) {
  default:
    ShouldNotReachHere();
    break;
  case _int:
    UseCompiler              = false;
    UseLoopCounter           = false;
    AlwaysCompileLoopMethods = false;
    UseOnStackReplacement    = false;
    break;
  case _mixed:
    // same as default
    break;
  case _comp:
    UseInterpreter           = false;
    BackgroundCompilation    = false;
    ClipInlining             = false;
    break;
  }
}

// Conflict: required to use shared spaces (-Xshare:on), but
// incompatible command line options were chosen.
static void no_shared_spaces(const char* message) {
  if (RequireSharedSpaces) {
    jio_fprintf(defaultStream::error_stream(),
      "Class data sharing is inconsistent with other specified options.\n");
    vm_exit_during_initialization("Unable to use shared archive", message);
  } else {
    log_info(cds)("Unable to use shared archive: %s", message);
    UseSharedSpaces = false;
  }
}

void set_object_alignment() {
  // Object alignment.
  assert(is_power_of_2(ObjectAlignmentInBytes), "ObjectAlignmentInBytes must be power of 2");
  MinObjAlignmentInBytes     = ObjectAlignmentInBytes;
  assert(MinObjAlignmentInBytes >= HeapWordsPerLong * HeapWordSize, "ObjectAlignmentInBytes value is too small");
  MinObjAlignment            = MinObjAlignmentInBytes / HeapWordSize;
  assert(MinObjAlignmentInBytes == MinObjAlignment * HeapWordSize, "ObjectAlignmentInBytes value is incorrect");
  MinObjAlignmentInBytesMask = MinObjAlignmentInBytes - 1;

  LogMinObjAlignmentInBytes  = exact_log2(ObjectAlignmentInBytes);
  LogMinObjAlignment         = LogMinObjAlignmentInBytes - LogHeapWordSize;

  // Oop encoding heap max
  OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes;
}

size_t Arguments::max_heap_for_compressed_oops() {
  // Avoid sign flip.
  assert(OopEncodingHeapMax > (uint64_t)os::vm_page_size(), "Unusual page size");
  // We need to fit both the NULL page and the heap into the memory budget, while
  // keeping alignment constraints of the heap. To guarantee the latter, as the
  // NULL page is located before the heap, we pad the NULL page to the conservative
  // maximum alignment that the GC may ever impose upon the heap.
  size_t displacement_due_to_null_page = align_up((size_t)os::vm_page_size(),
                                                  _conservative_max_heap_alignment);

  LP64_ONLY(return OopEncodingHeapMax - displacement_due_to_null_page);
  NOT_LP64(ShouldNotReachHere(); return 0);
}

void Arguments::set_use_compressed_oops() {
#ifdef _LP64
  // MaxHeapSize is not set up properly at this point, but
  // the only value that can override MaxHeapSize if we are
  // to use UseCompressedOops are InitialHeapSize and MinHeapSize.
  size_t max_heap_size = MAX3(MaxHeapSize, InitialHeapSize, MinHeapSize);

  if (max_heap_size <= max_heap_for_compressed_oops()) {
    if (FLAG_IS_DEFAULT(UseCompressedOops)) {
      FLAG_SET_ERGO(UseCompressedOops, true);
    }
  } else {
    if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
      warning("Max heap size too large for Compressed Oops");
      FLAG_SET_DEFAULT(UseCompressedOops, false);
      if (COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS) {
        FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
      }
    }
  }
#endif // _LP64
}


// NOTE: set_use_compressed_klass_ptrs() must be called after calling
// set_use_compressed_oops().
void Arguments::set_use_compressed_klass_ptrs() {
#ifdef _LP64
  // On some architectures, the use of UseCompressedClassPointers implies the use of
  // UseCompressedOops. The reason is that the rheap_base register of said platforms
  // is reused to perform some optimized spilling, in order to use rheap_base as a
  // temp register. But by treating it as any other temp register, spilling can typically
  // be completely avoided instead. So it is better not to perform this trick. And by
  // not having that reliance, large heaps, or heaps not supporting compressed oops,
  // can still use compressed class pointers.
  if (COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS && !UseCompressedOops) {
    if (UseCompressedClassPointers) {
      warning("UseCompressedClassPointers requires UseCompressedOops");
    }
    FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
  } else {
    // Turn on UseCompressedClassPointers too
    if (FLAG_IS_DEFAULT(UseCompressedClassPointers)) {
      FLAG_SET_ERGO(UseCompressedClassPointers, true);
    }
    // Check the CompressedClassSpaceSize to make sure we use compressed klass ptrs.
    if (UseCompressedClassPointers) {
      if (CompressedClassSpaceSize > KlassEncodingMetaspaceMax) {
        warning("CompressedClassSpaceSize is too large for UseCompressedClassPointers");
        FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
      }
    }
  }
#endif // _LP64
}

void Arguments::set_conservative_max_heap_alignment() {
  // The conservative maximum required alignment for the heap is the maximum of
  // the alignments imposed by several sources: any requirements from the heap
  // itself and the maximum page size we may run the VM with.
  size_t heap_alignment = GCConfig::arguments()->conservative_max_heap_alignment();
  _conservative_max_heap_alignment = MAX4(heap_alignment,
                                          (size_t)os::vm_allocation_granularity(),
                                          os::max_page_size(),
                                          GCArguments::compute_heap_alignment());
}

jint Arguments::set_ergonomics_flags() {
  GCConfig::initialize();

  set_conservative_max_heap_alignment();

#ifdef _LP64
  set_use_compressed_oops();

  // set_use_compressed_klass_ptrs() must be called after calling
  // set_use_compressed_oops().
  set_use_compressed_klass_ptrs();

  // Also checks that certain machines are slower with compressed oops
  // in vm_version initialization code.
#endif // _LP64

  return JNI_OK;
}

size_t Arguments::limit_heap_by_allocatable_memory(size_t limit) {
  size_t max_allocatable;
  size_t result = limit;
  if (os::has_allocatable_memory_limit(&max_allocatable)) {
    // The AggressiveHeap check is a temporary workaround to avoid calling
    // GCarguments::heap_virtual_to_physical_ratio() before a GC has been
    // selected. This works because AggressiveHeap implies UseParallelGC
    // where we know the ratio will be 1. Once the AggressiveHeap option is
    // removed, this can be cleaned up.
    size_t heap_virtual_to_physical_ratio = (AggressiveHeap ? 1 : GCConfig::arguments()->heap_virtual_to_physical_ratio());
    size_t fraction = MaxVirtMemFraction * heap_virtual_to_physical_ratio;
    result = MIN2(result, max_allocatable / fraction);
  }
  return result;
}

// Use static initialization to get the default before parsing
static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress;

void Arguments::set_heap_size() {
  julong phys_mem;

  // If the user specified one of these options, they
  // want specific memory sizing so do not limit memory
  // based on compressed oops addressability.
  // Also, memory limits will be calculated based on
  // available os physical memory, not our MaxRAM limit,
  // unless MaxRAM is also specified.
  bool override_coop_limit = (!FLAG_IS_DEFAULT(MaxRAMPercentage) ||
                           !FLAG_IS_DEFAULT(MaxRAMFraction) ||
                           !FLAG_IS_DEFAULT(MinRAMPercentage) ||
                           !FLAG_IS_DEFAULT(MinRAMFraction) ||
                           !FLAG_IS_DEFAULT(InitialRAMPercentage) ||
                           !FLAG_IS_DEFAULT(InitialRAMFraction) ||
                           !FLAG_IS_DEFAULT(MaxRAM));
  if (override_coop_limit) {
    if (FLAG_IS_DEFAULT(MaxRAM)) {
      phys_mem = os::physical_memory();
      FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem);
    } else {
      phys_mem = (julong)MaxRAM;
    }
  } else {
    phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
                                       : (julong)MaxRAM;
  }


  // Convert deprecated flags
  if (FLAG_IS_DEFAULT(MaxRAMPercentage) &&
      !FLAG_IS_DEFAULT(MaxRAMFraction))
    MaxRAMPercentage = 100.0 / MaxRAMFraction;

  if (FLAG_IS_DEFAULT(MinRAMPercentage) &&
      !FLAG_IS_DEFAULT(MinRAMFraction))
    MinRAMPercentage = 100.0 / MinRAMFraction;

  if (FLAG_IS_DEFAULT(InitialRAMPercentage) &&
      !FLAG_IS_DEFAULT(InitialRAMFraction))
    InitialRAMPercentage = 100.0 / InitialRAMFraction;

  // If the maximum heap size has not been set with -Xmx,
  // then set it as fraction of the size of physical memory,
  // respecting the maximum and minimum sizes of the heap.
  if (FLAG_IS_DEFAULT(MaxHeapSize)) {
    julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
    const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100);
    if (reasonable_min < MaxHeapSize) {
      // Small physical memory, so use a minimum fraction of it for the heap
      reasonable_max = reasonable_min;
    } else {
      // Not-small physical memory, so require a heap at least
      // as large as MaxHeapSize
      reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize);
    }

    if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) {
      // Limit the heap size to ErgoHeapSizeLimit
      reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit);
    }

    reasonable_max = limit_heap_by_allocatable_memory(reasonable_max);

    if (!FLAG_IS_DEFAULT(InitialHeapSize)) {
      // An initial heap size was specified on the command line,
      // so be sure that the maximum size is consistent.  Done
      // after call to limit_heap_by_allocatable_memory because that
      // method might reduce the allocation size.
      reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
    } else if (!FLAG_IS_DEFAULT(MinHeapSize)) {
      reasonable_max = MAX2(reasonable_max, (julong)MinHeapSize);
    }

#ifdef _LP64
    if (UseCompressedOops || UseCompressedClassPointers) {
      // HeapBaseMinAddress can be greater than default but not less than.
      if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) {
        if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) {
          // matches compressed oops printing flags
          log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least " SIZE_FORMAT
                                     " (" SIZE_FORMAT "G) which is greater than value given " SIZE_FORMAT,
                                     DefaultHeapBaseMinAddress,
                                     DefaultHeapBaseMinAddress/G,
                                     HeapBaseMinAddress);
          FLAG_SET_ERGO(HeapBaseMinAddress, DefaultHeapBaseMinAddress);
        }
      }
    }
    if (UseCompressedOops) {
      // Limit the heap size to the maximum possible when using compressed oops
      julong max_coop_heap = (julong)max_heap_for_compressed_oops();

      if (HeapBaseMinAddress + MaxHeapSize < max_coop_heap) {
        // Heap should be above HeapBaseMinAddress to get zero based compressed oops
        // but it should be not less than default MaxHeapSize.
--> --------------------

--> maximum size reached

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

¤ Dauer der Verarbeitung: 0.56 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff



                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik