blob: 1c3f9a70c0a861ac66d08cafaa49079d64215720 [file] [log] [blame]
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_RUNTIME_FLAGS_JVMFLAG_HPP
#define SHARE_RUNTIME_FLAGS_JVMFLAG_HPP
#include "utilities/globalDefinitions.hpp"
#include "utilities/enumIterator.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmEnums.hpp"
#include <type_traits>
class outputStream;
enum class JVMFlagOrigin : int {
// This is the value returned by JVMFlag::get_origin(). It records who
// has most recently changed the value of a JVMFlag. DEFAULT means that the
// flag was never changed, or was most recently changed by FLAG_SET_DEFAULT.
DEFAULT = 0,
COMMAND_LINE = 1,
ENVIRON_VAR = 2,
CONFIG_FILE = 3,
MANAGEMENT = 4,
ERGONOMIC = 5,
ATTACH_ON_DEMAND = 6,
INTERNAL = 7,
JIMAGE_RESOURCE = 8,
};
ENUMERATOR_RANGE(JVMFlagOrigin, JVMFlagOrigin::DEFAULT, JVMFlagOrigin::JIMAGE_RESOURCE)
class JVMFlag {
friend class VMStructs;
public:
enum Flags : int {
VALUE_ORIGIN_BITS = 4,
VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS),
// flag kind
KIND_PRODUCT = 1 << 4,
KIND_MANAGEABLE = 1 << 5,
KIND_DIAGNOSTIC = 1 << 6,
KIND_EXPERIMENTAL = 1 << 7,
KIND_NOT_PRODUCT = 1 << 8,
KIND_DEVELOP = 1 << 9,
KIND_PLATFORM_DEPENDENT = 1 << 10,
KIND_C1 = 1 << 11,
KIND_C2 = 1 << 12,
KIND_ARCH = 1 << 13,
KIND_LP64_PRODUCT = 1 << 14,
KIND_JVMCI = 1 << 15,
// Note the difference:
// f->get_origin() == COMMAND_LINE
// f was mostly recently set by the command-line
// f->_flags & WAS_SET_ON_COMMAND_LINE
// f was specified on the command-line (but may have since been updated by
// someone else like FLAG_SET_ERGO)
WAS_SET_ON_COMMAND_LINE = 1 << 17,
KIND_MASK = ~(VALUE_ORIGIN_MASK | WAS_SET_ON_COMMAND_LINE)
};
enum Error {
// no error
SUCCESS = 0,
// flag name is missing
MISSING_NAME,
// flag value is missing
MISSING_VALUE,
// error parsing the textual form of the value
WRONG_FORMAT,
// flag is not writable
NON_WRITABLE,
// flag value is outside of its bounds
OUT_OF_BOUNDS,
// flag value violates its constraint
VIOLATES_CONSTRAINT,
// there is no flag with the given name
INVALID_FLAG,
// the flag can only be set only on command line during invocation of the VM
COMMAND_LINE_ONLY,
// the flag may only be set once
SET_ONLY_ONCE,
// the flag is not writable in this combination of product/debug build
CONSTANT,
// other, unspecified error related to setting the flag
ERR_OTHER
};
enum MsgType {
NONE = 0,
DIAGNOSTIC_FLAG_BUT_LOCKED,
EXPERIMENTAL_FLAG_BUT_LOCKED,
DEVELOPER_FLAG_BUT_PRODUCT_BUILD,
NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD
};
#define JVM_FLAG_NON_STRING_TYPES_DO(f) \
f(bool) \
f(int) \
f(uint) \
f(intx) \
f(uintx) \
f(uint64_t) \
f(size_t) \
f(double)
#define JVM_FLAG_TYPE_DECLARE(t) \
TYPE_ ## t,
enum FlagType : int {
JVM_FLAG_NON_STRING_TYPES_DO(JVM_FLAG_TYPE_DECLARE)
// The two string types are a bit irregular: is_ccstr() returns true for both types.
TYPE_ccstr,
TYPE_ccstrlist,
NUM_FLAG_TYPES
};
private:
void* _addr;
const char* _name;
Flags _flags;
int _type;
NOT_PRODUCT(const char* _doc;)
public:
// points to all Flags static array
static JVMFlag* flags;
// number of flags
static size_t numFlags;
private:
static JVMFlag* find_flag(const char* name, size_t length, bool allow_locked, bool return_flag);
public:
constexpr JVMFlag() : _addr(), _name(), _flags(), _type() NOT_PRODUCT(COMMA _doc()) {}
constexpr JVMFlag(int flag_enum, FlagType type, const char* name,
void* addr, int flags, int extra_flags, const char* doc);
constexpr JVMFlag(int flag_enum, FlagType type, const char* name,
void* addr, int flags, const char* doc);
static JVMFlag* find_flag(const char* name) {
return find_flag(name, strlen(name), false, false);
}
static JVMFlag* find_declared_flag(const char* name, size_t length) {
return find_flag(name, length, true, true);
}
static JVMFlag* find_declared_flag(const char* name) {
return find_declared_flag(name, strlen(name));
}
static JVMFlag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
static void assert_valid_flag_enum(JVMFlagsEnum i) NOT_DEBUG_RETURN;
static void check_all_flag_declarations() NOT_DEBUG_RETURN;
inline JVMFlagsEnum flag_enum() const {
JVMFlagsEnum i = static_cast<JVMFlagsEnum>(this - JVMFlag::flags);
assert_valid_flag_enum(i);
return i;
}
static JVMFlag* flag_from_enum(JVMFlagsEnum flag_enum) {
assert_valid_flag_enum(flag_enum);
return &JVMFlag::flags[flag_enum];
}
#define JVM_FLAG_TYPE_ACCESSOR(t) \
bool is_##t() const { return _type == TYPE_##t;} \
t get_##t() const { assert(is_##t(), "sanity"); return *((t*) _addr); }
JVM_FLAG_NON_STRING_TYPES_DO(JVM_FLAG_TYPE_ACCESSOR)
bool is_ccstr() const { return _type == TYPE_ccstr || _type == TYPE_ccstrlist; }
bool ccstr_accumulates() const { return _type == TYPE_ccstrlist; }
ccstr get_ccstr() const { assert(is_ccstr(), "sanity"); return *((ccstr*) _addr); }
void set_ccstr(ccstr value) { assert(is_ccstr(), "sanity"); *((ccstr*) _addr) = value; }
#define JVM_FLAG_AS_STRING(t) \
case TYPE_##t: return STR(t);
const char* type_string() const {
return type_string_for((FlagType)_type);
}
static const char* type_string_for(FlagType t) {
switch(t) {
JVM_FLAG_NON_STRING_TYPES_DO(JVM_FLAG_AS_STRING)
case TYPE_ccstr: return "ccstr";
case TYPE_ccstrlist: return "ccstrlist";
default:
ShouldNotReachHere();
return "unknown";
}
}
int type() const { return _type; }
const char* name() const { return _name; }
// Do not use JVMFlag::read() or JVMFlag::write() directly unless you know
// what you're doing. Use FLAG_SET_XXX macros or JVMFlagAccess instead.
template <typename T> T read() const {
assert_compatible_type<T>(_type);
return *static_cast<T*>(_addr);
}
template <typename T> void write(T value) {
assert_compatible_type<T>(_type);
*static_cast<T*>(_addr) = value;
}
JVMFlagOrigin get_origin() const { return JVMFlagOrigin(_flags & VALUE_ORIGIN_MASK); }
void set_origin(JVMFlagOrigin origin);
bool is_default() const { return (get_origin() == JVMFlagOrigin::DEFAULT); }
bool is_ergonomic() const { return (get_origin() == JVMFlagOrigin::ERGONOMIC); }
bool is_command_line() const { return (_flags & WAS_SET_ON_COMMAND_LINE) != 0; }
void set_command_line() { _flags = Flags(_flags | WAS_SET_ON_COMMAND_LINE); }
bool is_jimage_resource() const { return (get_origin() == JVMFlagOrigin::JIMAGE_RESOURCE); }
bool is_product() const { return (_flags & KIND_PRODUCT) != 0; }
bool is_manageable() const { return (_flags & KIND_MANAGEABLE) != 0; }
bool is_diagnostic() const { return (_flags & KIND_DIAGNOSTIC) != 0; }
bool is_experimental() const { return (_flags & KIND_EXPERIMENTAL) != 0; }
bool is_notproduct() const { return (_flags & KIND_NOT_PRODUCT) != 0; }
bool is_develop() const { return (_flags & KIND_DEVELOP) != 0; }
bool is_constant_in_binary() const;
bool is_unlocker() const;
bool is_unlocked() const;
// Only manageable flags can be accessed by writeableFlags.cpp
bool is_writeable() const { return is_manageable(); }
// All flags except "manageable" are assumed to be internal flags.
bool is_external() const { return is_manageable(); }
void clear_diagnostic();
void clear_experimental();
void set_product();
JVMFlag::MsgType get_locked_message(char*, int) const;
static bool is_default(JVMFlagsEnum flag);
static bool is_ergo(JVMFlagsEnum flag);
static bool is_cmdline(JVMFlagsEnum flag);
static bool is_jimage_resource(JVMFlagsEnum flag);
static void setOnCmdLine(JVMFlagsEnum flag);
// printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges
void print_on(outputStream* st, bool withComments = false, bool printRanges = false) const;
void print_kind(outputStream* st, unsigned int width) const;
void print_origin(outputStream* st, unsigned int width) const;
void print_as_flag(outputStream* st) const;
private:
// type checking - the following functions make sure you access *_addr as
// the correct type <T>
static void assert_valid_type_enum(int type_enum) {
assert(0 <= type_enum && type_enum < NUM_FLAG_TYPES, "sanity");
}
// The following computation is not universal, but should be correct
// for the limited number of types that can be stored inside a JVMFlag.
template <typename T>
static constexpr int type_signature() {
return int(sizeof(T)) |
(((std::is_integral<T>::value) ? 1 : 0) << 8) |
(((std::is_signed<T>::value) ? 1 : 0) << 9) |
(((std::is_pointer<T>::value) ? 1 : 0) << 10);
}
static const int type_signatures[];
public:
template <typename T>
static void assert_compatible_type(int type_enum) {
assert(is_compatible_type<T>(type_enum), "must be");
}
template <typename T>
static bool is_compatible_type(int type_enum) {
assert_valid_type_enum(type_enum);
return type_signatures[type_enum] == type_signature<T>();
}
public:
static void printSetFlags(outputStream* out);
// printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges
static void printFlags(outputStream* out, bool withComments, bool printRanges = false, bool skipDefaults = false);
static void printError(bool verbose, const char* msg, ...) ATTRIBUTE_PRINTF(2, 3);
static void verify() PRODUCT_RETURN;
};
#define DECLARE_CONSTRAINT(type, func) JVMFlag::Error func(type value, bool verbose);
#endif // SHARE_RUNTIME_FLAGS_JVMFLAG_HPP