1 /*
2  * Copyright (c) 2020, 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 "utilities/macros.hpp"
33 #include "utilities/ostream.hpp"
34 
35 template<typename T, typename EVENT>
trace_flag_changed(JVMFlag * flag,const T old_value,const T new_value,const JVMFlagOrigin origin)36 static void trace_flag_changed(JVMFlag* flag, const T old_value, const T new_value, const JVMFlagOrigin origin) {
37   EVENT e;
38   e.set_name(flag->name());
39   e.set_oldValue(old_value);
40   e.set_newValue(new_value);
41   e.set_origin(static_cast<u8>(origin));
42   e.commit();
43 }
44 
45 class FlagAccessImpl {
46 public:
set(JVMFlag * flag,void * value,JVMFlagOrigin origin) const47   JVMFlag::Error set(JVMFlag* flag, void* value, JVMFlagOrigin origin) const {
48     return set_impl(flag, value, origin);
49   }
50 
51   virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) const = 0;
check_range(const JVMFlag * flag,bool verbose) const52   virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const { return JVMFlag::SUCCESS; }
print_range(outputStream * st,const JVMFlagLimit * range) const53   virtual void print_range(outputStream* st, const JVMFlagLimit* range) const { ShouldNotReachHere(); }
print_default_range(outputStream * st) const54   virtual void print_default_range(outputStream* st) const { ShouldNotReachHere(); }
check_constraint(const JVMFlag * flag,void * func,bool verbose) const55   virtual JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const  { return JVMFlag::SUCCESS; }
56 };
57 
58 template <typename T, int type_enum, typename EVENT>
59 class TypedFlagAccessImpl : public FlagAccessImpl {
60 
61 public:
check_constraint_and_set(JVMFlag * flag,void * value_addr,JVMFlagOrigin origin,bool verbose) const62   JVMFlag::Error check_constraint_and_set(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin, bool verbose) const {
63     T value = *((T*)value_addr);
64     const JVMTypedFlagLimit<T>* constraint = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_constraint(flag);
65     if (constraint != NULL && constraint->phase() <= static_cast<int>(JVMFlagLimit::validating_phase())) {
66       JVMFlag::Error err = typed_check_constraint(constraint->constraint_func(), value, verbose);
67       if (err != JVMFlag::SUCCESS) {
68         return err;
69       }
70     }
71 
72     T old_value = flag->read<T, type_enum>();
73     trace_flag_changed<T, EVENT>(flag, old_value, value, origin);
74     flag->write<T, type_enum>(value);
75     *((T*)value_addr) = old_value;
76     flag->set_origin(origin);
77 
78     return JVMFlag::SUCCESS;
79   }
80 
check_constraint(const JVMFlag * flag,void * func,bool verbose) const81   JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose) const  {
82     return typed_check_constraint(func, flag->read<T, type_enum>(), verbose);
83   }
84 
85   virtual JVMFlag::Error typed_check_constraint(void * func, T value, bool verbose) const = 0;
86 };
87 
88 class FlagAccessImpl_bool : public TypedFlagAccessImpl<JVM_FLAG_TYPE(bool), EventBooleanFlagChanged> {
89 public:
set_impl(JVMFlag * flag,void * value_addr,JVMFlagOrigin origin) const90   JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const {
91     bool verbose = JVMFlagLimit::verbose_checks_needed();
92     return TypedFlagAccessImpl<JVM_FLAG_TYPE(bool), EventBooleanFlagChanged>
93                ::check_constraint_and_set(flag, value_addr, origin, verbose);
94   }
95 
typed_check_constraint(void * func,bool value,bool verbose) const96   JVMFlag::Error typed_check_constraint(void* func, bool value, bool verbose) const {
97     return ((JVMFlagConstraintFunc_bool)func)(value, verbose);
98   }
99 };
100 
101 template <typename T, int type_enum, typename EVENT>
102 class RangedFlagAccessImpl : public TypedFlagAccessImpl<T, type_enum, EVENT> {
103 public:
set_impl(JVMFlag * flag,void * value_addr,JVMFlagOrigin origin) const104   virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const {
105     T value = *((T*)value_addr);
106     bool verbose = JVMFlagLimit::verbose_checks_needed();
107 
108     const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag);
109     if (range != NULL) {
110       if ((value < range->min()) || (value > range->max())) {
111         range_error(flag->name(), value, range->min(), range->max(), verbose);
112         return JVMFlag::OUT_OF_BOUNDS;
113       }
114     }
115 
116     return TypedFlagAccessImpl<T, type_enum, EVENT>::check_constraint_and_set(flag, value_addr, origin, verbose);
117   }
118 
check_range(const JVMFlag * flag,bool verbose) const119   virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const {
120     const JVMTypedFlagLimit<T>* range = (const JVMTypedFlagLimit<T>*)JVMFlagLimit::get_range(flag);
121     if (range != NULL) {
122       T value = flag->read<T, type_enum>();
123       if ((value < range->min()) || (value > range->max())) {
124         range_error(flag->name(), value, range->min(), range->max(), verbose);
125         return JVMFlag::OUT_OF_BOUNDS;
126       }
127     }
128     return JVMFlag::SUCCESS;
129   }
130 
print_range(outputStream * st,const JVMFlagLimit * range) const131   virtual void print_range(outputStream* st, const JVMFlagLimit* range) const {
132     const JVMTypedFlagLimit<T>* r = (const JVMTypedFlagLimit<T>*)range;
133     print_range_impl(st, r->min(), r->max());
134   }
135 
136   virtual void range_error(const char* name, T value, T min, T max, bool verbose) const = 0;
137   virtual void print_range_impl(outputStream* st, T min, T max) const = 0;
138 };
139 
140 class FlagAccessImpl_int : public RangedFlagAccessImpl<JVM_FLAG_TYPE(int), EventIntFlagChanged> {
141 public:
range_error(const char * name,int value,int min,int max,bool verbose) const142   void range_error(const char* name, int value, int min, int max, bool verbose) const {
143     JVMFlag::printError(verbose,
144                         "int %s=%d is outside the allowed range "
145                         "[ %d ... %d ]\n",
146                         name, value, min, max);
147   }
typed_check_constraint(void * func,int value,bool verbose) const148   JVMFlag::Error typed_check_constraint(void* func, int value, bool verbose) const {
149     return ((JVMFlagConstraintFunc_int)func)(value, verbose);
150   }
print_range_impl(outputStream * st,int min,int max) const151   void print_range_impl(outputStream* st, int min, int max) const {
152     st->print("[ %-25d ... %25d ]", min, max);
153   }
print_default_range(outputStream * st) const154   void print_default_range(outputStream* st) const {
155     st->print("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX);
156   }
157 };
158 
159 class FlagAccessImpl_uint : public RangedFlagAccessImpl<JVM_FLAG_TYPE(uint), EventUnsignedIntFlagChanged> {
160 public:
range_error(const char * name,uint value,uint min,uint max,bool verbose) const161   void range_error(const char* name, uint value, uint min, uint max, bool verbose) const {
162     JVMFlag::printError(verbose,
163                         "uint %s=%u is outside the allowed range "
164                         "[ %u ... %u ]\n",
165                         name, value, min, max);
166   }
typed_check_constraint(void * func,uint value,bool verbose) const167   JVMFlag::Error typed_check_constraint(void* func, uint value, bool verbose) const {
168     return ((JVMFlagConstraintFunc_uint)func)(value, verbose);
169   }
print_range_impl(outputStream * st,uint min,uint max) const170   void print_range_impl(outputStream* st, uint min, uint max) const {
171     st->print("[ %-25u ... %25u ]", min, max);
172   }
print_default_range(outputStream * st) const173   void print_default_range(outputStream* st) const {
174     st->print("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX);
175   }
176 };
177 
178 class FlagAccessImpl_intx : public RangedFlagAccessImpl<JVM_FLAG_TYPE(intx), EventLongFlagChanged> {
179 public:
range_error(const char * name,intx value,intx min,intx max,bool verbose) const180   void range_error(const char* name, intx value, intx min, intx max, bool verbose) const {
181     JVMFlag::printError(verbose,
182                         "intx %s=" INTX_FORMAT " is outside the allowed range "
183                         "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n",
184                         name, value, min, max);
185   }
typed_check_constraint(void * func,intx value,bool verbose) const186   JVMFlag::Error typed_check_constraint(void* func, intx value, bool verbose) const {
187     return ((JVMFlagConstraintFunc_intx)func)(value, verbose);
188   }
print_range_impl(outputStream * st,intx min,intx max) const189   void print_range_impl(outputStream* st, intx min, intx max) const {
190     st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min, max);
191   }
print_default_range(outputStream * st) const192   void print_default_range(outputStream* st) const {
193     st->print("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx);
194   }
195 };
196 
197 class FlagAccessImpl_uintx : public RangedFlagAccessImpl<JVM_FLAG_TYPE(uintx), EventUnsignedLongFlagChanged> {
198 public:
range_error(const char * name,uintx value,uintx min,uintx max,bool verbose) const199   void range_error(const char* name, uintx value, uintx min, uintx max, bool verbose) const {
200     JVMFlag::printError(verbose,
201                         "uintx %s=" UINTX_FORMAT " is outside the allowed range "
202                         "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n",
203                         name, value, min, max);
204   }
typed_check_constraint(void * func,uintx value,bool verbose) const205   JVMFlag::Error typed_check_constraint(void* func, uintx value, bool verbose) const {
206     return ((JVMFlagConstraintFunc_uintx)func)(value, verbose);
207   }
print_range_impl(outputStream * st,uintx min,uintx max) const208   void print_range_impl(outputStream* st, uintx min, uintx max) const {
209     st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", min, max);
210   }
print_default_range(outputStream * st) const211   void print_default_range(outputStream* st) const {
212     st->print("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", uintx(0), max_uintx);
213   }
214 };
215 
216 class FlagAccessImpl_uint64_t : public RangedFlagAccessImpl<JVM_FLAG_TYPE(uint64_t), EventUnsignedLongFlagChanged> {
217 public:
range_error(const char * name,uint64_t value,uint64_t min,uint64_t max,bool verbose) const218   void range_error(const char* name, uint64_t value, uint64_t min, uint64_t max, bool verbose) const {
219     JVMFlag::printError(verbose,
220                         "uint64_t %s=" UINT64_FORMAT " is outside the allowed range "
221                         "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n",
222                         name, value, min, max);
223   }
typed_check_constraint(void * func,uint64_t value,bool verbose) const224   JVMFlag::Error typed_check_constraint(void* func, uint64_t value, bool verbose) const {
225     return ((JVMFlagConstraintFunc_uint64_t)func)(value, verbose);
226   }
print_range_impl(outputStream * st,uint64_t min,uint64_t max) const227   void print_range_impl(outputStream* st, uint64_t min, uint64_t max) const {
228     st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", min, max);
229   }
print_default_range(outputStream * st) const230   void print_default_range(outputStream* st) const {
231     st->print("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", uint64_t(0), uint64_t(max_juint));
232   }
233 };
234 
235 class FlagAccessImpl_size_t : public RangedFlagAccessImpl<JVM_FLAG_TYPE(size_t), EventUnsignedLongFlagChanged> {
236 public:
range_error(const char * name,size_t value,size_t min,size_t max,bool verbose) const237   void range_error(const char* name, size_t value, size_t min, size_t max, bool verbose) const {
238     JVMFlag::printError(verbose,
239                         "size_t %s=" SIZE_FORMAT " is outside the allowed range "
240                         "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n",
241                         name, value, min, max);
242   }
typed_check_constraint(void * func,size_t value,bool verbose) const243   JVMFlag::Error typed_check_constraint(void* func, size_t value, bool verbose) const {
244     return ((JVMFlagConstraintFunc_size_t)func)(value, verbose);
245   }
print_range_impl(outputStream * st,size_t min,size_t max) const246   void print_range_impl(outputStream* st, size_t min, size_t max) const {
247     st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", min, max);
248   }
print_default_range(outputStream * st) const249   void print_default_range(outputStream* st) const {
250     st->print("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", size_t(0), size_t(SIZE_MAX));
251   }
252 };
253 
254 class FlagAccessImpl_double : public RangedFlagAccessImpl<JVM_FLAG_TYPE(double), EventDoubleFlagChanged> {
255 public:
range_error(const char * name,double value,double min,double max,bool verbose) const256   void range_error(const char* name, double value, double min, double max, bool verbose) const {
257     JVMFlag::printError(verbose,
258                           "double %s=%f is outside the allowed range "
259                           "[ %f ... %f ]\n",
260                         name, value, min, max);
261   }
typed_check_constraint(void * func,double value,bool verbose) const262   JVMFlag::Error typed_check_constraint(void* func, double value, bool verbose) const {
263     return ((JVMFlagConstraintFunc_double)func)(value, verbose);
264   }
print_range_impl(outputStream * st,double min,double max) const265   void print_range_impl(outputStream* st, double min, double max) const {
266     st->print("[ %-25.3f ... %25.3f ]", min, max);
267   }
print_default_range(outputStream * st) const268   void print_default_range(outputStream* st) const {
269     st->print("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX);
270   }
271 };
272 
273 #define FLAG_ACCESS_IMPL_INIT(t) \
274   static FlagAccessImpl_ ## t   flag_access_ ## t;
275 
276 #define FLAG_ACCESS_IMPL_ADDR(t) \
277   &flag_access_ ## t,
278 
279 JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_INIT)
280 
281 static const FlagAccessImpl* flag_accesss[JVMFlag::NUM_FLAG_TYPES] = {
282   JVM_FLAG_NON_STRING_TYPES_DO(FLAG_ACCESS_IMPL_ADDR)
283   // ccstr and ccstrlist have special setter
284 };
285 
access_impl(const JVMFlag * flag)286 inline const FlagAccessImpl* JVMFlagAccess::access_impl(const JVMFlag* flag) {
287   int type = flag->type();
288   int max = (int)(sizeof(flag_accesss)/sizeof(flag_accesss[0]));
289   assert(type >= 0 && type < max , "sanity");
290 
291   return flag_accesss[type];
292 }
293 
294 // This is called by JVMFlagAccess::*AtPut() and JVMFlagAccess::set<...>(JVMFlag* flag, ...)
set_impl(JVMFlag * flag,int type_enum,void * value,JVMFlagOrigin origin)295 JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlagOrigin origin) {
296   if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) {
297     return ccstrAtPut(flag, (ccstr*)value, origin);
298   }
299 
300   if (flag == NULL) {
301     return JVMFlag::INVALID_FLAG;
302   }
303   if (flag->type() != type_enum) {
304     return JVMFlag::WRONG_FORMAT;
305   }
306   return access_impl(flag)->set(flag, value, origin);
307 }
308 
ccstrAtPut(JVMFlag * flag,ccstr * value,JVMFlagOrigin origin)309 JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin) {
310   if (flag == NULL) return JVMFlag::INVALID_FLAG;
311   if (!flag->is_ccstr()) return JVMFlag::WRONG_FORMAT;
312   ccstr old_value = flag->get_ccstr();
313   trace_flag_changed<ccstr, EventStringFlagChanged>(flag, old_value, *value, origin);
314   char* new_value = NULL;
315   if (*value != NULL) {
316     new_value = os::strdup_check_oom(*value);
317   }
318   flag->set_ccstr(new_value);
319   if (flag->is_default() && old_value != NULL) {
320     // Prior value is NOT heap allocated, but was a literal constant.
321     old_value = os::strdup_check_oom(old_value);
322   }
323   *value = old_value;
324   flag->set_origin(origin);
325   return JVMFlag::SUCCESS;
326 }
327 
328 // This is called by the FLAG_SET_XXX macros.
set_impl(JVMFlagsEnum flag_enum,int type_enum,void * value,JVMFlagOrigin origin)329 JVMFlag::Error JVMFlagAccess::set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin) {
330   if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) {
331     return ccstrAtPut((JVMFlagsEnum)flag_enum, *((ccstr*)value), origin);
332   }
333 
334   JVMFlag* flag = JVMFlag::flag_from_enum(flag_enum);
335   assert(flag->type() == type_enum, "wrong flag type");
336   return set_impl(flag, type_enum, value, origin);
337 }
338 
339 // This is called by the FLAG_SET_XXX macros.
ccstrAtPut(JVMFlagsEnum flag,ccstr value,JVMFlagOrigin origin)340 JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlagOrigin origin) {
341   JVMFlag* faddr = JVMFlag::flag_from_enum(flag);
342   assert(faddr->is_ccstr(), "wrong flag type");
343   ccstr old_value = faddr->get_ccstr();
344   trace_flag_changed<ccstr, EventStringFlagChanged>(faddr, old_value, value, origin);
345   char* new_value = os::strdup_check_oom(value);
346   faddr->set_ccstr(new_value);
347   if (!faddr->is_default() && old_value != NULL) {
348     // Prior value is heap allocated so free it.
349     FREE_C_HEAP_ARRAY(char, old_value);
350   }
351   faddr->set_origin(origin);
352   return JVMFlag::SUCCESS;
353 }
354 
check_range(const JVMFlag * flag,bool verbose)355 JVMFlag::Error JVMFlagAccess::check_range(const JVMFlag* flag, bool verbose) {
356   return access_impl(flag)->check_range(flag, verbose);
357 }
358 
check_constraint(const JVMFlag * flag,void * func,bool verbose)359 JVMFlag::Error JVMFlagAccess::check_constraint(const JVMFlag* flag, void * func, bool verbose) {
360   return access_impl(flag)->check_constraint(flag, func, verbose);
361 }
362 
print_range(outputStream * st,const JVMFlag * flag,const JVMFlagLimit * range)363 void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag, const JVMFlagLimit* range) {
364   return access_impl(flag)->print_range(st, range);
365 }
366 
print_range(outputStream * st,const JVMFlag * flag)367 void JVMFlagAccess::print_range(outputStream* st, const JVMFlag* flag) {
368   const JVMFlagLimit* range = JVMFlagLimit::get_range(flag);
369   if (range != NULL) {
370     print_range(st, flag, range);
371   } else {
372     const JVMFlagLimit* limit = JVMFlagLimit::get_constraint(flag);
373     if (limit != NULL) {
374       void* func = limit->constraint_func();
375 
376       // Two special cases where the lower limit of the range is defined by an os:: function call
377       // and cannot be initialized at compile time with constexpr.
378       if (func == (void*)VMPageSizeConstraintFunc) {
379         uintx min = (uintx)os::vm_page_size();
380         uintx max = max_uintx;
381 
382         JVMTypedFlagLimit<uintx> tmp(0, min, max);
383         access_impl(flag)->print_range(st, &tmp);
384       } else if (func == (void*)NUMAInterleaveGranularityConstraintFunc) {
385         size_t min = os::vm_allocation_granularity();
386         size_t max = NOT_LP64(2*G) LP64_ONLY(8192*G);
387 
388         JVMTypedFlagLimit<size_t> tmp(0, min, max);
389         access_impl(flag)->print_range(st, &tmp);
390       } else {
391         access_impl(flag)->print_default_range(st);
392       }
393     } else {
394       st->print("[                           ...                           ]");
395     }
396   }
397 }
398