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