New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8253402: Convert vmSymbols::SID to enum class #276
8253402: Convert vmSymbols::SID to enum class #276
Conversation
👋 Welcome back iklam! A progress list of the required criteria for merging this PR into |
@iklam The following labels will be automatically applied to this pull request: When this pull request is ready to be reviewed, an RFR email will be sent to the corresponding mailing lists. If you would like to change these labels, use the |
/label remove serviceability |
@iklam |
@@ -29,6 +29,8 @@ | |||
#include "ci/ciObject.hpp" | |||
#include "utilities/growableArray.hpp" | |||
|
|||
enum class vmSymbolID : int; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need this declaration to avoid #include "classfile/vmSymbols.hpp" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's the intention, because vmSymbols.hpp is big.
I am thinking whether I should move such forward declarations of enums into globalDefinitions.hpp, so header files that use vmSymbolID
don't need to know that the base type is int
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, don't move them to globalDefinitions.hpp, only have the forward declarations where they're used. So this is like a class forward declaration? neat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about having a new header file utilities/vmEnums.hpp that looks like this:
// Include this header file if you just need the following enum types and
// you don't use their members directly. This way you don't need to include the
// complex header files that have the full definitions of these enums.
enum JVMFlagsEnum : int;
enum class vmSymbolID : int;
My plan is to have at least 2 more such enums (one for vmIntrinsics::ID
, and one for SystemDictionary::WKID
).
: int
is the base type of the enum. I think that's part of the type's implementation so it shouldn't be exposed to the user of these types. If we litter enum class vmSymbolID : int;
all over, when we decide to change the base type to something else, we would need to edit all such places.
Worse, if your forward declaration is wrong, like
enum class vmSymbolID : char;
the compiler won't detect this if your source file doesn't also include vmSymbols.hpp, so it could be dangerous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am okay with this suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved the forward declarations into vmEnum.hpp in the latest version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can't find it. Why did you have to add this little file to replace the forward declarations? What was wrong with the forward declarations? There weren't that many.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI and JVMCI changes seem fine. I did not look in details on the rest.
@iklam This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been no new commits pushed to the ➡️ To integrate this PR with the above commit message to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a nice improvement to me.
@@ -29,6 +29,8 @@ | |||
#include "ci/ciObject.hpp" | |||
#include "utilities/growableArray.hpp" | |||
|
|||
enum class vmSymbolID : int; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, don't move them to globalDefinitions.hpp, only have the forward declarations where they're used. So this is like a class forward declaration? neat.
// complex header files that have the full definitions of these enums. | ||
|
||
enum JVMFlagsEnum : int; | ||
enum class vmSymbolID : int; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like that you mixed two different enums that are used in different places here. Can you go back?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intention is to put other enums like vmIntrinsics::ID and SystemDictionary::WKID here. It's going to be a small collection of "enums used by the VM that have complex definitions but you probably don't care".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good.
@@ -0,0 +1,93 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are problems with this EnumIterator class. It was based in part on a prototype of mine, which I've been revisiting and revising, because I think it has problems. That prototype, in turn, was based on the existing WeakProcessorPhases::Iterator, which I think has some of the same failings. And I think this version expands on some of those problems. I don't yet have a full review, but below are some observations and issues. I'm working on an alternative.
A fundamental question is what style of "iterator" do we want.
(1) One style is self-contained; you create a single iterator which knows both the current position and the iteration limit, and step until a predicate (is_end() in the current code) is true.
(2) Another style is to have a pair of iterators, one designating the current position and the other designating the iteration limit. This is the style used by the C++ Standard Library.
Both my earlier prototype and the EnumIterator in this PR are 1-style but attempt (not necessarily very well, in my opinion) to also provide 2-style behavior. The point of that currently seems to be to support the new "range-based for" feature. (Said feature is currently not in the permitted list according to the Style Guide. I intentionally left it out because I think its utility is pretty strongly dependent on adopting 2-style iterators, which is not very well motivated without using the Standard Library.)
One requirement for an enum iterator (for me) is that it doesn't require a "fake" enumerator that designates the exclusive end of the range. The current proposal fails that test.
A problem with all of the variants is that they are trying to be both 1-style (providing is_end) and 2-style (providing being/end), with the result that they do neither well. This is especially true for the variant in the PR. I think part of the problem is that the begin/end functions don't belong to the iterator class; they should be part of a separate range class.
Aside: I think it is possible to provide iteration that doesn't assume sequential enumerators if one is willing to have some code duplication or has an enum that is x-macro based. While possibly an interesting exercise, I doubt that's worth pursuing. Just mentioning it in case anyone thinks this would actually useful.
I'm not certain how to proceed. Maybe this should be moved elsewhere as not yet ready to be a widely used "utility"? Or maybe go ahead with it with the intention of improving it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Kim, I have integrated the 2-style enumerator that you sent me off-line. Usage info (see enumIterator.hpp for details).
// Example (see vmSymbols.hpp/cpp)
//
// ENUMERATOR_RANGE(vmSymbolID, vmSymbolID::FIRST_SID, vmSymbolID::LAST_SID)
// constexpr EnumRange<vmSymbolID> vmSymbolsRange;
// using vmSymbolsIterator = EnumIterator<vmSymbolID>;
//
// /* Without range-based for, allowed */
// for (vmSymbolsIterator it = vmSymbolsRange.begin(); it != vmSymbolsRange.end(); ++it) {
// vmSymbolID index = *it; ....
// }
//
// /* With range-base for, not allowed by HotSpot coding style yet */
// for (vmSymbolID index : vmSymbolsRange) {
// ....
// }
I have rewritten all the iteration loops using the "Without range-based for" style. We can change to the "With range-base for" style when the HotSpot Coding Style Guide allows it.
@iklam this pull request can not be integrated into git checkout 8253402-convert-vmsymbols-sid-to-enum-class
git fetch https://git.openjdk.java.net/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
return (id >= FIRST_SID && id < SID_LIMIT); | ||
} | ||
static constexpr bool is_valid_id(vmSymbolID sid) { | ||
return (static_cast<int>(sid) >= FIRST_SID && static_cast<int>(sid) < SID_LIMIT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just return is_valid_id(static_cast<int>(sid));
VM_SYMBOLS_DO(VM_SYMBOL_IGNORE, VM_ALIAS_ENUM) | ||
#undef VM_ALIAS_ENUM | ||
static constexpr int number_of_symbols() { | ||
return SID_LIMIT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SID_LIMIT includes NO_SID, so this seems to be off-by-one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed NO_SID to -1 so SID_LIMIT no longer includes NO_SID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed to revert NO_SID to 0. There's an assert in vmSymbols.cpp for Symbol::_vm_symbols[NO_SID] == NULL
. This is pre-existing code and I don't understand why, but I should leave it as. As you can see in the old code, NO_SID is also counted as "part of the symbols"
- static vmSymbols::SID vm_symbol_index[vmSymbols::SID_LIMIT];
+ static vmSymbolID vm_symbol_index[vmSymbols::number_of_symbols()];
|
||
FIRST_SID = NO_SID + 1 | ||
}; | ||
enum { | ||
log2_SID_LIMIT = 11 // checked by an assert at start-up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[pre-existing, could be followup]
Why isn't this checked with a static assert right here?
SID_LIMIT <= (1 << log2_SID_LIMIT)
is (and always has been) compile-time checkable. And log2_SID_LIMIT should no longer be an enum. (Note that the value isn't currently constexpr-calculable because round_up_power_of_2 can't currently be constexpr.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing code groups several asserts together. I think this makes the intention clearer. I'll leave it for now.
void vmSymbols::initialize(TRAPS) {
assert(SID_LIMIT <= (1<<log2_SID_LIMIT), "must fit in this bitfield");
assert(SID_LIMIT*5 > (1<<log2_SID_LIMIT), "make the bitfield smaller, please");
assert(vmIntrinsics::FLAG_LIMIT <= (1 << vmIntrinsics::log2_FLAG_LIMIT), "must fit in this bitfield");
}; | ||
|
||
template<typename T> | ||
class EnumIterationTraits : AllStatic { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment for this class might be helpful. Something like "A helper class for EnumIterator, computing some additional information the iterator uses, based on T and EnumeratorRange." The main point being that users of enum iteration don't need to think about this.
// Don't bother trying to figure this out. | ||
// | ||
// | ||
// EnumIterationTraits -- defines the static range of all possible values of the enum. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This traits class isn't really interesting to users of this facility; it's more of an implementation detail. See my comment below on the definition. It's EnumeratorRange and (especially) ENUMERATOR_RANGE that are interesting to users.
assert(_value <= Traits::_end, "out of range"); | ||
} | ||
|
||
// True if the enumerators designate the same value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"True if the iterators designate the same enumeration value." (Sorry about that.) Similarly below for operator!=.
/integrate |
Convert
vmSymbols::SID
to anenum class
to provide better type safety.vmSymbols::SID
cannot be forward-declared. I moved it out of thevmSymbols
class and renamed, so now it can be forward-declared asenum class vmSymbolID : int;
, without including the large vmSymbols.hpp file.vmSymbols
andvmIntrinsics
classes. Now the declaration ofvmIntrinsics
can be moved from vmSymbols.hpp to vmIntrinsics.hpp, where it naturally belongs.vmSymbols::_symbols[]
toSymbol::_vm_symbols[]
, and made it accessible viaSymbol::vm_symbol_at()
. This way, header files (e.g. fieldInfo.hpp) that need to convert fromvmSymbolID
toSymbol*
don't need to include the large vmSymbols.hpp file.VM_SYMBOL_ENUM_NAME
macro so that the users don't need to explicitly add thevmSymbolID::
scope.int
andvmSymbolID
.vmSymbol::as_int()
andvmSymbols::as_SID()
with range checks.If this is successful, I will do the same for
vmIntrinsics::ID
.Progress
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/276/head:pull/276
$ git checkout pull/276