mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-28 15:51:02 +00:00
8282773: Refactor parsing of integer VM options
Reviewed-by: dholmes, kbarrett
This commit is contained in:
parent
5ef1990d6c
commit
b004fb0550
@ -40,6 +40,7 @@
|
||||
#include "logging/logStream.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
@ -56,6 +57,7 @@
|
||||
#include "services/management.hpp"
|
||||
#include "services/nmtCommon.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
@ -63,6 +65,7 @@
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif
|
||||
#include <limits>
|
||||
|
||||
#define DEFAULT_JAVA_LAUNCHER "generic"
|
||||
|
||||
@ -744,20 +747,84 @@ bool Arguments::verify_special_jvm_flags(bool check_globals) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parses a size specification string.
|
||||
bool Arguments::atojulong(const char *s, julong* result) {
|
||||
julong n = 0;
|
||||
template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)> // signed 32-bit
|
||||
static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) {
|
||||
// Don't use strtol -- on 64-bit builds, "long" could be either 32- or 64-bits
|
||||
// so the range tests could be tautological and might cause compiler warnings.
|
||||
STATIC_ASSERT(sizeof(long long) >= 8); // C++ specification
|
||||
errno = 0; // errno is thread safe
|
||||
long long v = strtoll(s, endptr, base);
|
||||
if (errno != 0 || v < min_jint || v > max_jint) {
|
||||
return false;
|
||||
}
|
||||
*result = static_cast<T>(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
// First char must be a digit. Don't allow negative numbers or leading spaces.
|
||||
if (!isdigit(*s)) {
|
||||
template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)> // unsigned 32-bit
|
||||
static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) {
|
||||
if (s[0] == '-') {
|
||||
return false;
|
||||
}
|
||||
// Don't use strtoul -- same reason as above.
|
||||
STATIC_ASSERT(sizeof(unsigned long long) >= 8); // C++ specification
|
||||
errno = 0; // errno is thread safe
|
||||
unsigned long long v = strtoull(s, endptr, base);
|
||||
if (errno != 0 || v > max_juint) {
|
||||
return false;
|
||||
}
|
||||
*result = static_cast<T>(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)> // signed 64-bit
|
||||
static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) {
|
||||
errno = 0; // errno is thread safe
|
||||
*result = strtoll(s, endptr, base);
|
||||
return errno == 0;
|
||||
}
|
||||
|
||||
template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)> // unsigned 64-bit
|
||||
static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) {
|
||||
if (s[0] == '-') {
|
||||
return false;
|
||||
}
|
||||
errno = 0; // errno is thread safe
|
||||
*result = strtoull(s, endptr, base);
|
||||
return errno == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool multiply_by_1k(T& n) {
|
||||
if (n >= std::numeric_limits<T>::min() / 1024 &&
|
||||
n <= std::numeric_limits<T>::max() / 1024) {
|
||||
n *= 1024;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All of the integral types that can be used for command line options:
|
||||
// int, uint, intx, uintx, uint64_t, size_t
|
||||
//
|
||||
// In all supported platforms, these types can be mapped to only 4 native types:
|
||||
// {signed, unsigned} x {32-bit, 64-bit}
|
||||
//
|
||||
// We use SFINAE to pick the correct parse_integer_impl() function
|
||||
template<typename T>
|
||||
static bool parse_integer(const char *s, T* result) {
|
||||
if (!isdigit(s[0]) && s[0] != '-') {
|
||||
// strtoll/strtoull may allow leading spaces. Forbid it.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
|
||||
T n = 0;
|
||||
bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ||
|
||||
(s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[3] == 'X'));
|
||||
char* remainder;
|
||||
errno = 0;
|
||||
n = strtoull(s, &remainder, (is_hex ? 16 : 10));
|
||||
if (errno != 0) {
|
||||
|
||||
if (!parse_integer_impl(s, &remainder, (is_hex ? 16 : 10), &n)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -768,28 +835,29 @@ bool Arguments::atojulong(const char *s, julong* result) {
|
||||
|
||||
switch (*remainder) {
|
||||
case 'T': case 't':
|
||||
*result = n * G * K;
|
||||
// Check for overflow.
|
||||
if (*result/((julong)G * K) != n) return false;
|
||||
return true;
|
||||
if (!multiply_by_1k(n)) return false;
|
||||
// fall-through
|
||||
case 'G': case 'g':
|
||||
*result = n * G;
|
||||
if (*result/G != n) return false;
|
||||
return true;
|
||||
if (!multiply_by_1k(n)) return false;
|
||||
// fall-through
|
||||
case 'M': case 'm':
|
||||
*result = n * M;
|
||||
if (*result/M != n) return false;
|
||||
return true;
|
||||
if (!multiply_by_1k(n)) return false;
|
||||
// fall-through
|
||||
case 'K': case 'k':
|
||||
*result = n * K;
|
||||
if (*result/K != n) return false;
|
||||
return true;
|
||||
if (!multiply_by_1k(n)) return false;
|
||||
break;
|
||||
case '\0':
|
||||
*result = n;
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Arguments::atojulong(const char *s, julong* result) {
|
||||
return parse_integer(s, result);
|
||||
}
|
||||
|
||||
Arguments::ArgsRange Arguments::check_memory_size(julong size, julong min_size, julong max_size) {
|
||||
@ -838,72 +906,57 @@ static bool set_fp_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool set_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) {
|
||||
julong v;
|
||||
int int_v;
|
||||
intx intx_v;
|
||||
bool is_neg = false;
|
||||
|
||||
static JVMFlag::Error set_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) {
|
||||
if (flag == NULL) {
|
||||
return false;
|
||||
return JVMFlag::INVALID_FLAG;
|
||||
}
|
||||
|
||||
// Check the sign first since atojulong() parses only unsigned values.
|
||||
if (*value == '-') {
|
||||
if (!flag->is_intx() && !flag->is_int()) {
|
||||
return false;
|
||||
}
|
||||
value++;
|
||||
is_neg = true;
|
||||
}
|
||||
if (!Arguments::atojulong(value, &v)) {
|
||||
return false;
|
||||
}
|
||||
if (flag->is_int()) {
|
||||
int_v = (int) v;
|
||||
if (is_neg) {
|
||||
int_v = -int_v;
|
||||
int v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_int(flag, &v, origin);
|
||||
}
|
||||
if ((!is_neg && v > max_jint) || (is_neg && -(intx)v < min_jint)) {
|
||||
return false;
|
||||
}
|
||||
return JVMFlagAccess::set_int(flag, &int_v, origin) == JVMFlag::SUCCESS;
|
||||
} else if (flag->is_uint()) {
|
||||
if (v > max_juint) {
|
||||
return false;
|
||||
uint v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_uint(flag, &v, origin);
|
||||
}
|
||||
uint uint_v = (uint) v;
|
||||
return JVMFlagAccess::set_uint(flag, &uint_v, origin) == JVMFlag::SUCCESS;
|
||||
} else if (flag->is_intx()) {
|
||||
intx_v = (intx) v;
|
||||
if (is_neg) {
|
||||
if (intx_v != min_intx) {
|
||||
intx_v = - intx_v;
|
||||
if (intx_v > 0) {
|
||||
return false; // underflow
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (intx_v < 0) {
|
||||
return false; // overflow
|
||||
}
|
||||
intx v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_intx(flag, &v, origin);
|
||||
}
|
||||
return JVMFlagAccess::set_intx(flag, &intx_v, origin) == JVMFlag::SUCCESS;
|
||||
} else if (flag->is_uintx()) {
|
||||
uintx uintx_v = (uintx) v;
|
||||
return JVMFlagAccess::set_uintx(flag, &uintx_v, origin) == JVMFlag::SUCCESS;
|
||||
uintx v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_uintx(flag, &v, origin);
|
||||
}
|
||||
} else if (flag->is_uint64_t()) {
|
||||
uint64_t uint64_t_v = (uint64_t) v;
|
||||
return JVMFlagAccess::set_uint64_t(flag, &uint64_t_v, origin) == JVMFlag::SUCCESS;
|
||||
uint64_t v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_uint64_t(flag, &v, origin);
|
||||
}
|
||||
} else if (flag->is_size_t()) {
|
||||
size_t size_t_v = (size_t) v;
|
||||
return JVMFlagAccess::set_size_t(flag, &size_t_v, origin) == JVMFlag::SUCCESS;
|
||||
size_t v;
|
||||
if (parse_integer(value, &v)) {
|
||||
return JVMFlagAccess::set_size_t(flag, &v, origin);
|
||||
}
|
||||
} else if (flag->is_double()) {
|
||||
double double_v = (double) v;
|
||||
return JVMFlagAccess::set_double(flag, &double_v, origin) == JVMFlag::SUCCESS;
|
||||
} else {
|
||||
return false;
|
||||
// This function parses only input strings without a decimal
|
||||
// point character (.)
|
||||
// If a string looks like a FP number, it would be parsed by
|
||||
// set_fp_numeric_flag(). See Arguments::parse_argument().
|
||||
jlong v;
|
||||
if (parse_integer(value, &v)) {
|
||||
double double_v = (double) v;
|
||||
if (value[0] == '-' && v == 0) { // special case: 0.0 is different than -0.0.
|
||||
double_v = -0.0;
|
||||
}
|
||||
return JVMFlagAccess::set_double(flag, &double_v, origin);
|
||||
}
|
||||
}
|
||||
|
||||
return JVMFlag::WRONG_FORMAT;
|
||||
}
|
||||
|
||||
static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) {
|
||||
@ -1065,7 +1118,7 @@ bool Arguments::parse_argument(const char* arg, JVMFlagOrigin origin) {
|
||||
return false;
|
||||
}
|
||||
JVMFlag* flag = JVMFlag::find_flag(real_name);
|
||||
return set_numeric_flag(flag, value, origin);
|
||||
return set_numeric_flag(flag, value, origin) == JVMFlag::SUCCESS;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -2082,24 +2135,16 @@ static const char* system_assertion_options[] = {
|
||||
bool Arguments::parse_uintx(const char* value,
|
||||
uintx* uintx_arg,
|
||||
uintx min_size) {
|
||||
|
||||
// Check the sign first since atojulong() parses only unsigned values.
|
||||
bool value_is_positive = !(*value == '-');
|
||||
|
||||
if (value_is_positive) {
|
||||
julong n;
|
||||
bool good_return = atojulong(value, &n);
|
||||
if (good_return) {
|
||||
bool above_minimum = n >= min_size;
|
||||
bool value_is_too_large = n > max_uintx;
|
||||
|
||||
if (above_minimum && !value_is_too_large) {
|
||||
*uintx_arg = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
uintx n;
|
||||
if (!parse_integer(value, &n)) {
|
||||
return false;
|
||||
}
|
||||
if (n >= min_size) {
|
||||
*uintx_arg = n;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Arguments::create_module_property(const char* prop_name, const char* prop_value, PropertyInternal internal) {
|
||||
@ -2150,7 +2195,7 @@ Arguments::ArgsRange Arguments::parse_memory_size(const char* s,
|
||||
julong* long_arg,
|
||||
julong min_size,
|
||||
julong max_size) {
|
||||
if (!atojulong(s, long_arg)) return arg_unreadable;
|
||||
if (!parse_integer(s, long_arg)) return arg_unreadable;
|
||||
return check_memory_size(*long_arg, min_size, max_size);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,6 +62,29 @@
|
||||
product(ccstr, DummyManageableStringFlag, NULL, MANAGEABLE, \
|
||||
"Dummy flag for testing string handling in WriteableFlags") \
|
||||
\
|
||||
product(bool, TestFlagFor_bool, false, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(int, TestFlagFor_int, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(uint, TestFlagFor_uint, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(intx, TestFlagFor_intx, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(uintx, TestFlagFor_uintx, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(uint64_t, TestFlagFor_uint64_t, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(size_t, TestFlagFor_size_t, 0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
\
|
||||
product(double, TestFlagFor_double, 0.0, \
|
||||
"Used by VM internal regression tests only") \
|
||||
|
||||
// end of DEBUG_RUNTIME_FLAGS
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
#include "jvm.h"
|
||||
#include "unittest.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/flags/jvmFlag.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
@ -41,6 +42,16 @@ public:
|
||||
static jint parse_xss(const JavaVMOption* option, const char* tail, intx* out_ThreadStackSize) {
|
||||
return Arguments::parse_xss(option, tail, out_ThreadStackSize);
|
||||
}
|
||||
|
||||
static bool parse_argument(const char* name, const char* value) {
|
||||
char buf[1024];
|
||||
int ret = jio_snprintf(buf, sizeof(buf), "%s=%s", name, value);
|
||||
if (ret > 0) {
|
||||
return Arguments::parse_argument(buf, JVMFlagOrigin::COMMAND_LINE);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ArgumentsTest, atojulong) {
|
||||
@ -201,3 +212,356 @@ TEST_VM_F(ArgumentsTest, parse_xss) {
|
||||
EXPECT_EQ(parse_xss_inner(to_string(K + 1), JNI_OK), calc_expected(K + 1));
|
||||
}
|
||||
}
|
||||
|
||||
struct Dummy {};
|
||||
static Dummy BAD;
|
||||
|
||||
template <typename T>
|
||||
struct NumericArgument {
|
||||
bool bad;
|
||||
const char* str;
|
||||
T expected_value;
|
||||
|
||||
NumericArgument(const char* s, T v) : bad(false), str(s), expected_value(v) {}
|
||||
NumericArgument(const char* s, Dummy & dummy) : bad(true), str(s), expected_value(0) {}
|
||||
};
|
||||
|
||||
static void check_invalid_numeric_string(JVMFlag* flag, const char** invalid_strings) {
|
||||
for (uint i = 0; ; i++) {
|
||||
const char* str = invalid_strings[i];
|
||||
if (str == NULL) {
|
||||
return;
|
||||
}
|
||||
ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str))
|
||||
<< "Invalid string '" << str
|
||||
<< "' parsed without error for type " << flag->type_string() << ".";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void check_numeric_flag(JVMFlag* flag, T getvalue(JVMFlag* flag),
|
||||
NumericArgument<T>* valid_args, size_t n,
|
||||
bool is_double = false) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
NumericArgument<T>* info = &valid_args[i];
|
||||
const char* str = info->str;
|
||||
if (info->bad) {
|
||||
ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str))
|
||||
<< "Invalid string '" << str
|
||||
<< "' parsed without error for type " << flag->type_string() << ".";
|
||||
} else {
|
||||
ASSERT_TRUE(ArgumentsTest::parse_argument(flag->name(), str))
|
||||
<< "Valid string '" <<
|
||||
str << "' did not parse for type " << flag->type_string() << ".";
|
||||
ASSERT_EQ(getvalue(flag), info->expected_value)
|
||||
<< "Valid string '" << str
|
||||
<< "' did not parse to the correct value for type "
|
||||
<< flag->type_string() << ".";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid strings for *any* type of integer VM arguments
|
||||
const char* invalid_strings[] = {
|
||||
"", " 1", "2 ", "3 2",
|
||||
"0x", "0x0x1" "e"
|
||||
"K", "M", "G", "1MB", "1KM", "AA", "0B",
|
||||
"18446744073709551615K", "17179869184G",
|
||||
"999999999999999999999999999999",
|
||||
"0x10000000000000000", "18446744073709551616",
|
||||
"-0x10000000000000000", "-18446744073709551616",
|
||||
"-0x8000000000000001", "-9223372036854775809",
|
||||
"0x8000000t", "0x800000000g",
|
||||
"0x800000000000m", "0x800000000000000k",
|
||||
"-0x8000000t", "-0x800000000g",
|
||||
"-0x800000000000m", "-0x800000000000000k",
|
||||
NULL,
|
||||
};
|
||||
check_invalid_numeric_string(flag, invalid_strings);
|
||||
}
|
||||
|
||||
if (!is_double) {
|
||||
const char* invalid_strings_for_integers[] = {
|
||||
"1.0", "0x4.5", "0.001", "4e10",
|
||||
NULL,
|
||||
};
|
||||
check_invalid_numeric_string(flag, invalid_strings_for_integers);
|
||||
}
|
||||
}
|
||||
|
||||
#define INTEGER_TEST_TABLE(f) \
|
||||
/*input i32 u32 i64 u64 */ \
|
||||
f("0", 0, 0, 0, 0 ) \
|
||||
f("-0", 0, BAD, 0, BAD ) \
|
||||
f("-1", -1, BAD, -1, BAD ) \
|
||||
f("0x1", 1, 1, 1, 1 ) \
|
||||
f("-0x1", -1, BAD, -1, BAD ) \
|
||||
f("4711", 4711, 4711, 4711, 4711 ) \
|
||||
f("1K", 1024, 1024, 1024, 1024 ) \
|
||||
f("1k", 1024, 1024, 1024, 1024 ) \
|
||||
f("2M", 2097152, 2097152, 2097152, 2097152 ) \
|
||||
f("2m", 2097152, 2097152, 2097152, 2097152 ) \
|
||||
f("1G", 1073741824, 1073741824, 1073741824, 1073741824 ) \
|
||||
f("2G", BAD, 0x80000000, 2147483648LL, 2147483648ULL ) \
|
||||
f("1T", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \
|
||||
f("1t", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \
|
||||
f("-1K", -1024, BAD, -1024, BAD ) \
|
||||
f("0x1K", 1024, 1024, 1024, 1024 ) \
|
||||
f("-0x1K", -1024, BAD, -1024, BAD ) \
|
||||
f("0K", 0, 0, 0, 0 ) \
|
||||
f("0x1000000k", BAD, BAD, 17179869184LL, 17179869184ULL ) \
|
||||
f("0x800000m", BAD, BAD, 0x80000000000LL, 0x80000000000ULL ) \
|
||||
f("0x8000g", BAD, BAD, 0x200000000000LL, 0x200000000000ULL ) \
|
||||
f("0x8000t", BAD, BAD, 0x80000000000000LL, 0x80000000000000ULL ) \
|
||||
f("-0x1000000k", BAD, BAD, -17179869184LL, BAD ) \
|
||||
f("-0x800000m", BAD, BAD, -0x80000000000LL, BAD ) \
|
||||
f("-0x8000g", BAD, BAD, -0x200000000000LL, BAD ) \
|
||||
f("-0x8000t", BAD, BAD, -0x80000000000000LL, BAD ) \
|
||||
f("0x7fffffff", 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff ) \
|
||||
f("0xffffffff", BAD, 0xffffffff, 0xffffffff, 0xffffffff ) \
|
||||
f("0x80000000", BAD, 0x80000000, 0x80000000, 0x80000000 ) \
|
||||
f("-0x7fffffff", -2147483647, BAD, -2147483647LL, BAD ) \
|
||||
f("-0x80000000", -2147483648, BAD, -2147483648LL, BAD ) \
|
||||
f("-0x80000001", BAD, BAD, -2147483649LL, BAD ) \
|
||||
f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \
|
||||
f("0xcafebabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \
|
||||
f("0XCAFEBABE", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \
|
||||
f("0XCAFEbabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \
|
||||
f("0xcafebabe1", BAD, BAD, 0xcafebabe1, 0xcafebabe1 ) \
|
||||
f("0x7fffffffffffffff", BAD, BAD, max_jlong, 9223372036854775807ULL ) \
|
||||
f("0x8000000000000000", BAD, BAD, BAD, 9223372036854775808ULL ) \
|
||||
f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \
|
||||
f("9223372036854775807", BAD, BAD, 9223372036854775807LL, 9223372036854775807ULL ) \
|
||||
f("9223372036854775808", BAD, BAD, BAD, 9223372036854775808ULL ) \
|
||||
f("-9223372036854775808", BAD, BAD, min_jlong, BAD ) \
|
||||
f("18446744073709551615", BAD, BAD, BAD, max_julong ) \
|
||||
\
|
||||
/* All edge cases without a k/m/g/t suffix */ \
|
||||
f("0x7ffffffe", max_jint-1, 0x7ffffffe, 0x7ffffffeLL, 0x7ffffffeULL ) \
|
||||
f("0x7fffffff", max_jint, 0x7fffffff, 0x7fffffffLL, 0x7fffffffULL ) \
|
||||
f("0x80000000", BAD, 0x80000000, 0x80000000LL, 0x80000000ULL ) \
|
||||
f("0xfffffffe", BAD, max_juint-1, 0xfffffffeLL, 0xfffffffeULL ) \
|
||||
f("0xffffffff", BAD, max_juint, 0xffffffffLL, 0xffffffffULL ) \
|
||||
f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \
|
||||
f("-0x7fffffff", min_jint+1, BAD, -0x7fffffffLL, BAD ) \
|
||||
f("-0x80000000", min_jint, BAD, -0x80000000LL, BAD ) \
|
||||
f("-0x80000001", BAD, BAD, -0x80000001LL, BAD ) \
|
||||
\
|
||||
f("0x7ffffffffffffffe", BAD, BAD, max_jlong-1, 0x7ffffffffffffffeULL ) \
|
||||
f("0x7fffffffffffffff", BAD, BAD, max_jlong, 0x7fffffffffffffffULL ) \
|
||||
f("0x8000000000000000", BAD, BAD, BAD, 0x8000000000000000ULL ) \
|
||||
f("0xfffffffffffffffe", BAD, BAD, BAD, max_julong-1 ) \
|
||||
f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \
|
||||
f("0x10000000000000000", BAD, BAD, BAD, BAD ) \
|
||||
f("-0x7fffffffffffffff", BAD, BAD, min_jlong+1, BAD ) \
|
||||
f("-0x8000000000000000", BAD, BAD, min_jlong, BAD ) \
|
||||
f("-0x8000000000000001", BAD, BAD, BAD, BAD ) \
|
||||
\
|
||||
/* edge cases for suffix: K */ \
|
||||
f("0x1ffffek", 0x1ffffe * k, 0x1ffffeU * k,0x1ffffeLL * k, 0x1ffffeULL * k ) \
|
||||
f("0x1fffffk", 0x1fffff * k, 0x1fffffU * k,0x1fffffLL * k, 0x1fffffULL * k ) \
|
||||
f("0x200000k", BAD, 0x200000U * k,0x200000LL * k, 0x200000ULL * k ) \
|
||||
f("0x3ffffek", BAD, 0x3ffffeU * k,0x3ffffeLL * k, 0x3ffffeULL * k ) \
|
||||
f("0x3fffffk", BAD, 0x3fffffU * k,0x3fffffLL * k, 0x3fffffULL * k ) \
|
||||
f("0x400000k", BAD, BAD, 0x400000LL * k, 0x400000ULL * k ) \
|
||||
f("-0x1fffffk", -0x1fffff * k, BAD, -0x1fffffLL * k, BAD ) \
|
||||
f("-0x200000k", -0x200000 * k, BAD, -0x200000LL * k, BAD ) \
|
||||
f("-0x200001k", BAD, BAD, -0x200001LL * k, BAD ) \
|
||||
\
|
||||
f("0x1ffffffffffffek", BAD, BAD, 0x1ffffffffffffeLL * k, 0x1ffffffffffffeULL * k ) \
|
||||
f("0x1fffffffffffffk", BAD, BAD, 0x1fffffffffffffLL * k, 0x1fffffffffffffULL * k ) \
|
||||
f("0x20000000000000k", BAD, BAD, BAD, 0x20000000000000ULL * k ) \
|
||||
f("0x3ffffffffffffek", BAD, BAD, BAD, 0x3ffffffffffffeULL * k ) \
|
||||
f("0x3fffffffffffffk", BAD, BAD, BAD, 0x3fffffffffffffULL * k ) \
|
||||
f("0x40000000000000k", BAD, BAD, BAD, BAD ) \
|
||||
f("-0x1fffffffffffffk", BAD, BAD, -0x1fffffffffffffLL * k, BAD ) \
|
||||
f("-0x20000000000000k", BAD, BAD, -0x20000000000000LL * k, BAD ) \
|
||||
f("-0x20000000000001k", BAD, BAD, BAD, BAD ) \
|
||||
\
|
||||
/* edge cases for suffix: M */ \
|
||||
f("0x7fem", 0x7fe * m, 0x7feU * m, 0x7feLL * m, 0x7feULL * m ) \
|
||||
f("0x7ffm", 0x7ff * m, 0x7ffU * m, 0x7ffLL * m, 0x7ffULL * m ) \
|
||||
f("0x800m", BAD, 0x800U * m, 0x800LL * m, 0x800ULL * m ) \
|
||||
f("0xffem", BAD, 0xffeU * m, 0xffeLL * m, 0xffeULL * m ) \
|
||||
f("0xfffm", BAD, 0xfffU * m, 0xfffLL * m, 0xfffULL * m ) \
|
||||
f("0x1000m", BAD, BAD, 0x1000LL * m, 0x1000ULL * m ) \
|
||||
f("-0x7ffm", -0x7ff * m, BAD, -0x7ffLL * m, BAD ) \
|
||||
f("-0x800m", -0x800 * m, BAD, -0x800LL * m, BAD ) \
|
||||
f("-0x801m", BAD, BAD, -0x801LL * m, BAD ) \
|
||||
\
|
||||
f("0x7fffffffffem", BAD, BAD, 0x7fffffffffeLL * m, 0x7fffffffffeULL * m ) \
|
||||
f("0x7ffffffffffm", BAD, BAD, 0x7ffffffffffLL * m, 0x7ffffffffffULL * m ) \
|
||||
f("0x80000000000m", BAD, BAD, BAD, 0x80000000000ULL * m ) \
|
||||
f("0xffffffffffem", BAD, BAD, BAD, 0xffffffffffeULL * m ) \
|
||||
f("0xfffffffffffm", BAD, BAD, BAD, 0xfffffffffffULL * m ) \
|
||||
f("0x100000000000m", BAD, BAD, BAD, BAD ) \
|
||||
f("-0x7ffffffffffm", BAD, BAD, -0x7ffffffffffLL * m, BAD ) \
|
||||
f("-0x80000000000m", BAD, BAD, -0x80000000000LL * m, BAD ) \
|
||||
f("-0x80000000001m", BAD, BAD, BAD, BAD ) \
|
||||
\
|
||||
/* edge cases for suffix: G */ \
|
||||
f("0x0g", 0x0 * g, 0x0U * g, 0x0LL * g, 0x0ULL * g ) \
|
||||
f("0x1g", 0x1 * g, 0x1U * g, 0x1LL * g, 0x1ULL * g ) \
|
||||
f("0x2g", BAD, 0x2U * g, 0x2LL * g, 0x2ULL * g ) \
|
||||
f("0x3g", BAD, 0x3U * g, 0x3LL * g, 0x3ULL * g ) \
|
||||
f("0x4g", BAD, BAD, 0x4LL * g, 0x4ULL * g ) \
|
||||
f("-0x1g", -0x1 * g, BAD, -0x1LL * g, BAD ) \
|
||||
f("-0x2g", -0x2 * g, BAD, -0x2LL * g, BAD ) \
|
||||
f("-0x3g", BAD, BAD, -0x3LL * g, BAD ) \
|
||||
\
|
||||
f("0x1fffffffeg", BAD, BAD, 0x1fffffffeLL * g, 0x1fffffffeULL * g ) \
|
||||
f("0x1ffffffffg", BAD, BAD, 0x1ffffffffLL * g, 0x1ffffffffULL * g ) \
|
||||
f("0x200000000g", BAD, BAD, BAD, 0x200000000ULL * g ) \
|
||||
f("0x3fffffffeg", BAD, BAD, BAD, 0x3fffffffeULL * g ) \
|
||||
f("0x3ffffffffg", BAD, BAD, BAD, 0x3ffffffffULL * g ) \
|
||||
f("0x400000000g", BAD, BAD, BAD, BAD ) \
|
||||
f("-0x1ffffffffg", BAD, BAD, -0x1ffffffffLL * g, BAD ) \
|
||||
f("-0x200000000g", BAD, BAD, -0x200000000LL * g, BAD ) \
|
||||
f("-0x200000001g", BAD, BAD, BAD, BAD ) \
|
||||
\
|
||||
/* edge cases for suffix: T */ \
|
||||
f("0x7ffffet", BAD, BAD, 0x7ffffeLL * t, 0x7ffffeULL * t ) \
|
||||
f("0x7ffffft", BAD, BAD, 0x7fffffLL * t, 0x7fffffULL * t ) \
|
||||
f("0x800000t", BAD, BAD, BAD, 0x800000ULL * t ) \
|
||||
f("0xfffffet", BAD, BAD, BAD, 0xfffffeULL * t ) \
|
||||
f("0xfffffft", BAD, BAD, BAD, 0xffffffULL * t ) \
|
||||
f("0x1000000t", BAD, BAD, BAD, BAD ) \
|
||||
f("-0x7ffffft", BAD, BAD, -0x7fffffLL * t, BAD ) \
|
||||
f("-0x800000t", BAD, BAD, -0x800000LL * t, BAD ) \
|
||||
f("-0x800001t", BAD, BAD, BAD, BAD )
|
||||
|
||||
#define INTEGER_TEST_i32(s, i32, u32, i64, u64) NumericArgument<T>(s, i32),
|
||||
#define INTEGER_TEST_u32(s, i32, u32, i64, u64) NumericArgument<T>(s, u32),
|
||||
#define INTEGER_TEST_i64(s, i32, u32, i64, u64) NumericArgument<T>(s, i64),
|
||||
#define INTEGER_TEST_u64(s, i32, u32, i64, u64) NumericArgument<T>(s, u64),
|
||||
|
||||
// signed 32-bit
|
||||
template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)>
|
||||
void check_flag(const char* f, T getvalue(JVMFlag* flag)) {
|
||||
JVMFlag* flag = JVMFlag::find_flag(f);
|
||||
if (flag == NULL) { // not available in product builds
|
||||
return;
|
||||
}
|
||||
|
||||
T k = static_cast<T>(K);
|
||||
T m = static_cast<T>(M);
|
||||
T g = static_cast<T>(G);
|
||||
NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i32) };
|
||||
check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings));
|
||||
}
|
||||
|
||||
// unsigned 32-bit
|
||||
template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 4)>
|
||||
void check_flag(const char* f, T getvalue(JVMFlag* flag)) {
|
||||
JVMFlag* flag = JVMFlag::find_flag(f);
|
||||
if (flag == NULL) { // not available in product builds
|
||||
return;
|
||||
}
|
||||
|
||||
T k = static_cast<T>(K);
|
||||
T m = static_cast<T>(M);
|
||||
T g = static_cast<T>(G);
|
||||
NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u32) };
|
||||
check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings));
|
||||
}
|
||||
|
||||
// signed 64-bit
|
||||
template <typename T, ENABLE_IF(std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)>
|
||||
void check_flag(const char* f, T getvalue(JVMFlag* flag)) {
|
||||
JVMFlag* flag = JVMFlag::find_flag(f);
|
||||
if (flag == NULL) { // not available in product builds
|
||||
return;
|
||||
}
|
||||
|
||||
T k = static_cast<T>(K);
|
||||
T m = static_cast<T>(M);
|
||||
T g = static_cast<T>(G);
|
||||
T t = static_cast<T>(G) * k;
|
||||
NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i64) };
|
||||
check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings));
|
||||
}
|
||||
|
||||
// unsigned 64-bit
|
||||
template <typename T, ENABLE_IF(!std::is_signed<T>::value), ENABLE_IF(sizeof(T) == 8)>
|
||||
void check_flag(const char* f, T getvalue(JVMFlag* flag)) {
|
||||
JVMFlag* flag = JVMFlag::find_flag(f);
|
||||
if (flag == NULL) { // not available in product builds
|
||||
return;
|
||||
}
|
||||
|
||||
T k = static_cast<T>(K);
|
||||
T m = static_cast<T>(M);
|
||||
T g = static_cast<T>(G);
|
||||
T t = static_cast<T>(G) * k;
|
||||
NumericArgument<T> valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u64) };
|
||||
check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings));
|
||||
}
|
||||
|
||||
// Testing the parsing of -XX:<SomeFlag>=<an integer value>
|
||||
//
|
||||
// All of the integral types that can be used for command line options:
|
||||
// int, uint, intx, uintx, uint64_t, size_t
|
||||
//
|
||||
// In all supported platforms, these types can be mapped to only 4 native types:
|
||||
// {signed, unsigned} x {32-bit, 64-bit}
|
||||
//
|
||||
// We use SFINAE to pick the correct column in the INTEGER_TEST_TABLE for each type.
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_int) {
|
||||
check_flag<int>("TestFlagFor_int", [] (JVMFlag* flag) {
|
||||
return flag->get_int();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_uint) {
|
||||
check_flag<uint>("TestFlagFor_uint", [] (JVMFlag* flag) {
|
||||
return flag->get_uint();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_intx) {
|
||||
check_flag<intx>("TestFlagFor_intx", [] (JVMFlag* flag) {
|
||||
return flag->get_intx();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_uintx) {
|
||||
check_flag<uintx>("TestFlagFor_uintx", [] (JVMFlag* flag) {
|
||||
return flag->get_uintx();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_uint64_t) {
|
||||
check_flag<uint64_t>("TestFlagFor_uint64_t", [] (JVMFlag* flag) {
|
||||
return flag->get_uint64_t();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_size_t) {
|
||||
check_flag<size_t>("TestFlagFor_size_t", [] (JVMFlag* flag) {
|
||||
return flag->get_size_t();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_VM_F(ArgumentsTest, set_numeric_flag_double) {
|
||||
JVMFlag* flag = JVMFlag::find_flag("TestFlagFor_double");
|
||||
if (flag == NULL) { // not available in product builds
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO -- JDK-8282774
|
||||
// Need to add more test input that have a fractional part like "4.2".
|
||||
NumericArgument<double> valid_strings[] = {
|
||||
NumericArgument<double>("0", 0.0),
|
||||
NumericArgument<double>("1", 1.0),
|
||||
NumericArgument<double>("-0", -0.0),
|
||||
NumericArgument<double>("-1", -1.0),
|
||||
};
|
||||
|
||||
auto getvalue = [] (JVMFlag* flag) {
|
||||
return flag->get_double();
|
||||
};
|
||||
|
||||
check_numeric_flag<double>(flag, getvalue, valid_strings,
|
||||
ARRAY_SIZE(valid_strings), /*is_double=*/true);
|
||||
}
|
||||
|
||||
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/flags/jvmFlag.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
class LargeOptionsTest : public ::testing::Test {
|
||||
public:
|
||||
static bool test_option_value(const char* option, intx value) {
|
||||
char buffer[100];
|
||||
UnlockDiagnosticVMOptions = true;
|
||||
os::snprintf(buffer, 100, "%s=" INTX_FORMAT, option, value);
|
||||
return Arguments::parse_argument(buffer, JVMFlagOrigin::COMMAND_LINE);
|
||||
}
|
||||
|
||||
static bool test_option_value(const char* option) {
|
||||
UnlockDiagnosticVMOptions = true;
|
||||
return Arguments::parse_argument(option, JVMFlagOrigin::COMMAND_LINE);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _LP64
|
||||
// CompilerDirectivesLimit is a diagnostic int option.
|
||||
TEST_VM(LARGE_OPTION, large_ints) {
|
||||
for (intx x = max_jint - 1; x <= (intx)max_jint + 1; x++) {
|
||||
bool result = LargeOptionsTest::test_option_value("CompilerDirectivesLimit", x);
|
||||
if (x > max_jint) {
|
||||
ASSERT_FALSE(result);
|
||||
} else {
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(CompilerDirectivesLimit, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VM(LARGE_OPTION, small_ints) {
|
||||
for (intx x = min_jint + 1; x >= (intx)min_jint - 1; x--) {
|
||||
bool result = LargeOptionsTest::test_option_value("CompilerDirectivesLimit", x);
|
||||
if (x < min_jint) {
|
||||
ASSERT_FALSE(result);
|
||||
} else {
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(CompilerDirectivesLimit, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VM(LARGE_OPTION, large_int_overflow) { // Test 0x100000000
|
||||
ASSERT_FALSE(LargeOptionsTest::test_option_value("CompilerDirectivesLimit", 4294967296));
|
||||
}
|
||||
#endif
|
||||
|
||||
// HandshakeTimeout is a diagnostic uint option.
|
||||
TEST_VM(LARGE_OPTION, large_uints) {
|
||||
for (uintx x = max_juint - 1; x <= (uintx)max_juint + 1; x++) {
|
||||
bool result = LargeOptionsTest::test_option_value("HandshakeTimeout", x);
|
||||
if (x <= max_juint) {
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(HandshakeTimeout, x);
|
||||
} else {
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
// MaxJNILocalCapacity is an intx option.
|
||||
TEST_VM(LARGE_OPTION, large_intxs) {
|
||||
// max_intx + 1 equals min_intx!
|
||||
for (julong x = max_intx - 1; x <= (julong)max_intx + 1; x++) {
|
||||
ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", x));
|
||||
ASSERT_EQ((julong)MaxJNILocalCapacity, x);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VM(LARGE_OPTION, small_intxs) {
|
||||
ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", min_intx + 1));
|
||||
ASSERT_EQ(MaxJNILocalCapacity, -9223372036854775807);
|
||||
ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", min_intx));
|
||||
ASSERT_EQ(MaxJNILocalCapacity, min_intx);
|
||||
// Test value that's less than min_intx (-0x8000000000000001).
|
||||
ASSERT_FALSE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity=-9223372036854775809"));
|
||||
}
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user