Skip to content
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

[WIP][GR-45250] Implement a bytecode-level analysis for constant reflection calls #10878

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

graalvmbot
Copy link
Collaborator

Currently, the constant reflection analysis used by Native Image is optimization dependent. This can lead to unexpected results during image run-time when using reflection. For example, the Class.forName call in the following snippet will be folded by the analysis:

static boolean isEven(int n) {
    return n % 2 == 0;
}

Class<?> grabClass() throws ClassNotFoundException {
    var className = isEven(4) ? "A" : "B";
    return Class.forName(className); // returns Class A
}

However, adding a simple printing statement to isEven or toggling different optimizations during build-time can cause the method to be non-inlinable and Class.forName call won't be folded:

static boolean isEven(int n) {
    System.out.print("isEven was called");
    return n % 2 == 0;
}

Class<?> grabClass() throws ClassNotFoundException {
    var className = isEven(4) ? "A" : "B";
    return Class.forName(className); // throws ClassNotFoundException / MissingReflectionRegistrationError
}

In order to prevent this behavior, we can run a constant reflection analysis directly on the bytecode used as input to Native Image.

This PR implements a JVMTI agent (com.oracle.svm.reflectionagent.NativeImageReflectionAgent) which intercepts user provided class files, analyzes them for constant reflection usage and marks such reflective methods as constant by redirecting them to their counterparts in the org.graalvm.nativeimage.impl.reflectiontags.ConstantTags) class. If a reflective method invocation in a user provided class gets folded by com.oracle.svm.hosted.snippets.ReflectionPlugins without it being marked as constant by the agent, the user gets a warning during build-time:

Warning: Call to java.lang.Class.forName(String) reached in Demo.main(Demo.java:14) with arguments (A) was reduced to the constant class A outside of the strict constant reflection mode. Consider adding the appropriate entry to your reachability metadata (https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection).

To enable the agent and warnings, use the -H:+EnableStrictReflection. In addition, three new options are provided for more accurate logging of constant reflection folding done by ReflectionPlugins:

  • -H:ReflectionPluginTraceLocation=<log_location> - Location for the log file. If not set, the log isn't created.
  • -H:ReflectionPluginTraceFormat=json|plain - Specify the format of the location log. Default value is json. If ReflectionPluginTraceLocation isn't set, this option has no effect.
  • -H:+ReflectionPluginTraceUserOnly - Log only the constant folding which occurred in user classes. Default value is true. If ReflectionPluginTraceLocation isn't set, this option has no effect.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Mar 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCA Verified All contributors have signed the Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants