-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8369186: HotSpot Style Guide should permit some uses of the C++ Standard Library #27601
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
base: master
Are you sure you want to change the base?
Conversation
29d7201
to
4759e6c
Compare
👋 Welcome back kbarrett! A progress list of the required criteria for merging this PR into |
@kimbarrett 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 |
@kimbarrett 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 pull request command. |
4759e6c
to
5db1aac
Compare
/label remove build |
@kimbarrett |
f03908f
to
d6723d8
Compare
@kimbarrett |
/label remove build |
@kimbarrett |
d6723d8
to
1c2f151
Compare
@kimbarrett |
1c2f151
to
f499567
Compare
/label remove build |
@kimbarrett |
f499567
to
98e7ccb
Compare
@kimbarrett |
/label remove build |
@kimbarrett |
doc/hotspot-style.md
Outdated
* `<tuple>` - Prefer named access to class objects, rather than indexed access | ||
to anonymous heterogeneous sequences. In particular, a standard-layout | ||
class is preferred to a tuple. | ||
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 gave this feedback offline, but I'll record it here as well. I think that the tuple section should go to the undecided section.
I understand the wish to go with named classes, and I often prefer that as well, but I also see that people often refrain from doing using them various reasons and instead use out-parameters or mix return values into one primitive. I don't want to fully close the door on this feature, and would like us to put this in the undecided (yes, still implicitly forbidden) section. To me that signals that we can at least experiment with it to see if it makes sense to sometimes use it (and if it does we can bring that back for discussion). Whereas outright forbidding it puts a stake in the ground and tells the story that we really shouldn't be looking at tuples. I think that's a too strong of a statement.
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 have a different take on the distinction between forbidden and undecided. I
think of forbidden features as being those where there are good arguments
against. Whereas I think of undecided as perhaps having wishy washy arguments
in either direction, or even not seriously thought about. But good arguments
against can be overcome by better arguments in favor.
But I can see how someone else might take that distinction differently.
I also admit to being somewhat biased against tuple in particular. I've seen
a few pretty terrible uses... one was even my fault!
So okay, I'll recategorize tuple.
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'm OK with cracking the door open on tuple, but I have to say I do like API-specific names very much. (And fst
/snd
or whatever are not API specific; they are tuple-specific!) So the guidance that steers folks towards name-based techniques, instead of positional techniques, is still sound.
I even like out-args, personally, in cases where the out-arg is for a return value that is clearly secondary to the main return value. Example: Main value is boolean, and out-arg is some hint about why the main value is what it is, like a position. The out-arg can also be optional if a null pointer is tolerated (explicitly documented as such, of course), which is useful when the out-arg costs extra to compute. (A separate boolean arg is OK for such uses also, but null pointers are so darn useful as optionality sentinels!) Note that our TRAPS/THREAD macro system can be viewed as a giant set of out-args.
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.
Often, we can use more "specialized" tuples like Maybe<T, Error>
, in which case it's fine to have the 'generic' _value
, _error
slots. Having a bigger sign saying "hey, hey!! this might fail!!!!" is good, it makes bugs related to missing error handling more shallow.
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. | |||
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. |
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.
So we have our own tuple ...
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.
We have our own baby partial tuple. What's there is more like a heterogeneous
array with compile-time indexing. It's used for one thing, and provides just
enough functionality for that use. I'm not entirely convinced it's the right
tool for the job, though I haven't taken the time to work out alternatives.
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 looked at the use of Tuple<...>. I think using named structs with named
members would be an improvement. Eliminates questions like is src element 0
and dst element 1, or is it the other way around.
Did you mean type_traits? |
Oops! Yes. Fixing description... |
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 like where this is going. Thanks for putting in the hard work to make it happen.
doc/hotspot-style.md
Outdated
* Memory allocation. HotSpot requires explicit control over where allocations | ||
occur. The C++98/03 `std::allocator` class is too limited to support our | ||
usage. But changes to the allocator concept in more recent Standards removed | ||
some of the limitations, supporting statefull allocators. HotSpot may, in 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.
s/statefull/stateful/
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.
Fixed locally for next push.
names into scope via a `using std;` directive. Doing so makes writing code | ||
using those names easier, since the qualifiers don't need to be included. But | ||
there are reasons not to do that. | ||
|
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.
s/reasons/several reasons/ (to better tee up the following bullet list)
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.
Fixed locally for next push.
* There is a risk of future name collisions. Additional Standard Library | ||
headers may be included, adding to the list of names being used. Also, | ||
future versions of the Standard Library may add currently unknown names to | ||
the headers already being included. |
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.
Maybe mention the assert
macro at the end of the bullet, if there is no other example of a previous name collision:
…already being included. (We already have a conflict from the HotSpot
assert
macro, although in that case thestd::
prefix is not applicable.)
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.
There aren't any previous examples because we don't have any examples of doing
this thing that we're warning against (using
a namespace). assert
is a
different problem, unrelated to namespaces. (Remember that one of the usual
knocks against macros is that they don't respect namespaces.)
* `<ratio>` | ||
* `<system_error>` | ||
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.
To continue the roll of rationale, for chrono
etc., here are some suggestions which I am just pulling out of my back pocket:
"HotSpot has its own timing support APIs."
"Initializer lists are an advanced C++ API feature which have surprising interactions with other initialization syntaxes in use in HotSpot."
"HotSpot uses floating point numbers, which are more portable and have more predictable performance characteristics than rational arithmetic."
"HotSpot has its own mechanisms for managing errors."
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'll add some stuff to the PR change.
"HotSpot has its own timing support APIs."
The argument for chrono is that our existing APIs aren't serving us well.
chrono provides strong type safety. We've had multiple cases of mistakes like
a double seconds being treated as double millis or vice versa, and other
similar errors. But it would be a large effort to adopt chrono. And we'd need
to decide whether to use the predefined clocks or hook up chrono to our
clocks. It may be that using the predefined clocks is fine, but it's a
question that needs careful study.
"Initializer lists are an advanced C++ API feature which have surprising
interactions with other initialization syntaxes in use in HotSpot."
I think the trailing "in use in HotSpot" can be dropped from that. Mostly I
think they are fine, but the potential ambiguity between some forms of direct
initialization and initializer list initialization, and the resolution of that
ambiguity, is unfortunate.
"HotSpot uses floating point numbers ..."
Note that <ratio>
is a compile-time rational arithmetic package. It's also
fixed (though parameterized) precision. It's not a general purpose rational
arithmetic facility. My understanding is that it started life as a detail of
chrono, and was extracted and promoted to a public facility in the belief that
it has broader utility.
"HotSpot has its own mechanisms for managing errors."
Well, no, we don't really. Or rather, we've got a plethora of bespoke ad hoc
mechanisms. There's a bunch of discussion happening around that topic lately.
I don't think we've coalesced around any particular approach yet. And even
once we decided on something it's likely to take quite a while for rollout to
really make use of whatever we settle on.
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 love a good nerd sniping! Thanks.
doc/hotspot-style.md
Outdated
* `<tuple>` - Prefer named access to class objects, rather than indexed access | ||
to anonymous heterogeneous sequences. In particular, a standard-layout | ||
class is preferred to a tuple. | ||
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'm OK with cracking the door open on tuple, but I have to say I do like API-specific names very much. (And fst
/snd
or whatever are not API specific; they are tuple-specific!) So the guidance that steers folks towards name-based techniques, instead of positional techniques, is still sound.
I even like out-args, personally, in cases where the out-arg is for a return value that is clearly secondary to the main return value. Example: Main value is boolean, and out-arg is some hint about why the main value is what it is, like a position. The out-arg can also be optional if a null pointer is tolerated (explicitly documented as such, of course), which is useful when the out-arg costs extra to compute. (A separate boolean arg is OK for such uses also, but null pointers are so darn useful as optionality sentinels!) Note that our TRAPS/THREAD macro system can be viewed as a giant set of out-args.
#include "code/compiledIC.hpp" | ||
#include "code/nmethod.hpp" | ||
#include "code/relocInfo.hpp" | ||
#include "cppstdlib/type_traits.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.
(I really, really like this scheme of wrapper headers for std stuff. Thanks Kim!)
// permitted: | ||
// * std::max_align_t, std::nullptr_t | ||
// * size_t (preferred) and std::size_t | ||
// * ptrdiff_t (preferred) and std::ptrdiff_t |
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.
Are we 100% sure that size_t
and ptrdiff_t
will always be the std
versions, on all platforms?
If not, uses of std::size_t
and std::ptrdiff_t
might turn out to be portability problems.
…Should I worry that std::size_t
and size_t
might be different types on some weirdo platform??
Maybe we should do a static-assert that those two names refer to the same type.
Then we can prove that the std::
prefix will never cause the meaning of size_t
to shift, on any platform.
I'm being a little paranoid here about possible failure modes specifically for size_t
,
specifically because size_t
is so pervasive and sensitive to type bugs.
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.
Are we 100% sure ...
Yes.
Should I worry ...
No.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2340r0.html
Clarifying the status of the "C headers"
On the basis of that paper, C++23 undeprecated the C headers (they'd been
deprecated since C++98) and gave them their own section in the main body of
the standard, rather than being relegated to an appendix.
The guidance is that a C++ source file should only include C headers if the
file also needs to be valid C source. I'm planning to nudge us in that
direction, except by using our own wrapper headers, like cppstdlib/cstddef.hpp.
@kimbarrett this pull request can not be integrated into git checkout stdlib-header-wrappers
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
Functions that may throw exceptions must not be used. This is in accordance | ||
with the HotSpot policy of [not using exceptions](#error-handling). |
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.
In the GCC implementation, destructor registration may throw __gnu_cxx::recursive_init_error
(via the __cxa_guard_acquire
Itanium ABI function). Are global or static objects with non-trivial destructors permitted? I think there are a couple of such uses today.
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.
We (you and me, @fweimer-rh) discussed this a couple of years ago:
https://mail.openjdk.org/pipermail/hotspot-dev/2023-December/082324.html
Quoting from here:
https://mail.openjdk.org/pipermail/hotspot-dev/2023-December/083142.html
"
Empirically, a recursive initialization attempt doesn't make any attempt to
throw. Rather, it blocks forever waiting for a futex signal from a thread that
succeeds in the initialization. Which of course will never come.
And that makes sense, now that I've looked at the code.
In __cxa_guard_acquire, with _GLIBCXX_USE_FUTEX, if the guard indicates
initialization hasn't yet been completed, then it goes into a while loop.
This while loop tries to claim initialization. Failing that, it checks
whether initialization is complete. Failing that, it does a SYS_futex
syscall, waiting for some other thread to perform the initialization. There's
nothing there to check for recursion.
throw_recursive_init_exception is only called if single-threaded (either by
configuration or at runtime).
"
It doesn't look like there have been any relevant changes in that area since
then. So I think there is still not a problem here.
It is discouraged but yes they exist and cause problems. I am currently fixing a bunch of issues due to static Semaphore instances. https://bugs.openjdk.org/browse/JDK-8361462 |
Please review this change to the HotSpot Style Guide to suggest that C++
Standard Library components may be used, after appropriate vetting and
discussion, rather than just a blanket "no, don't use it" with a few very
narrow exceptions. It provides some guidance on that vetting process and
the criteria to use, along with usage patterns.
In particular, it proposes that Standard Library headers should not be
included directly, but instead through HotSpot-provided wrapper headers. This
gives us a place to document usage, provide workarounds for platform issues in
a single place, and so on.
Such wrapper headers are provided by this PR for
<cstddef>
,<limits>
, and<type_traits>
, along with updates to use them. I have a separate change for<new>
that I plan to propose later, under JDK-8369187. There will beadditional followups for other C compatibility headers besides
<cstddef>
.This PR also cleans up some nomenclature issues around forbid vs exclude and
the like.
Testing: mach5 tier1-5, GHA sanity tests
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/27601/head:pull/27601
$ git checkout pull/27601
Update a local copy of the PR:
$ git checkout pull/27601
$ git pull https://git.openjdk.org/jdk.git pull/27601/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 27601
View PR using the GUI difftool:
$ git pr show -t 27601
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/27601.diff
Using Webrev
Link to Webrev Comment