From 3328b4ecf225f95edfce6ab848dcfb62ddc1aaff Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Tue, 19 Nov 2024 19:13:09 +0000 Subject: [PATCH] 8343700: ceil_log2 should not loop endlessly Reviewed-by: shade, kbarrett, aph, stuefe --- src/hotspot/share/classfile/dictionary.cpp | 2 +- src/hotspot/share/utilities/powerOfTwo.hpp | 9 ++-- .../gtest/utilities/test_powerOfTwo.cpp | 43 ++++++++++++++++++- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp index 73d58ac3687..92f362860eb 100644 --- a/src/hotspot/share/classfile/dictionary.cpp +++ b/src/hotspot/share/classfile/dictionary.cpp @@ -44,7 +44,7 @@ const size_t REHASH_LEN = 100; Dictionary::Dictionary(ClassLoaderData* loader_data, size_t table_size) : _number_of_entries(0), _loader_data(loader_data) { - size_t start_size_log_2 = MAX2(ceil_log2(table_size), (size_t)2); // 2 is minimum size even though some dictionaries only have one entry + size_t start_size_log_2 = MAX2(ceil_log2(table_size), 2); // 2 is minimum size even though some dictionaries only have one entry size_t current_size = ((size_t)1) << start_size_log_2; log_info(class, loader, data)("Dictionary start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", current_size, start_size_log_2); diff --git a/src/hotspot/share/utilities/powerOfTwo.hpp b/src/hotspot/share/utilities/powerOfTwo.hpp index 786977a347f..6c1e413f403 100644 --- a/src/hotspot/share/utilities/powerOfTwo.hpp +++ b/src/hotspot/share/utilities/powerOfTwo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -122,10 +122,9 @@ inline T next_power_of_2(T value) { // Find log2 value greater than this input template ::value)> -inline T ceil_log2(T value) { - T ret; - for (ret = 1; ((T)1 << ret) < value; ++ret); - return ret; +inline int ceil_log2(T value) { + assert(value > 0, "Invalid value"); + return log2i_graceful(value - 1) + 1; } // Return the largest power of two that is a submultiple of the given value. diff --git a/test/hotspot/gtest/utilities/test_powerOfTwo.cpp b/test/hotspot/gtest/utilities/test_powerOfTwo.cpp index 4d16e13ab31..fc4080bcefd 100644 --- a/test/hotspot/gtest/utilities/test_powerOfTwo.cpp +++ b/test/hotspot/gtest/utilities/test_powerOfTwo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -305,3 +305,44 @@ TEST(power_of_2, log2i) { check_log2i_variants_for((uint)0); check_log2i_variants_for((jlong)0); } + +template void test_ceil_log2() { + EXPECT_EQ(ceil_log2(T(1)), 0) << "value = " << T(1); + EXPECT_EQ(ceil_log2(T(2)), 1) << "value = " << T(2); + EXPECT_EQ(ceil_log2(T(3)), 2) << "value = " << T(3); + EXPECT_EQ(ceil_log2(T(4)), 2) << "value = " << T(4); + EXPECT_EQ(ceil_log2(T(5)), 3) << "value = " << T(5); + EXPECT_EQ(ceil_log2(T(6)), 3) << "value = " << T(6); + EXPECT_EQ(ceil_log2(T(7)), 3) << "value = " << T(7); + EXPECT_EQ(ceil_log2(T(8)), 3) << "value = " << T(8); + EXPECT_EQ(ceil_log2(T(9)), 4) << "value = " << T(9); + EXPECT_EQ(ceil_log2(T(10)), 4) << "value = " << T(10); + + // Test max values + if (std::is_unsigned::value) { + EXPECT_EQ(ceil_log2(std::numeric_limits::max()), + (int)(sizeof(T) * 8)) << "value = " << std::numeric_limits::max(); + } else { + EXPECT_EQ(ceil_log2(std::numeric_limits::max()), + (int)(sizeof(T) * 8 - 1)) << "value = " << std::numeric_limits::max(); + } +} + +TEST(power_of_2, ceil_log2) { + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); + test_ceil_log2(); +} + +#ifdef ASSERT +TEST_VM_ASSERT_MSG(power_of_2, ceil_log2_invalid, + ".*Invalid value") { + ceil_log2(0); +} + +#endif // ASSERT