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 }