|
1 | 1 | /* |
2 | | - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
24 | 24 | */ |
25 | 25 | package com.oracle.graal.pointsto.flow; |
26 | 26 |
|
| 27 | +import java.util.List; |
| 28 | + |
27 | 29 | import com.oracle.graal.pointsto.BigBang; |
28 | 30 | import com.oracle.graal.pointsto.api.HostVM; |
29 | 31 | import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; |
| 32 | +import com.oracle.graal.pointsto.meta.AnalysisField; |
30 | 33 | import com.oracle.graal.pointsto.meta.AnalysisMethod; |
31 | 34 | import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; |
32 | 35 | import com.oracle.graal.pointsto.util.AnalysisError; |
@@ -128,20 +131,57 @@ public static boolean isRequiredStage(Stage stage, AnalysisMethod method) { |
128 | 131 | HOST_ARCHITECTURE = compiler.getGraalRuntime().getCapability(RuntimeProvider.class).getHostBackend().getTarget().arch; |
129 | 132 | } |
130 | 133 |
|
131 | | - private static final AnalysisParsedGraph EMPTY = new AnalysisParsedGraph(null, false); |
| 134 | + /** |
| 135 | + * Immutable metadata captured for one parsed graph, retained with its encoding so subsequent |
| 136 | + * parsing of the same method cannot replace it. Closed-field writes describe stores observed |
| 137 | + * at the collection boundary, including stores eliminated before encoding. They conservatively |
| 138 | + * retain validation obligations rather than describing only the encoded graph's remaining effects. |
| 139 | + * |
| 140 | + * @param closedFieldWrites always-closed fields written before optimizations can remove their |
| 141 | + * stores; this is validation metadata for later layers and does not mark fields as |
| 142 | + * written in the analysis |
| 143 | + */ |
| 144 | + public record GraphMetadata(List<AnalysisField> closedFieldWrites) { |
| 145 | + private static final GraphMetadata EMPTY = new GraphMetadata(List.of()); |
| 146 | + |
| 147 | + public GraphMetadata { |
| 148 | + closedFieldWrites = List.copyOf(closedFieldWrites); |
| 149 | + } |
| 150 | + |
| 151 | + /** Collects metadata during one parsing operation, before publishing the encoded graph. */ |
| 152 | + public static final class Builder { |
| 153 | + private List<AnalysisField> closedFieldWrites = List.of(); |
| 154 | + |
| 155 | + public void setClosedFieldWrites(List<AnalysisField> closedFieldWrites) { |
| 156 | + this.closedFieldWrites = List.copyOf(closedFieldWrites); |
| 157 | + } |
| 158 | + |
| 159 | + public GraphMetadata build() { |
| 160 | + return closedFieldWrites.isEmpty() ? EMPTY : new GraphMetadata(closedFieldWrites); |
| 161 | + } |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + private static final AnalysisParsedGraph EMPTY = new AnalysisParsedGraph(null, false, GraphMetadata.EMPTY); |
132 | 166 |
|
133 | 167 | private final EncodedGraph encodedGraph; |
134 | 168 | private final boolean isIntrinsic; |
| 169 | + private final GraphMetadata metadata; |
135 | 170 |
|
136 | | - public AnalysisParsedGraph(EncodedGraph encodedGraph, boolean isIntrinsic) { |
| 171 | + public AnalysisParsedGraph(EncodedGraph encodedGraph, boolean isIntrinsic, GraphMetadata metadata) { |
137 | 172 | this.isIntrinsic = isIntrinsic; |
138 | 173 | this.encodedGraph = encodedGraph; |
| 174 | + this.metadata = metadata; |
139 | 175 | } |
140 | 176 |
|
141 | 177 | public EncodedGraph getEncodedGraph() { |
142 | 178 | return encodedGraph; |
143 | 179 | } |
144 | 180 |
|
| 181 | + public GraphMetadata getMetadata() { |
| 182 | + return metadata; |
| 183 | + } |
| 184 | + |
145 | 185 | public boolean isIntrinsic() { |
146 | 186 | return isIntrinsic; |
147 | 187 | } |
@@ -251,6 +291,7 @@ public static AnalysisParsedGraph createFinalStage(BigBang bb, AnalysisMethod me |
251 | 291 | return optimizeAndEncode(bb, method, decodeParsedGraph(bb, method, stage1Graph), stage1Graph.isIntrinsic, Stage.OPTIMIZATIONS_APPLIED); |
252 | 292 | } |
253 | 293 |
|
| 294 | + /** Decode a non-empty parsed graph without inlining or applying optimizations. */ |
254 | 295 | @SuppressWarnings("try") |
255 | 296 | private static StructuredGraph decodeParsedGraph(BigBang bb, AnalysisMethod method, AnalysisParsedGraph analysisParsedGraph) { |
256 | 297 | // Persisted analysis graphs do not consume the structured optimization log, so avoid |
@@ -281,13 +322,14 @@ private static AnalysisParsedGraph optimizeAndEncode(BigBang bb, AnalysisMethod |
281 | 322 | * Must be called before any other thread can access the graph, i.e., before the graph |
282 | 323 | * is published. |
283 | 324 | */ |
| 325 | + GraphMetadata.Builder metadata = new GraphMetadata.Builder(); |
284 | 326 | switch (stage) { |
285 | 327 | case BYTECODE_PARSED -> bb.getHostVM().methodAfterBytecodeParsedHook(bb, method, graph); |
286 | | - case OPTIMIZATIONS_APPLIED -> bb.getHostVM().methodAfterParsingHook(bb, method, graph); |
| 328 | + case OPTIMIZATIONS_APPLIED -> bb.getHostVM().methodAfterParsingHook(bb, method, graph, metadata); |
287 | 329 | } |
288 | 330 |
|
289 | 331 | EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HOST_ARCHITECTURE); |
290 | | - return new AnalysisParsedGraph(encodedGraph, isIntrinsic); |
| 332 | + return new AnalysisParsedGraph(encodedGraph, isIntrinsic, metadata.build()); |
291 | 333 | } catch (Throwable e) { |
292 | 334 | throw graph.getDebug().handle(e); |
293 | 335 | } |
|
0 commit comments