Skip to content

8263102: Expand documention of Method.isBridge #2852

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

Closed
wants to merge 9 commits into from

Conversation

jddarcy
Copy link
Member

@jddarcy jddarcy commented Mar 5, 2021

The existing documentation of Method.isBridge isn't terribly helpful to the reader. This RFE proposes to given a common example of how bridge methods are used. The JLS does not have a section discussing bridge methods in detail; bridge methods are a compilation technique for lowering the Java language to the JVM, they are not a language feature per se. The example given is not exhaustive; there can be and are other uses of bridge methods.

Once the text is agreed to; I'll update the copyright year as well.


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

Reviewers

Download

$ git fetch https://git.openjdk.java.net/jdk pull/2852/head:pull/2852
$ git checkout pull/2852

@bridgekeeper
Copy link

bridgekeeper bot commented Mar 5, 2021

👋 Welcome back darcy! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Mar 6, 2021

@jddarcy The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Mar 6, 2021
@openjdk openjdk bot added the rfr Pull request is ready for review label Mar 6, 2021
@mlbridge
Copy link

mlbridge bot commented Mar 6, 2021

Webrevs

@liach
Copy link
Member

liach commented Mar 7, 2021

I suggest briefly mentioning generic specialization as an example as well.

* method calls its non-bridge counterpart and returns its
* result. (While the Java language specification forbids a class
* declaring two methods with the same parameter types but a
* different return type, the virtual machine does not.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm of two minds about this. This is certainly a good example of a bridge method. It doesn't motivate why a bridge method is necessary in this case. It think it's because the language says you should be able to write code like

    EnumSet<E> es2 = es.clone();

so there needs to be a method defined in the class file whose return type is assignment-compatible with EnumSet. However, a clone method that returns Object is the only one that can override the Object::clone method. Thus, a something is necessary to span this gap -- a bridge method.

On the other hand, this might be too much detail for here. This is a really obscure location. It seems like somewhere else would be better, and where a full explanation with examples can be provided.

*
* <p>Bridge methods may also be used by Java compiler in other
* circumstances to span across difference in Java Language
* semantics and JVM semantics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you decide to put less detail here, you could start with this statement. I think the main point is that there are some semantic gaps between methods in the Java language and in the JVM; bridge methods are necessary to "span" this gap. You might simply list some examples without explaining them fully.

Would this be "used by a Java compiler" or "used by the Java compiler?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo "created" should be better. Is there any case where a java compiler accepts bridge methods generated?

@mlbridge
Copy link

mlbridge bot commented Mar 9, 2021

Mailing list message from Joe Darcy on core-libs-dev:

Hi Stuart,

On 3/8/2021 6:02 PM, Stuart Marks wrote:

On Sat, 6 Mar 2021 17:44:18 GMT, Joe Darcy <darcy at openjdk.org> wrote:

The existing documentation of Method.isBridge isn't terribly helpful to the reader. This RFE proposes to given a common example of how bridge methods are used. The JLS does *not* have a section discussing bridge methods in detail; bridge methods are a compilation technique for lowering the Java language to the JVM, they are not a language feature per se. The example given is not exhaustive; there can be and are other uses of bridge methods.

Once the text is agreed to; I'll update the copyright year as well.
Joe Darcy has updated the pull request incrementally with one additional commit since the last revision:

Improve linkage for isSynethetic.
src/java.base/share/classes/java/lang/reflect/Method.java line 593:

591: * result. (While the Java language specification forbids a class
592: * declaring two methods with the same parameter types but a
593: * different return type, the virtual machine does not.)
I'm of two minds about this. This is certainly a good example of a bridge method. It doesn't motivate _why_ a bridge method is necessary in this case. It think it's because the language says you should be able to write code like
EnumSet<E> es2 = es.clone();
so there needs to be a method defined in the class file whose return type is assignment-compatible with `EnumSet`. However, a `clone` method that returns `Object` is the only one that can override the `Object::clone` method. Thus, a something is necessary to span this gap -- a bridge method.

On the other hand, this might be too much detail for here. This is a really obscure location. It seems like somewhere else would be better, and where a full explanation with examples can be provided.

If someone is looking at isBridge and wondering what it does, having
some discussion there some reasonable :-)

The text in question is not intended to be exhaustive and the exact use
of bridge methods can, in principle, be Java compiler dependent.

Also, if in the future there are new JVM/platform facilities added so
that bridge methods are not necessarily required for the cases where
they are now used, I intended to write this text so it would still be
correct.

Thanks,

-Joe

* declaring two methods with the same parameter types but a
* different return type, the virtual machine does not.
* A
* common case where covariant overrides are used is for a {@link
Copy link
Member

@forax forax Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the example should be clearer because here, you don't show the code of EnumSet.clone().
I wonder if it's not easier if all the code is visible

  interface I {
    Object m();
  }
  class A implements I {
    String m() { return "hello"; }
  }

so you can explain that the VM do the dispatch on I::m()Object so the compiler has to insert a method A::m()Object,
the bridge method with this pseudo-code

  class A implements I {
    /* bridge */ Object m() { return m(); } // calls m()String
    String m()  { return "hello"; }
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Remi,

Thanks for the feedback. I did consider that kind of approach of an example from scratch. I judged referencing instances of bridge methods in the base module to be helpful to demonstrate it wasn't too esoteric of a feature in terms of it is something you, as a developer, may already have seen. Also, given the likely audience of the reading Class.isBridge, I didn't think a stand-alone example was warranted.

Copy link
Member

@stuart-marks stuart-marks Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prose description here and is still rather clumsy, though. If you're going to use EnumSet.clone() as an example, maybe run with that and list the methods directly instead of saying "EnumSet.clone() returns EnumSet rather than Object", be more explicit. Maybe something like the following:

The Object class has the method:
Object clone()
whereas the EnumSet class has this method:
EnumSet<E> clone()
From the JVM's perspective, the second method doesn't override the first, because they have different return types. The Java compiler provides a proper override by inserting the following bridge method into the EnumSet class:
Object clone()
that simply calls the second method and returns its result.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jddarcy, the problem i see is that EnumSet is not used a lot and clone has another layer of complexity because of CloneNotSupportedException, etc.
So i'm not sure that using EnumSet.clone() is the right example here.

Perhaps String.compareTo()/Comparable.compareTo() is a better example ? But generics are in the middle too.

* code.
* Bridge methods are used by Java compilers in various
* circumstances to span across differences in Java programming
* language semantics and JVM semantics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quibble: "span across" => "span"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, also maybe need a

tag here.

@openjdk
Copy link

openjdk bot commented Mar 9, 2021

@jddarcy 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:

8263102: Expand documention of Method.isBridge

Reviewed-by: smarks

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 44 new commits pushed to the master branch:

  • d0c1aec: 8263140: Japanese chars garble in console window in HSDB
  • 70342e8: 8262520: Add SA Command Line Debugger support to connect to debug server
  • e5ce97b: 8263206: assert(*error_msg != '\0') failed: Must have error_message while parsing -XX:CompileCommand=unknown
  • 3212f80: 8261937: LambdaForClassInBaseArchive: SimpleApp$$Lambda$1 missing
  • 2218e72: 8262486: Merge trivial JDWP agent changes from the loom repo to the jdk repo
  • 86fac95: 8263142: Delete unused entry points in libawt/libawt_xawt/libawt_headless
  • b7f0b3f: 8252173: Use handles instead of jobjects in modules.cpp
  • a6e34b3: 8262829: Native crash in Win32PrintServiceLookup.getAllPrinterNames()
  • fbe40e8: 8252399: Update mapMulti documentation to use type test pattern instead of instanceof once JEP 375 exits preview
  • 0f2402d: 8263190: Update java.io, java.math, and java.text to use instanceof pattern variable
  • ... and 34 more: https://git.openjdk.java.net/jdk/compare/e1cad97049642ab201d53ff608937f7e7ef3ff3e...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Mar 9, 2021
@mlbridge
Copy link

mlbridge bot commented Mar 9, 2021

Mailing list message from Joe Darcy on core-libs-dev:

On 3/9/2021 12:03 PM, Stuart Marks wrote:

On Tue, 9 Mar 2021 19:13:24 GMT, Joe Darcy <darcy at openjdk.org> wrote:

src/java.base/share/classes/java/lang/reflect/Method.java line 589:

587: * different return type, the virtual machine does not.
588: * A
589: * common case where covariant overrides are used is for a {@link
I think the example should be clearer because here, you don't show the code of EnumSet.clone().
I wonder if it's not easier if all the code is visible
interface I {
Object m();
}
class A implements I {
String m() { return "hello"; }
}
so you can explain that the VM do the dispatch on I::m()Object so the compiler has to insert a method A::m()Object,
the bridge method with this pseudo-code
class A implements I {
/* bridge */ Object m() { return m(); } // calls m()String
String m() { return "hello"; }
}
Hi Remi,

Thanks for the feedback. I did consider that kind of approach of an example from scratch. I judged referencing instances of bridge methods in the base module to be helpful to demonstrate it wasn't too esoteric of a feature in terms of it is something you, as a developer, may already have seen. Also, given the likely audience of the reading Class.isBridge, I didn't think a stand-alone example was warranted.
The prose description here and is still rather clumsy, though. If you're going to use EnumSet.clone() as an example, maybe run with that and list the methods directly instead of saying "EnumSet.clone() returns EnumSet rather than Object", be more explicit. Maybe something like the following:

The Object class has the method:
clone()```
whereas the EnumSet class has this method:
<E> clone()```
From the JVM's perspective, the second method doesn't override the first, because they have different return types. The Java compiler provides a proper override by inserting the following bridge method into the EnumSet class:
clone()```
that simply calls the second method and returns its result.

Pushed a refinement along those lines; new text:

A bridge method is a synthetic method created by a Java compiler
alongside a method originating from the source code. Bridge methods are
used by Java compilers in various circumstances to span differences in
Java programming language semantics and JVM semantics. One example use
of bridge methods is as technique for a Java compiler to support
covariant overrides, where a subclass overrides a method and gives the
new method a more specific return type than the method in the
superclass. While the Java language specification forbids a class
declaring two methods with the same parameter types but a different
return type, the virtual machine does not. A common case where covariant
overrides are used is for a Cloneable class where the clone method
inherited from java.lang.Object is overridden and declared to return the
type of the class. For example, Object declares
protected Object clone() throws CloneNotSupportedException {...}
and EnumSet<E> declares its language-level covariant override
public EnumSet<E> clone() {...}
If this technique was being used, the resulting class file for EnumSet
would have two clone methods, one returning EnumSet<E> and the second a
bridge method returning Object. The bridge method is a JVM-level
override of Object.clone(). The body of the clone bridge method calls
its non-bridge counterpart and returns its result.

-Joe

* circumstances to span differences in Java programming
* language semantics and JVM semantics.
*
* One example use of bridge methods is as technique for a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"a technique"

Copy link
Member

@stuart-marks stuart-marks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK just a couple markup comments, otherwise good.

* code.
* Bridge methods are used by Java compilers in various
* circumstances to span across differences in Java programming
* language semantics and JVM semantics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, also maybe need a

tag here.

* {@code protected Object clone() throws CloneNotSupportedException {...}}<br>
* and {@code EnumSet<E>} declares its language-level {@linkplain java.util.EnumSet#clone() covariant override}<br>
* {@code public EnumSet<E> clone() {...}}<br>
* If this technique was being used, the resulting class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the preferred code block markup style is here; maybe <pre>{@code ...}</pre> instead of <br>.

@jddarcy
Copy link
Member Author

jddarcy commented Mar 10, 2021

/integrate

@openjdk openjdk bot closed this Mar 10, 2021
@openjdk openjdk bot added integrated Pull request has been integrated and removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Mar 10, 2021
@openjdk
Copy link

openjdk bot commented Mar 10, 2021

@jddarcy Since your change was applied there have been 44 commits pushed to the master branch:

  • d0c1aec: 8263140: Japanese chars garble in console window in HSDB
  • 70342e8: 8262520: Add SA Command Line Debugger support to connect to debug server
  • e5ce97b: 8263206: assert(*error_msg != '\0') failed: Must have error_message while parsing -XX:CompileCommand=unknown
  • 3212f80: 8261937: LambdaForClassInBaseArchive: SimpleApp$$Lambda$1 missing
  • 2218e72: 8262486: Merge trivial JDWP agent changes from the loom repo to the jdk repo
  • 86fac95: 8263142: Delete unused entry points in libawt/libawt_xawt/libawt_headless
  • b7f0b3f: 8252173: Use handles instead of jobjects in modules.cpp
  • a6e34b3: 8262829: Native crash in Win32PrintServiceLookup.getAllPrinterNames()
  • fbe40e8: 8252399: Update mapMulti documentation to use type test pattern instead of instanceof once JEP 375 exits preview
  • 0f2402d: 8263190: Update java.io, java.math, and java.text to use instanceof pattern variable
  • ... and 34 more: https://git.openjdk.java.net/jdk/compare/e1cad97049642ab201d53ff608937f7e7ef3ff3e...master

Your commit was automatically rebased without conflicts.

Pushed as commit 67ea3bd.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@jddarcy jddarcy deleted the 8263102 branch June 10, 2021 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

5 participants