1/*
2 * Copyright (c) 2015, 2018, 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 "classfile/javaClasses.hpp"
27#include "memory/allocation.inline.hpp"
28#include "runtime/arguments.hpp"
29#include "runtime/flags/jvmFlag.hpp"
30#include "runtime/flags/jvmFlagRangeList.hpp"
31#include "runtime/java.hpp"
32#include "runtime/jniHandles.hpp"
33#include "services/writeableFlags.hpp"
34
35#define TEMP_BUF_SIZE 80
36
37static void buffer_concat(char* buffer, const char* src) {
38 strncat(buffer, src, TEMP_BUF_SIZE - 1 - strlen(buffer));
39}
40
41static void print_flag_error_message_bounds(const char* name, char* buffer) {
42 JVMFlagRange* range = JVMFlagRangeList::find(name);
43 if (range != NULL) {
44 buffer_concat(buffer, "must have value in range ");
45
46 stringStream stream;
47 range->print(&stream);
48 const char* range_string = stream.as_string();
49 size_t j = strlen(buffer);
50 for (size_t i=0; j<TEMP_BUF_SIZE-1; i++) {
51 if (range_string[i] == '\0') {
52 break;
53 } else if (range_string[i] != ' ') {
54 buffer[j] = range_string[i];
55 j++;
56 }
57 }
58 buffer[j] = '\0';
59 }
60}
61
62static void print_flag_error_message_if_needed(JVMFlag::Error error, const char* name, FormatBuffer<80>& err_msg) {
63 if (error == JVMFlag::SUCCESS) {
64 return;
65 }
66
67 char buffer[TEMP_BUF_SIZE] = {'\0'};
68 if ((error != JVMFlag::MISSING_NAME) && (name != NULL)) {
69 buffer_concat(buffer, name);
70 buffer_concat(buffer, " error: ");
71 } else {
72 buffer_concat(buffer, "Error: ");
73 }
74 switch (error) {
75 case JVMFlag::MISSING_NAME:
76 buffer_concat(buffer, "flag name is missing."); break;
77 case JVMFlag::MISSING_VALUE:
78 buffer_concat(buffer, "parsing the textual form of the value."); break;
79 case JVMFlag::NON_WRITABLE:
80 buffer_concat(buffer, "flag is not writeable."); break;
81 case JVMFlag::OUT_OF_BOUNDS:
82 if (name != NULL) { print_flag_error_message_bounds(name, buffer); } break;
83 case JVMFlag::VIOLATES_CONSTRAINT:
84 buffer_concat(buffer, "value violates its flag's constraint."); break;
85 case JVMFlag::INVALID_FLAG:
86 buffer_concat(buffer, "there is no flag with the given name."); break;
87 case JVMFlag::ERR_OTHER:
88 buffer_concat(buffer, "other, unspecified error related to setting the flag."); break;
89 case JVMFlag::SUCCESS:
90 break;
91 default:
92 break;
93 }
94
95 err_msg.print("%s", buffer);
96}
97
98// set a boolean global flag
99JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
100 if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) {
101 return set_bool_flag(name, true, origin, err_msg);
102 } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) {
103 return set_bool_flag(name, false, origin, err_msg);
104 }
105 err_msg.print("flag value must be a boolean (1/0 or true/false)");
106 return JVMFlag::WRONG_FORMAT;
107}
108
109JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
110 JVMFlag::Error err = JVMFlag::boolAtPut(name, &value, origin);
111 print_flag_error_message_if_needed(err, name, err_msg);
112 return err;
113}
114
115// set a int global flag
116JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
117 int value;
118
119 if (sscanf(arg, "%d", &value) == 1) {
120 return set_int_flag(name, value, origin, err_msg);
121 }
122 err_msg.print("flag value must be an integer");
123 return JVMFlag::WRONG_FORMAT;
124}
125
126JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
127 JVMFlag::Error err = JVMFlag::intAtPut(name, &value, origin);
128 print_flag_error_message_if_needed(err, name, err_msg);
129 return err;
130}
131
132// set a uint global flag
133JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
134 uint value;
135
136 if (sscanf(arg, "%u", &value) == 1) {
137 return set_uint_flag(name, value, origin, err_msg);
138 }
139 err_msg.print("flag value must be an unsigned integer");
140 return JVMFlag::WRONG_FORMAT;
141}
142
143JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
144 JVMFlag::Error err = JVMFlag::uintAtPut(name, &value, origin);
145 print_flag_error_message_if_needed(err, name, err_msg);
146 return err;
147}
148
149// set a intx global flag
150JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
151 intx value;
152
153 if (sscanf(arg, INTX_FORMAT, &value) == 1) {
154 return set_intx_flag(name, value, origin, err_msg);
155 }
156 err_msg.print("flag value must be an integer");
157 return JVMFlag::WRONG_FORMAT;
158}
159
160JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
161 JVMFlag::Error err = JVMFlag::intxAtPut(name, &value, origin);
162 print_flag_error_message_if_needed(err, name, err_msg);
163 return err;
164}
165
166// set a uintx global flag
167JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
168 uintx value;
169
170 if (sscanf(arg, UINTX_FORMAT, &value) == 1) {
171 return set_uintx_flag(name, value, origin, err_msg);
172 }
173 err_msg.print("flag value must be an unsigned integer");
174 return JVMFlag::WRONG_FORMAT;
175}
176
177JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
178 JVMFlag::Error err = JVMFlag::uintxAtPut(name, &value, origin);
179 print_flag_error_message_if_needed(err, name, err_msg);
180 return err;
181}
182
183// set a uint64_t global flag
184JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
185 uint64_t value;
186
187 if (sscanf(arg, UINT64_FORMAT, &value) == 1) {
188 return set_uint64_t_flag(name, value, origin, err_msg);
189 }
190 err_msg.print("flag value must be an unsigned 64-bit integer");
191 return JVMFlag::WRONG_FORMAT;
192}
193
194JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
195 JVMFlag::Error err = JVMFlag::uint64_tAtPut(name, &value, origin);
196 print_flag_error_message_if_needed(err, name, err_msg);
197 return err;
198}
199
200// set a size_t global flag
201JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
202 size_t value;
203
204 if (sscanf(arg, SIZE_FORMAT, &value) == 1) {
205 return set_size_t_flag(name, value, origin, err_msg);
206 }
207 err_msg.print("flag value must be an unsigned integer");
208 return JVMFlag::WRONG_FORMAT;
209}
210
211JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
212 JVMFlag::Error err = JVMFlag::size_tAtPut(name, &value, origin);
213 print_flag_error_message_if_needed(err, name, err_msg);
214 return err;
215}
216
217// set a double global flag
218JVMFlag::Error WriteableFlags::set_double_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
219 double value;
220
221 if (sscanf(arg, "%lf", &value) == 1) {
222 return set_double_flag(name, value, origin, err_msg);
223 }
224 err_msg.print("flag value must be a double");
225 return JVMFlag::WRONG_FORMAT;
226}
227
228JVMFlag::Error WriteableFlags::set_double_flag(const char* name, double value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
229 JVMFlag::Error err = JVMFlag::doubleAtPut(name, &value, origin);
230 print_flag_error_message_if_needed(err, name, err_msg);
231 return err;
232}
233
234// set a string global flag using value from AttachOperation
235JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
236 JVMFlag::Error err = JVMFlag::ccstrAtPut((char*)name, &value, origin);
237 print_flag_error_message_if_needed(err, name, err_msg);
238 return err;
239}
240
241/* sets a writeable flag to the provided value
242 *
243 * - return status is one of the WriteableFlags::err enum values
244 * - an eventual error message will be generated to the provided err_msg buffer
245 */
246JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
247 return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg);
248}
249
250/* sets a writeable flag to the provided value
251 *
252 * - return status is one of the WriteableFlags::err enum values
253 * - an eventual error message will be generated to the provided err_msg buffer
254 */
255JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
256 return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg);
257}
258
259// a writeable flag setter accepting either 'jvalue' or 'char *' values
260JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
261 if (name == NULL) {
262 err_msg.print("flag name is missing");
263 return JVMFlag::MISSING_NAME;
264 }
265 if (value == NULL) {
266 err_msg.print("flag value is missing");
267 return JVMFlag::MISSING_VALUE;
268 }
269
270 JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name));
271 if (f) {
272 // only writeable flags are allowed to be set
273 if (f->is_writeable()) {
274 return setter(f, value, origin, err_msg);
275 } else {
276 err_msg.print("only 'writeable' flags can be set");
277 return JVMFlag::NON_WRITABLE;
278 }
279 }
280
281 err_msg.print("flag %s does not exist", name);
282 return JVMFlag::INVALID_FLAG;
283}
284
285// a writeable flag setter accepting 'char *' values
286JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) {
287 char* flag_value = *(char**)value;
288 if (flag_value == NULL) {
289 err_msg.print("flag value is missing");
290 return JVMFlag::MISSING_VALUE;
291 }
292 if (f->is_bool()) {
293 return set_bool_flag(f->_name, flag_value, origin, err_msg);
294 } else if (f->is_int()) {
295 return set_int_flag(f->_name, flag_value, origin, err_msg);
296 } else if (f->is_uint()) {
297 return set_uint_flag(f->_name, flag_value, origin, err_msg);
298 } else if (f->is_intx()) {
299 return set_intx_flag(f->_name, flag_value, origin, err_msg);
300 } else if (f->is_uintx()) {
301 return set_uintx_flag(f->_name, flag_value, origin, err_msg);
302 } else if (f->is_uint64_t()) {
303 return set_uint64_t_flag(f->_name, flag_value, origin, err_msg);
304 } else if (f->is_size_t()) {
305 return set_size_t_flag(f->_name, flag_value, origin, err_msg);
306 } else if (f->is_double()) {
307 return set_double_flag(f->_name, flag_value, origin, err_msg);
308 } else if (f->is_ccstr()) {
309 return set_ccstr_flag(f->_name, flag_value, origin, err_msg);
310 } else {
311 ShouldNotReachHere();
312 }
313 return JVMFlag::ERR_OTHER;
314}
315
316// a writeable flag setter accepting 'jvalue' values
317JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin,
318 FormatBuffer<80>& err_msg) {
319 jvalue new_value = *(jvalue*)value;
320 if (f->is_bool()) {
321 bool bvalue = (new_value.z == JNI_TRUE ? true : false);
322 return set_bool_flag(f->_name, bvalue, origin, err_msg);
323 } else if (f->is_int()) {
324 int ivalue = (int)new_value.j;
325 return set_int_flag(f->_name, ivalue, origin, err_msg);
326 } else if (f->is_uint()) {
327 uint uvalue = (uint)new_value.j;
328 return set_uint_flag(f->_name, uvalue, origin, err_msg);
329 } else if (f->is_intx()) {
330 intx ivalue = (intx)new_value.j;
331 return set_intx_flag(f->_name, ivalue, origin, err_msg);
332 } else if (f->is_uintx()) {
333 uintx uvalue = (uintx)new_value.j;
334 return set_uintx_flag(f->_name, uvalue, origin, err_msg);
335 } else if (f->is_uint64_t()) {
336 uint64_t uvalue = (uint64_t)new_value.j;
337 return set_uint64_t_flag(f->_name, uvalue, origin, err_msg);
338 } else if (f->is_size_t()) {
339 size_t svalue = (size_t)new_value.j;
340 return set_size_t_flag(f->_name, svalue, origin, err_msg);
341 } else if (f->is_double()) {
342 double dvalue = (double)new_value.d;
343 return set_double_flag(f->_name, dvalue, origin, err_msg);
344 } else if (f->is_ccstr()) {
345 oop str = JNIHandles::resolve_external_guard(new_value.l);
346 if (str == NULL) {
347 err_msg.print("flag value is missing");
348 return JVMFlag::MISSING_VALUE;
349 }
350 ccstr svalue = java_lang_String::as_utf8_string(str);
351 JVMFlag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg);
352 if (ret != JVMFlag::SUCCESS) {
353 FREE_C_HEAP_ARRAY(char, svalue);
354 }
355 return ret;
356 } else {
357 ShouldNotReachHere();
358 }
359 return JVMFlag::ERR_OTHER;
360}
361