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_JVMFLAGACCESS_HPP
26 #define SHARE_RUNTIME_FLAGS_JVMFLAGACCESS_HPP
27 
28 #include "memory/allStatic.hpp"
29 #include "runtime/flags/jvmFlag.hpp"
30 #include "utilities/vmEnums.hpp"
31 
32 class FlagAccessImpl;
33 class JVMFlagLimit;
34 class outputStream;
35 
36 // Use this macro in combination with JVMFlag::{read, write} and JVMFlagAccess::{get, set}
37 // to safely access the underlying variable of a JVMFlag:
38 //
39 //  JVMFlag* flag = JVMFlag::flag_from_enum(FLAG_MEMBER_ENUM(ObjectAlignmentInBytes));
40 //
41 //  /* If you use a wrong type, a run-time assertion will happen */
42 //  intx v = flag->read<JVM_FLAG_TYPE(intx)>();
43 //
44 //  /* If you use a wrong type, or a NULL flag, an error code is returned */
45 //  JVMFlag::Error err = JVMFlagAccess::get<JVM_FLAG_TYPE(intx)>(flag, &v);
46 
47 #define JVM_FLAG_TYPE(t) \
48   t, JVMFlag::TYPE_ ## t
49 
50 // This class provides a unified interface for getting/setting the JVM flags, with support
51 // for (1) type correctness checks, (2) range checks, (3) constraint checks. Two main types
52 // of setters are provided. See notes below on which one to use.
53 class JVMFlagAccess : AllStatic {
54   inline static const FlagAccessImpl* access_impl(const JVMFlag* flag);
55   static JVMFlag::Error set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin);
56   static JVMFlag::Error set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlagOrigin origin);
57   static JVMFlag::Error ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlagOrigin origin);
58 
59 public:
60   static JVMFlag::Error check_range(const JVMFlag* flag, bool verbose);
61   static JVMFlag::Error check_constraint(const JVMFlag* flag, void * func, bool verbose);
62   static void print_range(outputStream* st, const JVMFlag* flag, const JVMFlagLimit* range);
63   static void print_range(outputStream* st, const JVMFlag* flag);
64 
65   template <typename T, int type_enum>
get(const JVMFlag * flag,T * value)66   static JVMFlag::Error get(const JVMFlag* flag, T* value) {
67     if (flag == NULL) {
68       return JVMFlag::INVALID_FLAG;
69     }
70     if (type_enum == JVMFlag::TYPE_ccstr) {
71       if (!flag->is_ccstr()) { // ccstr or ccstrlist
72         return JVMFlag::WRONG_FORMAT;
73       }
74     } else {
75       if (flag->type() != type_enum) {
76         return JVMFlag::WRONG_FORMAT;
77       }
78     }
79     *value = flag->read<T, type_enum>();
80     return JVMFlag::SUCCESS;
81   }
82 
83   // This is a *flag specific* setter. It should be used only via by the
84   // FLAG_SET_{DEFAULT, CMDLINE, ERGO, MGMT} macros.
85   // It's used to set a specific flag whose type is statically known. A mismatched
86   // type_enum will result in an assert.
87   template <typename T, int type_enum>
set(JVMFlagsEnum flag_enum,T value,JVMFlagOrigin origin)88   static JVMFlag::Error set(JVMFlagsEnum flag_enum, T value, JVMFlagOrigin origin) {
89     return set_impl(flag_enum, type_enum, &value, origin);
90   }
91 
92   // This setter, and the xxxAtPut functions below, are *generic* setters. They should be used
93   // by code that can set a number of different flags, often according to external input that
94   // may contain errors.
95   // Examples callers are arguments.cpp, writeableFlags.cpp, and WB_SetXxxVMFlag functions.
96   // A mismatched type_enum would result in a JVMFlag::WRONG_FORMAT code.
97   template <typename T, int type_enum>
set(JVMFlag * flag,T * value,JVMFlagOrigin origin)98   static JVMFlag::Error set(JVMFlag* flag, T* value, JVMFlagOrigin origin) {
99     return set_impl(flag, type_enum, (void*)value, origin);
100   }
101 
boolAtPut(JVMFlag * f,bool * v,JVMFlagOrigin origin)102   static JVMFlag::Error boolAtPut    (JVMFlag* f, bool*     v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(bool)>    (f, v, origin); }
intAtPut(JVMFlag * f,int * v,JVMFlagOrigin origin)103   static JVMFlag::Error intAtPut     (JVMFlag* f, int*      v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(int)>     (f, v, origin); }
uintAtPut(JVMFlag * f,uint * v,JVMFlagOrigin origin)104   static JVMFlag::Error uintAtPut    (JVMFlag* f, uint*     v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(uint)>    (f, v, origin); }
intxAtPut(JVMFlag * f,intx * v,JVMFlagOrigin origin)105   static JVMFlag::Error intxAtPut    (JVMFlag* f, intx*     v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(intx)>    (f, v, origin); }
uintxAtPut(JVMFlag * f,uintx * v,JVMFlagOrigin origin)106   static JVMFlag::Error uintxAtPut   (JVMFlag* f, uintx*    v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(uintx)>   (f, v, origin); }
uint64_tAtPut(JVMFlag * f,uint64_t * v,JVMFlagOrigin origin)107   static JVMFlag::Error uint64_tAtPut(JVMFlag* f, uint64_t* v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(uint64_t)>(f, v, origin); }
size_tAtPut(JVMFlag * f,size_t * v,JVMFlagOrigin origin)108   static JVMFlag::Error size_tAtPut  (JVMFlag* f, size_t*   v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(size_t)>  (f, v, origin); }
doubleAtPut(JVMFlag * f,double * v,JVMFlagOrigin origin)109   static JVMFlag::Error doubleAtPut  (JVMFlag* f, double*   v, JVMFlagOrigin origin) { return set<JVM_FLAG_TYPE(double)>  (f, v, origin); }
110 
111   // Special handling needed for ccstr
112   // Contract:  JVMFlag will make private copy of the incoming value.
113   // Outgoing value is always malloc-ed, and caller MUST call free.
114   static JVMFlag::Error ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin);
115 
116   // Handy aliases
ccstrAt(const JVMFlag * flag,ccstr * value)117   static JVMFlag::Error ccstrAt(const JVMFlag* flag, ccstr* value) {
118     return get<ccstr, JVMFlag::TYPE_ccstr>(flag, value);
119   }
120 };
121 
122 #endif // SHARE_RUNTIME_FLAGS_JVMFLAGACCESS_HPP
123