Skip to content

8303431: [JVMCI] libgraal annotation API#12810

Closed
dougxc wants to merge 14 commits intoopenjdk:masterfrom
dougxc:JDK-8303431
Closed

8303431: [JVMCI] libgraal annotation API#12810
dougxc wants to merge 14 commits intoopenjdk:masterfrom
dougxc:JDK-8303431

Conversation

@dougxc
Copy link
Member

@dougxc dougxc commented Mar 1, 2023

This PR extends JVMCI with new API (jdk.vm.ci.meta.Annotated) for accessing annotations. The main differences from java.lang.reflect.AnnotatedElement are:

  • All methods in the Annotated interface explicitly specify requested annotation type(s). That is, there is no equivalent of AnnotatedElement.getAnnotations().
  • Annotation data is returned in a map-like object (of type jdk.vm.ci.meta.AnnotationData) instead of in an Annotation object. This works better for libgraal as it avoids the need for annotation types to be loaded and included in libgraal.

To demonstrate the new API, here's an example in terms java.lang.reflect.AnnotatedElement (which ResolvedJavaType implements):

    ResolvedJavaMethod method = ...;
    ExplodeLoop a = method.getAnnotation(ExplodeLoop.class);
    return switch (a.kind()) {
        case FULL_UNROLL -> LoopExplosionKind.FULL_UNROLL;
        case FULL_UNROLL_UNTIL_RETURN -> LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN;
        ...
    }

The same code using the new API:

    ResolvedJavaMethod method = ...;
    ResolvedJavaType explodeLoopType = ...;
    AnnotationData a = method.getAnnotationDataFor(explodeLoopType);
    return switch (a.getEnum("kind").getName()) {
        case "FULL_UNROLL" -> LoopExplosionKind.FULL_UNROLL;
        case "FULL_UNROLL_UNTIL_RETURN" -> LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN;
        ...
    }

The implementation relies on new methods in jdk.internal.vm.VMSupport for parsing annotations and serializing/deserializing to/from a byte array. This allows the annotation data to be passed from the HotSpot heap to the libgraal heap.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/12810/head:pull/12810
$ git checkout pull/12810

Update a local copy of the PR:
$ git checkout pull/12810
$ git pull https://git.openjdk.org/jdk.git pull/12810/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 12810

View PR using the GUI difftool:
$ git pr show -t 12810

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/12810.diff

Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Mar 1, 2023

👋 Welcome back dnsimon! 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 1, 2023

@dougxc The following labels will be automatically applied to this pull request:

  • core-libs
  • hotspot

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.

@openjdk openjdk bot added hotspot hotspot-dev@openjdk.org core-libs core-libs-dev@openjdk.org labels Mar 1, 2023
@dougxc dougxc marked this pull request as ready for review March 1, 2023 18:33
@openjdk openjdk bot added the rfr Pull request is ready for review label Mar 1, 2023
@mlbridge
Copy link

mlbridge bot commented Mar 1, 2023

Webrevs

@openjdk openjdk bot removed the rfr Pull request is ready for review label Mar 5, 2023
@openjdk openjdk bot added the rfr Pull request is ready for review label Mar 5, 2023
@dougxc dougxc closed this Mar 7, 2023
@dougxc
Copy link
Member Author

dougxc commented Mar 7, 2023

This PR still needs work. I'll re-open it when ready.

@dougxc dougxc reopened this Mar 8, 2023
@openjdk
Copy link

openjdk bot commented Mar 8, 2023

@dougxc this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout JDK-8303431
git fetch https://git.openjdk.org/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added the merge-conflict Pull request has merge conflict with target branch label Mar 8, 2023
@openjdk openjdk bot removed the merge-conflict Pull request has merge conflict with target branch label Mar 8, 2023
}
@SuppressWarnings("unchecked")
@Test
public void encodeDecodeTest2() throws Exception {
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
for (int i = 0; i < 10; i++) {
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
}
encodeDecode(throwable);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Why this was removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it does exactly the same thing as encodeDecodeTest. It should have been cleaned up in the original PR that introduced this test.

Copy link
Contributor

@vnkozlov vnkozlov left a comment

Choose a reason for hiding this comment

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

I looked on Hotspot, JVMCI and VMSupport.java changes. But you need to ask Tom to look on JVMCI changes in details. And someone from core-libs who familiar with Annotations have to comment on your implementation in general because I am not expert.

@openjdk
Copy link

openjdk bot commented Mar 13, 2023

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

8303431: [JVMCI] libgraal annotation API

Reviewed-by: kvn, never, darcy

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

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 13, 2023
Copy link
Contributor

@tkrodriguez tkrodriguez left a comment

Choose a reason for hiding this comment

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

The JVMCI changes look ok to me.


typeArrayOop ba = typeArrayOop(res);
int ba_len = ba->length();
if (ba_len <= 256) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this really necessary? Resource allocation is very cheap.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, good point. I'll remove the optimization.

* initialized. Class initialization is not triggered for enum types referenced by other
* annotations of this element.
*
* If this element is a class, then {@link Inherited} annotations are included in set of
Copy link
Contributor

Choose a reason for hiding this comment

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

in the set

@dougxc
Copy link
Member Author

dougxc commented Mar 15, 2023

@jddarcy would you be able to help review this PR? Based on git log, you are knowledgeable in sun.reflect.annotation. If not, please suggest who else I can reach out to for a review.

@openjdk openjdk bot added merge-conflict Pull request has merge conflict with target branch and removed ready Pull request is ready to be integrated labels Apr 3, 2023
/**
* Encodes a list of annotations to a byte array. The byte array can be decoded with {@link #decodeAnnotations(byte[], AnnotationDecoder)}.
*/
public static byte[] encodeAnnotations(Collection<Annotation> annotations) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think it matters much in this use case, but it looks like encodeAnnotations could be changed to take a List rather than a Collection, as the comment implies.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just above (line 228) you can see a call to this method where the argument comes from Map.values() whose type is Collection so I'd prefer to leave it as is rather than have to convert the argument to a List.

Copy link
Member

Choose a reason for hiding this comment

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

In that case, I think the comment on line 232 should be updated to not say "list".

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the comment to "Encodes annotations to a byte array."

* @param <E> type of the object representing a decoded enum constant
* @param <X> type of the object representing a decoded error
*/
public interface AnnotationDecoder<T, A, E, X> {
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be better to include some bound on the type parameters to better capture their intention
A extends java.lang.Annotatoin
E extends java.lang.Enum
etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

These types are alternatives to java.lang.Annotation, java.lang.Enum etc. That's the primary motivation for this PR, i.e. to be able to represent annotations without having to reify them as java.lang.Annotation objects.

@jddarcy
Copy link
Member

jddarcy commented Apr 17, 2023

A few higher-level comments:

From the long-term perspective, it is likely that the set of kinds of elements that can occur in an annotation will be expanded, for example, method references are a repeated request. Easing future maintenance to gives more inter-source linkage in this situation and error handling for this case in the libgraal code would be prudent IMO.

The java.lang.reflect.AnnotatedElement API (https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/reflect/AnnotatedElement.html) defines different ways an annotation can be affiliated with an element:

"The terms directly present, indirectly present, present, and associated are used throughout this interface to describe precisely which annotations are returned by methods: "

tl;dr these terms relate to which of inheriting annotations and looking through repeated annotations the methods do on behalf of the caller. I think the methods should phrase their operations in terms of these concepts, such as "Construct the annotations present..." since inheritance is taken into account.

@dougxc
Copy link
Member Author

dougxc commented Apr 17, 2023

From the long-term perspective, it is likely that the set of kinds of elements that can occur in an annotation will be expanded, for example, method references are a repeated request. Easing future maintenance to gives more inter-source linkage in this situation and error handling for this case in the libgraal code would be prudent IMO.

I'm not sure what you're suggesting in terms of how I should update this PR. Do you mean AnnotationData.get needs to somehow be more flexible? If so, could you please give a concrete example of what you're after.

@dougxc
Copy link
Member Author

dougxc commented Apr 17, 2023

the methods should phrase their operations in terms of these concepts...

I think this is what you're suggesting: 362738a

@openjdk openjdk bot added ready Pull request is ready to be integrated and removed merge-conflict Pull request has merge conflict with target branch labels Apr 17, 2023
@jddarcy
Copy link
Member

jddarcy commented Apr 18, 2023

From the long-term perspective, it is likely that the set of kinds of elements that can occur in an annotation will be expanded, for example, method references are a repeated request. Easing future maintenance to gives more inter-source linkage in this situation and error handling for this case in the libgraal code would be prudent IMO.

I'm not sure what you're suggesting in terms of how I should update this PR. Do you mean AnnotationData.get needs to somehow be more flexible? If so, could you please give a concrete example of what you're after.

Let me explain my concerns in more detail.

We have (at least) two separate annotations implementations in the JDK, one in javac for compile-time and other in core reflection for runtime. Due to various technical constraints, the implementations are necessarily separate (although the annotation objects constructed by javac do also implement the java.lang.annotation.Annotation interface also used by core reflection).

This work is proposing to add another partial implementation to satisfy other technical goals, reusing portions of the existing core reflection machinery.

If at some point the universe of objects that can be encoded as annotation is expanded, e..g method literals as mentioned previously, it is well-understood that core reflection and javac will need to be updated. I think it would be relatively easy to overlook the need to make corresponding updates to libgraal API and all regression tests might still pass.

As a concrete suggestion, if such an unknown annotation was handed over to libgraal, I think the code should reject it (AssertionError("unexpected annotation component") etc.) in hope of the omission getting corrected sooner. Also, leaving some bread crumb comments to future maintainers of core reflection annotations in that implementation package would be helpful too, e.g. "// used by libgraal".

HTH

@dougxc
Copy link
Member Author

dougxc commented Apr 18, 2023

I think the code should reject it

The AnnotationData constructor already has a check for unknown annotation element types so I think this concern is covered.

leaving some bread crumb comments to future maintainers of core reflection annotations

Done here: bad23a0

@dougxc
Copy link
Member Author

dougxc commented Apr 19, 2023

Thanks for the reviews @turbanoff , @vnkozlov and @jddarcy.

/integrate

@openjdk
Copy link

openjdk bot commented Apr 19, 2023

Going to push as commit 48fd4f2.
Since your change was applied there have been 35 commits pushed to the master branch:

  • c57af31: 8306038: SystemModulesPlugin generates code that doesn't pop when return value not used
  • a31a11f: 8306006: strace001.java fails due to unknown methods on stack
  • ddb8646: 8306123: Move InstanceKlass writeable flags
  • 1a41e12: 8306310: Move is_shared Klass flag
  • c738c8e: 8306278: jvmtiAgentList.cpp:253 assert(offset >= 0) failed: invariant occurs on AIX after JDK-8257967
  • 9fb53ad: 8305716: Enhancements for printing age tables
  • ebba42a: 8305993: Add handleSocketErrorWithMessage to extend nio Net.c exception message
  • 42b7260: 8306111: PPC64: RT call after thaw with exception requires larger ABI section
  • c7faf60: 8305757: Call Method::compute_has_loops_flag() when creating CDS archive
  • eb8d8cd: 8299129: Enhance NameService lookups
  • ... and 25 more: https://git.openjdk.org/jdk/compare/525a91e3fac892c26b09cc1705d0909afe80c8f9...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Apr 19, 2023
@openjdk openjdk bot closed this Apr 19, 2023
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Apr 19, 2023
@openjdk
Copy link

openjdk bot commented Apr 19, 2023

@dougxc Pushed as commit 48fd4f2.

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

@vnkozlov
Copy link
Contributor

vnkozlov commented Apr 20, 2023

@dougxc I see next 2 JVMCI tests failed when run with -XX:TypeProfileLevel=222 on all platforms (our stress testing):

compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java
compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java

#  Internal Error (/workspace/open/src/hotspot/cpu/x86/macroAssembler_x86.cpp:829), pid=2430194, tid=2430218
#  fatal error: DEBUG MESSAGE: exact klass and actual klass differ

Current thread (0x00007f9ff8460480):  JavaThread "MainThread" [_thread_in_Java, id=2430218, stack(0x00007f9fe06b7000,0x00007f9fe07b8000)]

Stack: [0x00007f9fe06b7000,0x00007f9fe07b8000],  sp=0x00007f9fe07b44e0,  free space=1013k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x12b8d35]  MacroAssembler::debug64(char*, long, long*)+0x45  (macroAssembler_x86.cpp:829)
J 1935 c1 sun.reflect.annotation.AnnotationParser.parseAnnotation2(Ljava/nio/ByteBuffer;Ljdk/internal/reflect/ConstantPool;Ljava/lang/Class;Z[Ljava/lang/Class;)Ljava/lang/annotation/Annotation; java.base@21-internal (275 bytes) @ 0x00007f9fe10d4cc6 [0x00007f9fe10d4740+0x0000000000000586]

[error occurred during error reporting (printing native stack (with source info))

@dougxc
Copy link
Member Author

dougxc commented Apr 20, 2023

I can reproduce this locally as well but really don't know where to start in terms of debugging this. Can you please provide hints as to what may cause this failure C1 compiled code?

@vnkozlov
Copy link
Contributor

Filed JDK-8306581

@dougxc dougxc deleted the JDK-8303431 branch August 20, 2024 06:20
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 hotspot hotspot-dev@openjdk.org integrated Pull request has been integrated

Development

Successfully merging this pull request may close these issues.

5 participants