-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8362885: A more formal way to mark javac's Flags that belong to a specific Symbol type only #26452
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
…cific Symbol type only
👋 Welcome back jlahoda! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
@lahodaj The |
/label remove build |
@lahodaj |
Webrevs
|
This looks like a really nice improvement for maintainability. ? Would it make more sense (and/or be simpler?) to move the conflict-checking logic into It somehow seems odd to have a tool which can knowingly generate an invalid ? Is it worth adding some simple runtime check for correct For example (just brainstorming):
(Of course even better would be to check this at compile time using stronger typing (e.g., by replacing |
|
||
private static void printFreeFlags(String comment, long freeFlags) { | ||
System.err.print("free flags for " + comment + ": "); | ||
for (int bit = 16; bit < 64; bit++) { //lowest 16 bits are used in classfiles, never suggest adding anything there |
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.
Replace 16 with Character.SIZE and 64 with Long.SIZE?
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 think Character.SIZE
is really appropriate, but I've declared U2_SIZE
for 16
, and used Long.SIZE
for 64
.
|
||
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(Paths.get(args[1])))) { | ||
out.println(""" | ||
package com.sun.tools.javac.code; |
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 we need a license header for generated sources?
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.
CompilerProperties
and other files that are generated using similar means don't have license headers, so I assume we don't need that.
} | ||
|
||
private static void verifyFlagsNonOverlapping() throws Throwable { | ||
Map<FlagTarget, Map<Long, List<Field>>> target2Flag2Fields = computeTarget2Flag2Fields(); |
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.
You could calculate this once in main and pass to verifyFlagNonOverlapping
and findFreeFlags
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.
Given this is a test, I would prefer to keep the test cases separate. This is a bit moot now, as the test is no doing the verification anymore.
- when conflict is detected, the generator fails - adding runtime checks - using constants for number of bits
public static final int StandardFlags = 0x0fff; | ||
|
||
// Because the following access flags are overloaded with other | ||
// bit positions, we translate them when reading and writing class | ||
// files into unique bits positions: ACC_SYNTHETIC <-> SYNTHETIC, | ||
// for example. | ||
@NotFlag | ||
public static final int ACC_SUPER = 0x0020; |
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 didn't we add annotation on these ACC ones? After all, they also overlap with previous flags -- e.g. ACC_SUPER overlaps with SYNCHRONIZED, and it works because the former goes on types and the latter on methods. So, isn't this the same trick we're pulling?
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.
Done.
…plit of the TYPE target into CLASS/MODULE/PACKAGE/TYPE_VARIABLE.
@@ -167,8 +168,11 @@ private static Object valueOfValueAttribute(AnnotationMirror am) { | |||
|
|||
public enum FlagTarget { |
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.
Just flyby comment: symbol kind is an enum, so in principle we could use constants such as MTH, VAR, TYP as targets, if we wanted to connect the decls more with the actual code. But I like your approach as well (as symbol kind has also a lot of other more dubious stuff/noise)
Done.
I've added the checks. It may be useful, but it is somewhat limited, as it cannot detect the most dangerous case where the flag with overloaded meaning is set incorrectly.
There were several experiments, in the past and currently ongoing, but it is difficult to do something that is safer and does not cost too much on performance/memory consumption. Value classes may or may not help. |
@@ -2127,6 +2127,9 @@ private boolean needPackageInfoClass(JCPackageDecl pd) { | |||
} | |||
|
|||
public void visitModuleDef(JCModuleDecl tree) { | |||
FlagsEnum.assertNoUnexpectedFlags(tree.sym.flags_field, |
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.
Not super sure about rolling this into Lower... but a separate visitor will also look a bit "too much"...
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.
For instance, for type variables there's no way to check them at this point?
There's a lot to like in this patch. Now flags cannot erroneously overlap, which will give us all javac developers more confidence that we're not stepping into each other toes. Also, by making the mechanism more formally correct, it's easier to see which "holes" we have available (and there's probably quite a lot left). The only thing I'm unsure of, as pointed out in the review, is the dynamic checks. I believe that, as far as this PR is concerned, this feels like "scope creep". I think it would be cleaner if this PR only concerned about introducing the machinery. Then maybe we can brainstorm separately on what would be the best way to add some of these checks (but I'm skeptical that we can find anything that doesn't feel like a compromise). For instance, another way to do this could be to do another combo test like the tree test, where we compile all the existing tests, and check the validity of all the flags on all the symbols. That's an offline way to make sure that what we do in javac is "sort of" correct, but one that doesn't leak into the code. The real fix for this, as we know (and as @archiecobbs commented) is to move away from longs, but that's not what this PR is about. |
This PR proposes to improve handling of javac's
Flags
in two ways:TypeSymbol
s,MethodSymbol
s andVarSymbol
s. If we ran out of flags forTypeSymbol
s, we could split those to module/package/class/type variable, but it does not seem to be quite necessary yet. There's an auxiliary specialBLOCK
, which is forJCBlock
.Flags.Flag
enum is replaced with autogeneratedFlagsEnum
This is inspired by:
#26181 (review)
There may be some better to handle
Flags
eventually, but this hopefully improves the current situation at least somewhat, by providing more formal way to say the flags' target, and restricting the need to read comments and search for free flags.As a side-effect of this annotation, the
test/langtools/tools/javac/flags/FlagsTest.java
now also prints which flags are free, for each Symbol type.(I will remove the
build
label for now, until discussion on javac level is done, and will re-add it if we decide the goal to autogenerate the FlagsEnum makes sense.)/label remove build
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/26452/head:pull/26452
$ git checkout pull/26452
Update a local copy of the PR:
$ git checkout pull/26452
$ git pull https://git.openjdk.org/jdk.git pull/26452/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 26452
View PR using the GUI difftool:
$ git pr show -t 26452
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/26452.diff
Using Webrev
Link to Webrev Comment