Path: blob/master/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp
40957 views
/*1* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jfr/jfrEvents.hpp"26#include "memory/allocation.hpp"27#include "runtime/flags/jvmFlag.hpp"28#include "runtime/flags/jvmFlagAccess.hpp"29#include "runtime/flags/jvmFlagLimit.hpp"30#include "runtime/flags/jvmFlagConstraintsRuntime.hpp"31#include "runtime/os.hpp"32#include "utilities/macros.hpp"33#include "utilities/ostream.hpp"3435template<typename T, typename EVENT>36static void trace_flag_changed(JVMFlag* flag, const T old_value, const T new_value, const JVMFlagOrigin origin) {37EVENT e;38e.set_name(flag->name());39e.set_oldValue(old_value);40e.set_newValue(new_value);41e.set_origin(static_cast<u8>(origin));42e.commit();43}4445class FlagAccessImpl {46public:47JVMFlag::Error set(JVMFlag* flag, void* value, JVMFlagOrigin origin) const {48return set_impl(flag, value, origin);49}5051virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) const = 0;52virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const { return JVMFlag::SUCCESS; }53virtual void print_range(outputStream* st, const JVMFlagLimit* range) const { ShouldNotReachHere(); }54virtual void print_default_range(outputStream* st) const { ShouldNotReachHere(); }55virtual JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const { return JVMFlag::SUCCESS; }56};5758template <typename T, typename EVENT>59class TypedFlagAccessImpl : public FlagAccessImpl {6061public:62JVMFlag::Error check_constraint_and_set(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin, bool verbose) const {63T value = *((T*)value_addr);64const JVMTypedFlagLimit<T>* constraint = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_constraint(flag);65if (constraint != NULL && constraint->phase() <= static_cast<int>(JVMFlagLimit::validating_phase())) {66JVMFlag::Error err = typed_check_constraint(constraint->constraint_func(), value, verbose);67if (err != JVMFlag::SUCCESS) {68return err;69}70}7172T old_value = flag->read<T>();73trace_flag_changed<T, EVENT>(flag, old_value, value, origin);74flag->write<T>(value);75*((T*)value_addr) = old_value;76flag->set_origin(origin);7778return JVMFlag::SUCCESS;79}8081JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const {82return typed_check_constraint(func, flag->read<T>(), verbose);83}8485virtual JVMFlag::Error typed_check_constraint(void * func, T value, bool verbose) const = 0;86};8788class FlagAccessImpl_bool : public TypedFlagAccessImpl<bool, EventBooleanFlagChanged> {89public:90JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const {91bool verbose = JVMFlagLimit::verbose_checks_needed();92return TypedFlagAccessImpl<bool, EventBooleanFlagChanged>93::check_constraint_and_set(flag, value_addr, origin, verbose);94}9596JVMFlag::Error typed_check_constraint(void* func, bool value, bool verbose) const {97return ((JVMFlagConstraintFunc_bool)func)(value, verbose);98}99};100101template <typename T, typename EVENT>102class RangedFlagAccessImpl : public TypedFlagAccessImpl<T, EVENT> {103public:104virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const {105T value = *((T*)value_addr);106bool verbose = JVMFlagLimit::verbose_checks_needed();107108const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag);109if (range != NULL) {110if ((value < range->min()) || (value > range->max())) {111range_error(flag->name(), value, range->min(), range->max(), verbose);112return JVMFlag::OUT_OF_BOUNDS;113}114}115116return TypedFlagAccessImpl<T, EVENT>::check_constraint_and_set(flag, value_addr, origin, verbose);117}118119virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const {120const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag);121if (range != NULL) {122T value = flag->read<T>();123if ((value < range->min()) || (value > range->max())) {124range_error(flag->name(), value, range->min(), range->max(), verbose);125return JVMFlag::OUT_OF_BOUNDS;126}127}128return JVMFlag::SUCCESS;129}130131virtual void print_range(outputStream* st, const JVMFlagLimit* range) const {132const JVMTypedFlagLimit<T>* r = (const JVMTypedFlagLimit<T>*)range;133print_range_impl(st, r->min(), r->max());134}135136virtual void range_error(const char* name, T value, T min, T max, bool verbose) const = 0;137virtual void print_range_impl(outputStream* st, T min, T max) const = 0;138};139140class FlagAccessImpl_int : public RangedFlagAccessImpl<int, EventIntFlagChanged> {141public:142void range_error(const char* name, int value, int min, int max, bool verbose) const {143JVMFlag::printError(verbose,144"int %s=%d is outside the allowed range "145"[ %d ... %d ]\n",146name, value, min, max);147}148JVMFlag::Error typed_check_constraint(void* func, int value, bool verbose) const {149return ((JVMFlagConstraintFunc_int)func)(value, verbose);150}151void print_range_impl(outputStream* st, int min, int max) const {152st->print("[ %-25d ... %25d ]", min, max);153}154void print_default_range(outputStream* st) const {155st->print("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX);156}157};158159class FlagAccessImpl_uint : public RangedFlagAccessImpl<uint, EventUnsignedIntFlagChanged> {160public:161void range_error(const char* name, uint value, uint min, uint max, bool verbose) const {162JVMFlag::printError(verbose,163"uint %s=%u is outside the allowed range "164"[ %u ... %u ]\n",165name, value, min, max);166}167JVMFlag::Error typed_check_constraint(void* func, uint value, bool verbose) const {168return ((JVMFlagConstraintFunc_uint)func)(value, verbose);169}170void print_range_impl(outputStream* st, uint min, uint max) const {171st->print("[ %-25u ... %25u ]", min, max);172}173void print_default_range(outputStream* st) const {174st->print("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX);175}176};177178class FlagAccessImpl_intx : public RangedFlagAccessImpl<intx, EventLongFlagChanged> {179public:180void range_error(const char* name, intx value, intx min, intx max, bool verbose) const {181JVMFlag::printError(verbose,182"intx %s=" INTX_FORMAT " is outside the allowed range "183"[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n",184name, value, min, max);185}186JVMFlag::Error typed_check_constraint(void* func, intx value, bool verbose) const {187return ((JVMFlagConstraintFunc_intx)func)(value, verbose);188}189void print_range_impl(outputStream* st, intx min, intx max) const {190st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min, max);191}192void print_default_range(outputStream* st) const {193st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx);194}195};196197class FlagAccessImpl_uintx : public RangedFlagAccessImpl<uintx, EventUnsignedLongFlagChanged> {198public:199void range_error(const char* name, uintx value, uintx min, uintx max, bool verbose) const {200JVMFlag::printError(verbose,201"uintx %s=" UINTX_FORMAT " is outside the allowed range "202"[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n",203name, value, min, max);204}205JVMFlag::Error typed_check_constraint(void* func, uintx value, bool verbose) const {206return ((JVMFlagConstraintFunc_uintx)func)(value, verbose);207}208void print_range_impl(outputStream* st, uintx min, uintx max) const {209st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", min, max);210}211void print_default_range(outputStream* st) const {212st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", uintx(0), max_uintx);213}214};215216class FlagAccessImpl_uint64_t : public RangedFlagAccessImpl<uint64_t, EventUnsignedLongFlagChanged> {217public:218void range_error(const char* name, uint64_t value, uint64_t min, uint64_t max, bool verbose) const {219JVMFlag::printError(verbose,220"uint64_t %s=" UINT64_FORMAT " is outside the allowed range "221"[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n",222name, value, min, max);223}224JVMFlag::Error typed_check_constraint(void* func, uint64_t value, bool verbose) const {225return ((JVMFlagConstraintFunc_uint64_t)func)(value, verbose);226}227void print_range_impl(outputStream* st, uint64_t min, uint64_t max) const {228st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", min, max);229}230void print_default_range(outputStream* st) const {231st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", uint64_t(0), uint64_t(max_juint));232}233};234235class FlagAccessImpl_size_t : public RangedFlagAccessImpl<size_t, EventUnsignedLongFlagChanged> {236public:237void range_error(const char* name, size_t value, size_t min, size_t max, bool verbose) const {238JVMFlag::printError(verbose,239"size_t %s=" SIZE_FORMAT " is outside the allowed range "240"[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n",241name, value, min, max);242}243JVMFlag::Error typed_check_constraint(void* func, size_t value, bool verbose) const {244return ((JVMFlagConstraintFunc_size_t)func)(value, verbose);245}246void print_range_impl(outputStream* st, size_t min, size_t max) const {247st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", min, max);248}249void print_default_range(outputStream* st) const {250st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", size_t(0), size_t(SIZE_MAX));251}252};253254class FlagAccessImpl_double : public RangedFlagAccessImpl<double, EventDoubleFlagChanged> {255public:256void range_error(const char* name, double value, double min, double max, bool verbose) const {257JVMFlag::printError(verbose,258"double %s=%f is outside the allowed range "259"[ %f ... %f ]\n",260name, value, min, max);261}262JVMFlag::Error typed_check_constraint(void* func, double value, bool verbose) const {263return ((JVMFlagConstraintFunc_double)func)(value, verbose);264}265void print_range_impl(outputStream* st, double min, double max) const {266st->print("[ %-25.3f ... %25.3f ]", min, max);267}268void print_default_range(outputStream* st) const {269st->print("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX);270}271};272273#define FLAG_ACCESS_IMPL_INIT(t) \274static FlagAccessImpl_ ## t flag_access_ ## t;275276#define FLAG_ACCESS_IMPL_ADDR(t) \277&flag_access_ ## t,278279JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_INIT)280281static const FlagAccessImpl* flag_accesss[JVMFlag::NUM_FLAG_TYPES] = {282JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_ADDR)283// ccstr and ccstrlist have special setter284};285286inline const FlagAccessImpl* JVMFlagAccess::access_impl(const JVMFlag* flag) {287int type = flag->type();288int max = (int)(sizeof(flag_accesss)/sizeof(flag_accesss[0]));289assert(type >= 0 && type < max , "sanity");290291return flag_accesss[type];292}293294JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) {295if (flag->is_ccstr()) {296return set_ccstr(flag, (ccstr*)value, origin);297} else {298return access_impl(flag)->set(flag, value, origin);299}300}301302JVMFlag::Error JVMFlagAccess::set_ccstr(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin) {303if (flag == NULL) return JVMFlag::INVALID_FLAG;304if (!flag->is_ccstr()) return JVMFlag::WRONG_FORMAT;305ccstr old_value = flag->get_ccstr();306trace_flag_changed<ccstr, EventStringFlagChanged>(flag, old_value, *value, origin);307char* new_value = NULL;308if (*value != NULL) {309new_value = os::strdup_check_oom(*value);310}311flag->set_ccstr(new_value);312if (!flag->is_default() && old_value != NULL) {313// Old value is heap allocated so free it.314FREE_C_HEAP_ARRAY(char, old_value);315}316// Unlike the other APIs, the old vale is NOT returned, so the caller won't need to free it.317// The callers typically don't care what the old value is.318// If the caller really wants to know the old value, read it (and make a copy if necessary)319// before calling this API.320*value = NULL;321flag->set_origin(origin);322return JVMFlag::SUCCESS;323}324325// This is called by the FLAG_SET_XXX macros.326JVMFlag::Error JVMFlagAccess::set_or_assert(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin) {327JVMFlag* flag = JVMFlag::flag_from_enum(flag_enum);328if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) {329assert(flag->is_ccstr(), "must be");330return set_ccstr(flag, (ccstr*)value, origin);331} else {332assert(flag->type() == type_enum, "wrong flag type");333return set_impl(flag, value, origin);334}335}336337JVMFlag::Error JVMFlagAccess::check_range(const JVMFlag* flag, bool verbose) {338return access_impl(flag)->check_range(flag, verbose);339}340341JVMFlag::Error JVMFlagAccess::check_constraint(const JVMFlag* flag, void * func, bool verbose) {342const int type_enum = flag->type();343if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) {344// ccstr and ccstrlist are the same type.345return ((JVMFlagConstraintFunc_ccstr)func)(flag->get_ccstr(), verbose);346}347348return access_impl(flag)->check_constraint(flag, func, verbose);349}350351void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag, const JVMFlagLimit* range) {352return access_impl(flag)->print_range(st, range);353}354355void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag) {356const JVMFlagLimit* range = JVMFlagLimit::get_range(flag);357if (range != NULL) {358print_range(st, flag, range);359} else {360const JVMFlagLimit* limit = JVMFlagLimit::get_constraint(flag);361if (limit != NULL) {362void* func = limit->constraint_func();363364// Two special cases where the lower limit of the range is defined by an os:: function call365// and cannot be initialized at compile time with constexpr.366if (func == (void*)VMPageSizeConstraintFunc) {367uintx min = (uintx)os::vm_page_size();368uintx max = max_uintx;369370JVMTypedFlagLimit<uintx> tmp(0, min, max);371access_impl(flag)->print_range(st, &tmp);372} else if (func == (void*)NUMAInterleaveGranularityConstraintFunc) {373size_t min = os::vm_allocation_granularity();374size_t max = NOT_LP64(2*G) LP64_ONLY(8192*G);375376JVMTypedFlagLimit<size_t> tmp(0, min, max);377access_impl(flag)->print_range(st, &tmp);378} else {379access_impl(flag)->print_default_range(st);380}381} else {382st->print("[ ... ]");383}384}385}386387388