-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[GR-45250] [GR-45734] Strict Dynamic Access Inference #11079
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
Open
graalvmbot
wants to merge
15
commits into
master
Choose a base branch
from
alekstef/GR-45250-GR-45734-bytecode-level-reflection-analysis
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[GR-45250] [GR-45734] Strict Dynamic Access Inference #11079
graalvmbot
wants to merge
15
commits into
master
from
alekstef/GR-45250-GR-45734-bytecode-level-reflection-analysis
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51bf4e1
to
50a8e02
Compare
db34a29
to
5a4d449
Compare
4d9ed1b
to
385e93e
Compare
e236ee3
to
d3b758d
Compare
a2a6d67
to
d19698f
Compare
…the start of parsing.
…requiring reachability registrations.
…they are no longer needed.
…e to a singleton and style fixes.
…text#getInliningChain.
6499016
to
e6f31c8
Compare
831bce9
to
9a5faec
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem description
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:However, adding a simple printing statement to either of the wrappers or toggling different optimizations (for example,
-H:InlineBeforeAnalysisAllowedDepth=1
) during build-time can cause the method to be non-inlinable and theClass.forName
call won't be folded:This is only a simple example of this kind of behavior. The inlining context can potentially be multiple levels deep, making it virtually impossible to reason about when it's safe to use reflective methods without specifying additional metadata. This also opens up the possibility of code breaking upon toggling different optimizations or seemingly unrelated changes in user code.
In short, the main issues with the current approach are:
Additions from this PR
This PR introduces a bytecode-level inference scheme for invocations which would otherwise require a reachability metadata entry. Some of the properties of this scheme are:
Two new hosted options are introduced:
-H:StrictDynamicAccessInference=Disable|Warn|Enforce
-H:+ReportDynamicAccessInference
Strict dynamic access inference scheme specification / description
A method is composed of a sequence of instructions. The analysis records the abstract frame state before the abstract interpretation of each instruction in that sequence. The abstract frame state is composed of a representation of the operand stack and local variable table, both containing abstract representation of values.
An abstract value can be either of the following:
A data flow analysis is then employed on the method until a fixed point is reached (no changes in the abstract frames are observed). The abstract frames are computed in the following way:
ACONST_NULL
,ICONST_1
,LDC
, ...);GETSTATIC
instructions referencing the appropriate boxed type's TYPE field push the corresponding Class object as a compile time constant;INVOKESTATIC
instruction with BCI 42 referencing thejava.lang.Boolean.TYPE
field pushes a (42, boolean.class) compile-time constant on the operand stack;ASTORE
, ...) or a variable load (ALOAD
, ...) instruction, and the value they are targeting is a non-array compile-time constant, then that value can be propagated (the source BCI must change);ASTORE
with BCI 8 and an operand which is a compile time constant (6, "SomeClassName") would put a compile-time constant (8, "SomeClassName") into the local variable table;INVOKESTATIC
instruction callingjava.lang.Class.forName(String className)
has a compile time constant operand and the call can be executed without throwing an exception, a compile time constant holding the result can be pushed on the operand stack.NEWARRAY
,ANEWARRAY
,MULTIANEWARRAY
) push a compile time constant on the operand stack if and only if all the count operands are compile time constants;AASTORE
) and which have a compile time constant array reference operand (array source BCI, array value) have to modify all of the compile time constants corresponding to that array reference which are currently in the abstract frame (for which the source BCI is equal to the array source BCI), and not only the operand itself. The updating is done in the following way:Strict dynamic access inference in terms of Java source code
The inference scheme is formally defined in terms of bytecode, but can roughly be translated to the following, relatively simple rules in terms of Java code - we define compile-time constants; if all arguments to the dynamic access invocation are compile-time constants, we can infer it:
null
literals and casts on them are compile-time constants;Future work - annotations
The proposed analysis works within the bounds of a single method and only for simple patterns. In other cases, the user has to specify reachability metadata in external files. Those can be cumbersome for maintaining and writing, especially if done by hand (and not generated with the tracing agent). One alternative to this approach is specifying reachability metadata through annotations. One candidate for the structure of such hypothetical annotations would mimic the structure of reachability .json files:
Usage example:
A more realistic scenario where the proposed analysis fails would be in cases where the arguments of the reflective call depend on the arguments of the containing method. As an example, the following method is used in the Spring framework (defined in
org.springframework.util.ClassUtils
):The method calls Class.getMethod, but the arguments are passed from an outside context. A specific example of its call site in one place is:
The arguments of
ClassUtils.getMethod
are constant and could be detected, but it is a user defined method which isn't subject to our analysis. To get around that, we would either need to extend the analysis to be interprocedural, which would be too inefficient and complicated to reason about, or extend the previously proposed annotations to interoperate with our analysis. As an example, the annotation could then look something like this:The "#n" tags would imply binding the annotation parameter to the value of that method's argument, effectively turning a method annotated with "@ReflectiveAccess" into an ordinary reflective method which from the point of view of our analysis. Upon detecting that a method invocation with the "@ReflectiveAccess" annotation has constant arguments, the appropriate types, fields and methods would be registered for reflection. With this strategy, one annotation could potentially replace a large number of reflection metadata entries.
Some benefits of annotations for reachability metadata in comparison to .json files are: