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 #ifndef SHARE_RUNTIME_FLAGS_JVMFLAGLIMIT_HPP
26 #define SHARE_RUNTIME_FLAGS_JVMFLAGLIMIT_HPP
27 
28 #include "runtime/flags/jvmFlag.hpp"
29 
30 class outputStream;
31 template <typename T> class JVMTypedFlagLimit;
32 
33 enum class JVMFlagConstraintPhase : int {
34   // Will be validated during argument processing (Arguments::parse_argument).
35   AtParse         = 0,
36   // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo().
37   AfterErgo       = 1,
38   // Will be validated inside universe_init(), right after Metaspace::global_initialize().
39   AfterMemoryInit = 2
40 };
41 
42 
43 typedef JVMFlag::Error (*JVMFlagConstraintFunc_bool)(bool value, bool verbose);
44 typedef JVMFlag::Error (*JVMFlagConstraintFunc_int)(int value, bool verbose);
45 typedef JVMFlag::Error (*JVMFlagConstraintFunc_intx)(intx value, bool verbose);
46 typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint)(uint value, bool verbose);
47 typedef JVMFlag::Error (*JVMFlagConstraintFunc_uintx)(uintx value, bool verbose);
48 typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose);
49 typedef JVMFlag::Error (*JVMFlagConstraintFunc_size_t)(size_t value, bool verbose);
50 typedef JVMFlag::Error (*JVMFlagConstraintFunc_double)(double value, bool verbose);
51 
52 // A JVMFlagLimit is created for each JVMFlag that has a range() and/or constraint() in its declaration in
53 // the globals_xxx.hpp file.
54 //
55 // To query the range information of a JVMFlag:
56 //     JVMFlagLimit::get_range(JVMFlag*)
57 //     JVMFlagLimit::get_range_at(int flag_enum)
58 // If the given flag doesn't have a range, NULL is returned.
59 //
60 // To query the constraint information of a JVMFlag:
61 //     JVMFlagLimit::get_constraint(JVMFlag*)
62 //     JVMFlagLimit::get_constraint_at(int flag_enum)
63 // If the given flag doesn't have a constraint, NULL is returned.
64 
65 class JVMFlagLimit {
66   short _constraint_func;
67   char  _phase;
68   char  _kind;
69 
70   static const JVMFlagLimit* const* flagLimits;
71   static JVMFlagsEnum _last_checked;
72   static JVMFlagConstraintPhase _validating_phase;
73 
74 protected:
75   static constexpr int HAS_RANGE = 1;
76   static constexpr int HAS_CONSTRAINT = 2;
77 
78 private:
get_kind_at(JVMFlagsEnum flag_enum,int required_kind)79   static const JVMFlagLimit* get_kind_at(JVMFlagsEnum flag_enum, int required_kind) {
80     const JVMFlagLimit* limit = at(flag_enum);
81     if (limit != NULL && (limit->_kind & required_kind) != 0) {
82       _last_checked = flag_enum;
83       return limit;
84     } else {
85       return NULL;
86     }
87   }
88 
at(JVMFlagsEnum flag_enum)89   static const JVMFlagLimit* at(JVMFlagsEnum flag_enum) {
90     JVMFlag::assert_valid_flag_enum(flag_enum);
91     return flagLimits[static_cast<int>(flag_enum)];
92   }
93 
94 public:
95   void* constraint_func() const;
phase() const96   char phase() const { return _phase; }
kind() const97   char kind()  const { return _kind; }
98 
JVMFlagLimit(short func,short phase,short kind)99   constexpr JVMFlagLimit(short func, short phase, short kind) : _constraint_func(func), _phase(phase), _kind(kind) {}
100 
get_range(const JVMFlag * flag)101   static const JVMFlagLimit* get_range(const JVMFlag* flag) {
102     return get_range_at(flag->flag_enum());
103   }
get_range_at(JVMFlagsEnum flag_enum)104   static const JVMFlagLimit* get_range_at(JVMFlagsEnum flag_enum) {
105     return get_kind_at(flag_enum, HAS_RANGE);
106   }
107 
get_constraint(const JVMFlag * flag)108   static const JVMFlagLimit* get_constraint(const JVMFlag* flag) {
109     return get_constraint_at(flag->flag_enum());
110   }
get_constraint_at(JVMFlagsEnum flag_enum)111   static const JVMFlagLimit* get_constraint_at(JVMFlagsEnum flag_enum) {
112     return get_kind_at(flag_enum, HAS_CONSTRAINT);
113   }
114 
115   static const JVMFlag* last_checked_flag();
116 
117   // Is the current value of each JVM flag within the allowed range (if specified)
118   static bool check_all_ranges();
119   void print_range(outputStream* st, const JVMFlag* flag) const;
120 
121   // Does the current value of each JVM flag satisfy the specified constraint
122   static bool check_all_constraints(JVMFlagConstraintPhase phase);
123 
124   // If range/constraint checks fail, print verbose error messages only if we are parsing
125   // arguments from the command-line. Silently ignore any invalid values that are
126   // set programmatically via FLAG_SET_ERGO, etc.
verbose_checks_needed()127   static bool verbose_checks_needed() {
128     return _validating_phase == JVMFlagConstraintPhase::AtParse;
129   }
130 
validating_phase()131   static JVMFlagConstraintPhase validating_phase() { return _validating_phase; }
132 };
133 
134 enum ConstraintMarker {
135   next_two_args_are_constraint,
136 };
137 
138 template <typename T>
139 class JVMTypedFlagLimit : public JVMFlagLimit {
140   const T _min;
141   const T _max;
142 
143 public:
144   // dummy - no range or constraint. This object will not be emitted into the .o file
145   // because we declare it as "const" but has no reference to it.
JVMTypedFlagLimit(int dummy)146   constexpr JVMTypedFlagLimit(int dummy) :
147     JVMFlagLimit(0, 0, 0), _min(0), _max(0) {}
148 
149   // range only
JVMTypedFlagLimit(int dummy,T min,T max)150   constexpr JVMTypedFlagLimit(int dummy, T min, T max) :
151     JVMFlagLimit(0, 0, HAS_RANGE), _min(min), _max(max) {}
152 
153   // constraint only
JVMTypedFlagLimit(int dummy,ConstraintMarker dummy2,short func,int phase)154   constexpr JVMTypedFlagLimit(int dummy, ConstraintMarker dummy2, short func, int phase) :
155     JVMFlagLimit(func, phase, HAS_CONSTRAINT), _min(0), _max(0) {}
156 
157   // range and constraint
JVMTypedFlagLimit(int dummy,T min,T max,ConstraintMarker dummy2,short func,int phase)158   constexpr JVMTypedFlagLimit(int dummy, T min, T max, ConstraintMarker dummy2, short func, int phase)  :
159     JVMFlagLimit(func, phase, HAS_RANGE | HAS_CONSTRAINT), _min(min), _max(max) {}
160 
161   // constraint and range
JVMTypedFlagLimit(int dummy,ConstraintMarker dummy2,short func,int phase,T min,T max)162   constexpr JVMTypedFlagLimit(int dummy, ConstraintMarker dummy2, short func, int phase, T min, T max)  :
163     JVMFlagLimit(func, phase, HAS_RANGE | HAS_CONSTRAINT), _min(min), _max(max) {}
164 
min() const165   T min() const { return _min; }
max() const166   T max() const { return _max; }
167 };
168 
169 #endif // SHARE_RUNTIME_FLAGS_JVMFLAGLIMIT_HPP
170