2424 */
2525package com .oracle .svm .core ;
2626
27+ import static org .graalvm .compiler .nodeinfo .NodeCycles .CYCLES_0 ;
28+ import static org .graalvm .compiler .nodeinfo .NodeSize .SIZE_1 ;
29+
2730import java .util .Objects ;
2831
32+ import org .graalvm .compiler .api .replacements .SnippetReflectionProvider ;
33+ import org .graalvm .compiler .core .common .type .StampFactory ;
34+ import org .graalvm .compiler .graph .NodeClass ;
35+ import org .graalvm .compiler .nodeinfo .NodeInfo ;
36+ import org .graalvm .compiler .nodes .ConstantNode ;
37+ import org .graalvm .compiler .nodes .calc .FloatingNode ;
38+ import org .graalvm .compiler .nodes .graphbuilderconf .GraphBuilderConfiguration .Plugins ;
39+ import org .graalvm .compiler .nodes .graphbuilderconf .GraphBuilderContext ;
40+ import org .graalvm .compiler .nodes .graphbuilderconf .InvocationPlugin ;
41+ import org .graalvm .compiler .nodes .graphbuilderconf .InvocationPlugins .Registration ;
42+ import org .graalvm .compiler .nodes .spi .Lowerable ;
43+ import org .graalvm .compiler .nodes .spi .LoweringTool ;
44+ import org .graalvm .compiler .phases .util .Providers ;
2945import org .graalvm .nativeimage .ImageSingletons ;
3046import org .graalvm .nativeimage .Platform ;
3147import org .graalvm .nativeimage .Platforms ;
32- import org .graalvm .nativeimage . hosted . Feature ;
48+ import org .graalvm .word . LocationIdentity ;
3349
3450import com .oracle .svm .core .annotate .AutomaticFeature ;
35- import com .oracle .svm .core .annotate .Uninterruptible ;
36- import com .oracle .svm .core .annotate .UnknownObjectField ;
51+ import com .oracle .svm .core .graal .GraalFeature ;
3752import com .oracle .svm .core .meta .SharedField ;
53+ import com .oracle .svm .core .meta .SubstrateObjectConstant ;
54+
55+ import jdk .vm .ci .meta .JavaConstant ;
56+ import jdk .vm .ci .meta .JavaKind ;
57+ import jdk .vm .ci .meta .ResolvedJavaMethod ;
3858
3959/**
4060 * Static fields are represented as two arrays in the native image heap: one for Object fields and
4464 * Implementation notes: The arrays are created after static analysis, but before compilation. We
4565 * need to know how many static fields are reachable in order to compute the appropriate size for
4666 * the arrays, which is only available after static analysis.
67+ *
68+ * When bytecode is parsed before static analysis, the arrays are not available yet. Therefore, the
69+ * accessor functions {@link #getStaticObjectFields()}} and {@link #getStaticPrimitiveFields()} are
70+ * intrinsified to a {@link StaticFieldBaseNode}, which is then during compilation lowered to the
71+ * constant arrays. This also solves memory graph problems in the Graal compiler: Direct
72+ * loads/stores using the arrays, for example via Unsafe or VarHandle, alias with static field
73+ * loads/stores that have dedicated {@link LocationIdentity}. If the arrays are already exposed in
74+ * the high-level optimization phases of Graal, the compiler would miss the alias since the location
75+ * identities for arrays are considered non-aliasing with location identities for fields. Replacing
76+ * the {@link StaticFieldBaseNode} with a {@link ConstantNode} only in the low tier of the compiler
77+ * solves this problem.
4778 */
4879public final class StaticFieldsSupport {
4980
50- @ UnknownObjectField ( types = { Object []. class }) private Object [] staticObjectFields ;
51- @ UnknownObjectField ( types = { byte []. class }) private byte [] staticPrimitiveFields ;
81+ Object [] staticObjectFields ;
82+ byte [] staticPrimitiveFields ;
5283
5384 @ Platforms (Platform .HOSTED_ONLY .class )
5485 protected StaticFieldsSupport () {
@@ -61,30 +92,74 @@ public static void setData(Object[] staticObjectFields, byte[] staticPrimitiveFi
6192 support .staticPrimitiveFields = Objects .requireNonNull (staticPrimitiveFields );
6293 }
6394
64- @ Platforms (Platform .HOSTED_ONLY .class )
65- public static boolean dataAvailable () {
66- return ImageSingletons .lookup (StaticFieldsSupport .class ).staticObjectFields != null ;
67- }
68-
69- @ Uninterruptible (reason = "Called from uninterruptible code." , mayBeInlined = true )
70- public static Object [] getStaticObjectFields () {
95+ /* Intrinsified by the graph builder plugin below. */
96+ public static Object getStaticObjectFields () {
7197 Object [] result = ImageSingletons .lookup (StaticFieldsSupport .class ).staticObjectFields ;
7298 assert result != null ;
7399 return result ;
74100 }
75101
76- @ Uninterruptible ( reason = "Called from uninterruptible code." , mayBeInlined = true )
77- public static byte [] getStaticPrimitiveFields () {
102+ /* Intrinsified by the graph builder plugin below. */
103+ public static Object getStaticPrimitiveFields () {
78104 byte [] result = ImageSingletons .lookup (StaticFieldsSupport .class ).staticPrimitiveFields ;
79105 assert result != null ;
80106 return result ;
81107 }
108+
109+ public static FloatingNode createStaticFieldBaseNode (boolean primitive ) {
110+ return new StaticFieldBaseNode (primitive );
111+ }
82112}
83113
84114@ AutomaticFeature
85- class StaticFieldsFeature implements Feature {
115+ final class StaticFieldsFeature implements GraalFeature {
86116 @ Override
87117 public void afterRegistration (AfterRegistrationAccess access ) {
88118 ImageSingletons .add (StaticFieldsSupport .class , new StaticFieldsSupport ());
89119 }
120+
121+ @ Override
122+ public void registerInvocationPlugins (Providers providers , SnippetReflectionProvider snippetReflection , Plugins plugins , ParsingReason reason ) {
123+ Registration r = new Registration (plugins .getInvocationPlugins (), StaticFieldsSupport .class );
124+ r .register0 ("getStaticObjectFields" , new InvocationPlugin () {
125+ @ Override
126+ public boolean apply (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Receiver unused ) {
127+ b .addPush (JavaKind .Object , new StaticFieldBaseNode (false ));
128+ return true ;
129+ }
130+ });
131+ r .register0 ("getStaticPrimitiveFields" , new InvocationPlugin () {
132+ @ Override
133+ public boolean apply (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Receiver unused ) {
134+ b .addPush (JavaKind .Object , new StaticFieldBaseNode (true ));
135+ return true ;
136+ }
137+ });
138+ }
139+ }
140+
141+ @ NodeInfo (cycles = CYCLES_0 , size = SIZE_1 )
142+ final class StaticFieldBaseNode extends FloatingNode implements Lowerable {
143+ public static final NodeClass <StaticFieldBaseNode > TYPE = NodeClass .create (StaticFieldBaseNode .class );
144+
145+ private final boolean primitive ;
146+
147+ /**
148+ * We must not expose that the stamp will eventually be an array, to avoid memory graph
149+ * problems. See the comment on {@link StaticFieldsSupport}.
150+ */
151+ protected StaticFieldBaseNode (boolean primitive ) {
152+ super (TYPE , StampFactory .objectNonNull ());
153+ this .primitive = primitive ;
154+ }
155+
156+ @ Override
157+ public void lower (LoweringTool tool ) {
158+ if (tool .getLoweringStage () == LoweringTool .StandardLoweringStage .LOW_TIER ) {
159+ StaticFieldsSupport support = ImageSingletons .lookup (StaticFieldsSupport .class );
160+ JavaConstant constant = SubstrateObjectConstant .forObject (primitive ? support .staticPrimitiveFields : support .staticObjectFields );
161+ assert constant .isNonNull ();
162+ replaceAndDelete (ConstantNode .forConstant (constant , tool .getMetaAccess (), graph ()));
163+ }
164+ }
90165}
0 commit comments