1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "jfr/jfrEvents.hpp" 27 #include "memory/allocation.hpp" 28 #include "runtime/flags/jvmFlag.hpp" 29 #include "runtime/flags/jvmFlagAccess.hpp" 30 #include "runtime/flags/jvmFlagLimit.hpp" 31 #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" 32 #include "runtime/os.hpp" 33 #include "utilities/macros.hpp" 34 #include "utilities/ostream.hpp" 35 36 template<typename T, typename EVENT> 37 static void trace_flag_changed(JVMFlag* flag, const T old_value, const T new_value, const JVMFlagOrigin origin) { 38 EVENT e; 39 e.set_name(flag->name()); 40 e.set_oldValue(old_value); 41 e.set_newValue(new_value); 42 e.set_origin(static_cast<u8>(origin)); 43 e.commit(); 44 } 45 46 class FlagAccessImpl { 47 public: 48 JVMFlag::Error set(JVMFlag* flag, void* value, JVMFlagOrigin origin) const { 49 return set_impl(flag, value, origin); 50 } 51 52 virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) const = 0; 53 virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const { return JVMFlag::SUCCESS; } 54 virtual void print_range(outputStream* st, const JVMFlagLimit* range) const { ShouldNotReachHere(); } 55 virtual void print_default_range(outputStream* st) const { ShouldNotReachHere(); } 56 virtual JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const { return JVMFlag::SUCCESS; } 57 }; 58 59 template <typename T, typename EVENT> 60 class TypedFlagAccessImpl : public FlagAccessImpl { 61 62 public: 63 JVMFlag::Error check_constraint_and_set(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin, bool verbose) const { 64 verbose |= (origin == JVMFlagOrigin::ERGONOMIC); 65 T value = *((T*)value_addr); 66 const JVMTypedFlagLimit<T>* constraint = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_constraint(flag); 67 if (constraint != nullptr && constraint->phase() <= JVMFlagLimit::validating_phase()) { 68 JVMFlag::Error err = typed_check_constraint(constraint->constraint_func(), value, verbose); 69 if (err != JVMFlag::SUCCESS) { 70 if (origin == JVMFlagOrigin::ERGONOMIC) { 71 fatal("FLAG_SET_ERGO cannot be used to set an invalid value for %s", flag->name()); 72 } 73 return err; 74 } 75 } 76 77 T old_value = flag->read<T>(); 78 trace_flag_changed<T, EVENT>(flag, old_value, value, origin); 79 flag->write<T>(value); 80 *((T*)value_addr) = old_value; 81 flag->set_origin(origin); 82 83 return JVMFlag::SUCCESS; 84 } 85 86 JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const { 87 return typed_check_constraint(func, flag->read<T>(), verbose); 88 } 89 90 virtual JVMFlag::Error typed_check_constraint(void * func, T value, bool verbose) const = 0; 91 }; 92 93 class FlagAccessImpl_bool : public TypedFlagAccessImpl<bool, EventBooleanFlagChanged> { 94 public: 95 JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const { 96 bool verbose = JVMFlagLimit::verbose_checks_needed(); 97 return TypedFlagAccessImpl<bool, EventBooleanFlagChanged> 98 ::check_constraint_and_set(flag, value_addr, origin, verbose); 99 } 100 101 JVMFlag::Error typed_check_constraint(void* func, bool value, bool verbose) const { 102 return ((JVMFlagConstraintFunc_bool)func)(value, verbose); 103 } 104 }; 105 106 template <typename T, typename EVENT> 107 class RangedFlagAccessImpl : public TypedFlagAccessImpl<T, EVENT> { 108 public: 109 virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const { 110 T value = *((T*)value_addr); 111 bool verbose = JVMFlagLimit::verbose_checks_needed() | (origin == JVMFlagOrigin::ERGONOMIC); 112 113 const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag); 114 if (range != nullptr) { 115 if ((value < range->min()) || (value > range->max())) { 116 range_error(flag->name(), value, range->min(), range->max(), verbose); 117 if (origin == JVMFlagOrigin::ERGONOMIC) { 118 fatal("FLAG_SET_ERGO cannot be used to set an invalid value for %s", flag->name()); 119 } 120 return JVMFlag::OUT_OF_BOUNDS; 121 } 122 } 123 124 return TypedFlagAccessImpl<T, EVENT>::check_constraint_and_set(flag, value_addr, origin, verbose); 125 } 126 127 virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const { 128 const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag); 129 if (range != nullptr) { 130 T value = flag->read<T>(); 131 if ((value < range->min()) || (value > range->max())) { 132 range_error(flag->name(), value, range->min(), range->max(), verbose); 133 return JVMFlag::OUT_OF_BOUNDS; 134 } 135 } 136 return JVMFlag::SUCCESS; 137 } 138 139 virtual void print_range(outputStream* st, const JVMFlagLimit* range) const { 140 const JVMTypedFlagLimit<T>* r = (const JVMTypedFlagLimit<T>*)range; 141 print_range_impl(st, r->min(), r->max()); 142 } 143 144 virtual void range_error(const char* name, T value, T min, T max, bool verbose) const = 0; 145 virtual void print_range_impl(outputStream* st, T min, T max) const = 0; 146 }; 147 148 class FlagAccessImpl_int : public RangedFlagAccessImpl<int, EventIntFlagChanged> { 149 public: 150 void range_error(const char* name, int value, int min, int max, bool verbose) const { 151 JVMFlag::printError(verbose, 152 "int %s=%d is outside the allowed range " 153 "[ %d ... %d ]\n", 154 name, value, min, max); 155 } 156 JVMFlag::Error typed_check_constraint(void* func, int value, bool verbose) const { 157 return ((JVMFlagConstraintFunc_int)func)(value, verbose); 158 } 159 void print_range_impl(outputStream* st, int min, int max) const { 160 st->print("[ %-25d ... %25d ]", min, max); 161 } 162 void print_default_range(outputStream* st) const { 163 st->print("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); 164 } 165 }; 166 167 class FlagAccessImpl_uint : public RangedFlagAccessImpl<uint, EventUnsignedIntFlagChanged> { 168 public: 169 void range_error(const char* name, uint value, uint min, uint max, bool verbose) const { 170 JVMFlag::printError(verbose, 171 "uint %s=%u is outside the allowed range " 172 "[ %u ... %u ]\n", 173 name, value, min, max); 174 } 175 JVMFlag::Error typed_check_constraint(void* func, uint value, bool verbose) const { 176 return ((JVMFlagConstraintFunc_uint)func)(value, verbose); 177 } 178 void print_range_impl(outputStream* st, uint min, uint max) const { 179 st->print("[ %-25u ... %25u ]", min, max); 180 } 181 void print_default_range(outputStream* st) const { 182 st->print("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); 183 } 184 }; 185 186 class FlagAccessImpl_intx : public RangedFlagAccessImpl<intx, EventLongFlagChanged> { 187 public: 188 void range_error(const char* name, intx value, intx min, intx max, bool verbose) const { 189 JVMFlag::printError(verbose, 190 "intx %s=" INTX_FORMAT " is outside the allowed range " 191 "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n", 192 name, value, min, max); 193 } 194 JVMFlag::Error typed_check_constraint(void* func, intx value, bool verbose) const { 195 return ((JVMFlagConstraintFunc_intx)func)(value, verbose); 196 } 197 void print_range_impl(outputStream* st, intx min, intx max) const { 198 st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min, max); 199 } 200 void print_default_range(outputStream* st) const { 201 st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); 202 } 203 }; 204 205 class FlagAccessImpl_uintx : public RangedFlagAccessImpl<uintx, EventUnsignedLongFlagChanged> { 206 public: 207 void range_error(const char* name, uintx value, uintx min, uintx max, bool verbose) const { 208 JVMFlag::printError(verbose, 209 "uintx %s=" UINTX_FORMAT " is outside the allowed range " 210 "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n", 211 name, value, min, max); 212 } 213 JVMFlag::Error typed_check_constraint(void* func, uintx value, bool verbose) const { 214 return ((JVMFlagConstraintFunc_uintx)func)(value, verbose); 215 } 216 void print_range_impl(outputStream* st, uintx min, uintx max) const { 217 st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", min, max); 218 } 219 void print_default_range(outputStream* st) const { 220 st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", uintx(0), max_uintx); 221 } 222 }; 223 224 class FlagAccessImpl_uint64_t : public RangedFlagAccessImpl<uint64_t, EventUnsignedLongFlagChanged> { 225 public: 226 void range_error(const char* name, uint64_t value, uint64_t min, uint64_t max, bool verbose) const { 227 JVMFlag::printError(verbose, 228 "uint64_t %s=" UINT64_FORMAT " is outside the allowed range " 229 "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n", 230 name, value, min, max); 231 } 232 JVMFlag::Error typed_check_constraint(void* func, uint64_t value, bool verbose) const { 233 return ((JVMFlagConstraintFunc_uint64_t)func)(value, verbose); 234 } 235 void print_range_impl(outputStream* st, uint64_t min, uint64_t max) const { 236 st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", min, max); 237 } 238 void print_default_range(outputStream* st) const { 239 st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", uint64_t(0), uint64_t(max_juint)); 240 } 241 }; 242 243 class FlagAccessImpl_size_t : public RangedFlagAccessImpl<size_t, EventUnsignedLongFlagChanged> { 244 public: 245 void range_error(const char* name, size_t value, size_t min, size_t max, bool verbose) const { 246 JVMFlag::printError(verbose, 247 "size_t %s=" SIZE_FORMAT " is outside the allowed range " 248 "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n", 249 name, value, min, max); 250 } 251 JVMFlag::Error typed_check_constraint(void* func, size_t value, bool verbose) const { 252 return ((JVMFlagConstraintFunc_size_t)func)(value, verbose); 253 } 254 void print_range_impl(outputStream* st, size_t min, size_t max) const { 255 st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", min, max); 256 } 257 void print_default_range(outputStream* st) const { 258 st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", size_t(0), size_t(SIZE_MAX)); 259 } 260 }; 261 262 class FlagAccessImpl_double : public RangedFlagAccessImpl<double, EventDoubleFlagChanged> { 263 public: 264 void range_error(const char* name, double value, double min, double max, bool verbose) const { 265 JVMFlag::printError(verbose, 266 "double %s=%f is outside the allowed range " 267 "[ %f ... %f ]\n", 268 name, value, min, max); 269 } 270 JVMFlag::Error typed_check_constraint(void* func, double value, bool verbose) const { 271 return ((JVMFlagConstraintFunc_double)func)(value, verbose); 272 } 273 void print_range_impl(outputStream* st, double min, double max) const { 274 st->print("[ %-25.3f ... %25.3f ]", min, max); 275 } 276 void print_default_range(outputStream* st) const { 277 st->print("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); 278 } 279 }; 280 281 #define FLAG_ACCESS_IMPL_INIT(t) \ 282 static FlagAccessImpl_ ## t flag_access_ ## t; 283 284 #define FLAG_ACCESS_IMPL_ADDR(t) \ 285 &flag_access_ ## t, 286 287 JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_INIT) 288 289 static const FlagAccessImpl* flag_accesss[JVMFlag::NUM_FLAG_TYPES] = { 290 JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_ADDR) 291 // ccstr and ccstrlist have special setter 292 }; 293 294 inline const FlagAccessImpl* JVMFlagAccess::access_impl(const JVMFlag* flag) { 295 int type = flag->type(); 296 int max = (int)(sizeof(flag_accesss)/sizeof(flag_accesss[0])); 297 assert(type >= 0 && type < max , "sanity"); 298 299 return flag_accesss[type]; 300 } 301 302 JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) { 303 if (flag->is_ccstr()) { 304 return set_ccstr(flag, (ccstr*)value, origin); 305 } else { 306 return access_impl(flag)->set(flag, value, origin); 307 } 308 } 309 310 JVMFlag::Error JVMFlagAccess::set_ccstr(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin) { 311 if (flag == nullptr) return JVMFlag::INVALID_FLAG; 312 if (!flag->is_ccstr()) return JVMFlag::WRONG_FORMAT; 313 ccstr old_value = flag->get_ccstr(); 314 trace_flag_changed<ccstr, EventStringFlagChanged>(flag, old_value, *value, origin); 315 char* new_value = nullptr; 316 if (*value != nullptr) { 317 new_value = os::strdup_check_oom(*value); 318 } 319 flag->set_ccstr(new_value); 320 if (!flag->is_default() && old_value != nullptr) { 321 // Old value is heap allocated so free it. 322 FREE_C_HEAP_ARRAY(char, old_value); 323 } 324 // Unlike the other APIs, the old value is NOT returned, so the caller won't need to free it. 325 // The callers typically don't care what the old value is. 326 // If the caller really wants to know the old value, read it (and make a copy if necessary) 327 // before calling this API. 328 *value = nullptr; 329 flag->set_origin(origin); 330 return JVMFlag::SUCCESS; 331 } 332 333 // This is called by the FLAG_SET_XXX macros. 334 JVMFlag::Error JVMFlagAccess::set_or_assert(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin) { 335 JVMFlag* flag = JVMFlag::flag_from_enum(flag_enum); 336 if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) { 337 assert(flag->is_ccstr(), "must be"); 338 return set_ccstr(flag, (ccstr*)value, origin); 339 } else { 340 assert(flag->type() == type_enum, "wrong flag type"); 341 return set_impl(flag, value, origin); 342 } 343 } 344 345 JVMFlag::Error JVMFlagAccess::check_range(const JVMFlag* flag, bool verbose) { 346 return access_impl(flag)->check_range(flag, verbose); 347 } 348 349 JVMFlag::Error JVMFlagAccess::check_constraint(const JVMFlag* flag, void * func, bool verbose) { 350 const int type_enum = flag->type(); 351 if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) { 352 // ccstr and ccstrlist are the same type. 353 return ((JVMFlagConstraintFunc_ccstr)func)(flag->get_ccstr(), verbose); 354 } 355 356 return access_impl(flag)->check_constraint(flag, func, verbose); 357 } 358 359 void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag, const JVMFlagLimit* range) { 360 return access_impl(flag)->print_range(st, range); 361 } 362 363 void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag) { 364 const JVMFlagLimit* range = JVMFlagLimit::get_range(flag); 365 if (range != nullptr) { 366 print_range(st, flag, range); 367 } else { 368 const JVMFlagLimit* limit = JVMFlagLimit::get_constraint(flag); 369 if (limit != nullptr) { 370 void* func = limit->constraint_func(); 371 372 // Two special cases where the lower limit of the range is defined by an os:: function call 373 // and cannot be initialized at compile time with constexpr. 374 if (func == (void*)VMPageSizeConstraintFunc) { 375 uintx min = (uintx)os::vm_page_size(); 376 uintx max = max_uintx; 377 378 JVMTypedFlagLimit<uintx> tmp(0, min, max); 379 access_impl(flag)->print_range(st, &tmp); 380 } else if (func == (void*)NUMAInterleaveGranularityConstraintFunc) { 381 size_t min = os::vm_allocation_granularity(); 382 size_t max = NOT_LP64(2*G) LP64_ONLY(8192*G); 383 384 JVMTypedFlagLimit<size_t> tmp(0, min, max); 385 access_impl(flag)->print_range(st, &tmp); 386 } else { 387 access_impl(flag)->print_default_range(st); 388 } 389 } else { 390 st->print("[ ... ]"); 391 } 392 } 393 }