Skip to content

Commit d82a349

Browse files
committed
[GR-54137] Persist and reload analysis graph in extension layers
PullRequest: graal/17869
2 parents 56bf7be + 9cf446f commit d82a349

File tree

44 files changed

+2024
-332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2024
-332
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/util/test/ObjectCopierTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public void testIt() {
175175
List<Field> externalValues = List.of(ObjectCopier.getField(BaseClass.class, "BASE_SINGLETON"),
176176
ObjectCopier.getField(TestObject.class, "TEST_OBJECT_SINGLETON"));
177177

178-
String encoded = ObjectCopier.encode(root, externalValues);
178+
String encoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValues), root);
179179
if (DEBUG) {
180180
System.out.printf("encoded:%n%s%n", encoded);
181181
}
@@ -184,7 +184,7 @@ public void testIt() {
184184
System.out.printf("root:%n%s%n", root);
185185
System.out.printf("decoded:%n%s%n", decoded);
186186
}
187-
String reencoded = ObjectCopier.encode(decoded, externalValues);
187+
String reencoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValues), decoded);
188188
if (DEBUG) {
189189
System.out.printf("reencoded:%n%s%n", reencoded);
190190
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/SymbolicSnippetEncoder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,8 @@ protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, Valu
10731073

10741074
/**
10751075
* To prevent this field being considered as an <i>externalValue</i> by
1076-
* {@link ObjectCopier#encode(Object, List)}, it must <b>not</b> be {@code final}.
1076+
* {@link ObjectCopier#encode(ObjectCopier.Encoder, Object)}, it must <b>not</b> be
1077+
* {@code final}.
10771078
*/
10781079
private static Map<Class<?>, SnippetResolvedJavaType> snippetTypes = new HashMap<>();
10791080

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/guestgraal/CompilerConfig.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.ArrayList;
3636
import java.util.Collections;
3737
import java.util.List;
38+
import java.util.Locale;
3839
import java.util.stream.Stream;
3940

4041
import jdk.graal.compiler.core.common.spi.ForeignCallSignature;
@@ -89,7 +90,18 @@ public static void main(String[] args) throws Exception {
8990
encodedObjects.put("encodedSnippets", encodedSnippets);
9091
encodedObjects.put("foreignCallSignatures", foreignCallSignatures);
9192

92-
String encoded = ObjectCopier.encode(encodedObjects, externalValues);
93+
ObjectCopier.Encoder encoder = new ObjectCopier.Encoder(externalValues) {
94+
@Override
95+
protected ClassInfo makeClassInfo(Class<?> declaringClass) {
96+
ClassInfo ci = ClassInfo.of(declaringClass);
97+
for (var f : ci.fields().values()) {
98+
// Avoid problems with identity hash codes
99+
GraalError.guarantee(!f.getName().toLowerCase(Locale.ROOT).contains("hash"), "Cannot serialize hash field: %s", f);
100+
}
101+
return ci;
102+
}
103+
};
104+
String encoded = ObjectCopier.encode(encoder, encodedObjects);
93105

94106
Files.writeString(Path.of(args[0]), encoded);
95107
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -844,12 +844,12 @@ public int hashCode() {
844844
private static final TimerKey SnippetTemplateCreationTime = DebugContext.timer("SnippetTemplateCreationTime");
845845
private static final CounterKey SnippetTemplates = DebugContext.counter("SnippetTemplateCount");
846846

847-
static class Options {
847+
public static class Options {
848848
@Option(help = "Use a LRU cache for snippet templates.")//
849849
public static final OptionKey<Boolean> UseSnippetTemplateCache = new OptionKey<>(true);
850850

851851
@Option(help = "")//
852-
static final OptionKey<Integer> MaxTemplatesPerSnippet = new OptionKey<>(50);
852+
public static final OptionKey<Integer> MaxTemplatesPerSnippet = new OptionKey<>(50);
853853
}
854854

855855
/**
@@ -997,11 +997,11 @@ protected PhaseSuite<CoreProviders> createMidTierPostLoweringPhases() {
997997
}
998998
}
999999

1000-
private static final class LRUCache<K, V> extends LinkedHashMap<K, V> {
1000+
public static final class LRUCache<K, V> extends LinkedHashMap<K, V> {
10011001
private static final long serialVersionUID = 1L;
10021002
private final int maxCacheSize;
10031003

1004-
LRUCache(int initialCapacity, int maxCacheSize) {
1004+
public LRUCache(int initialCapacity, int maxCacheSize) {
10051005
super(initialCapacity, 0.75F, true);
10061006
this.maxCacheSize = maxCacheSize;
10071007
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import java.util.Iterator;
3737
import java.util.LinkedHashMap;
3838
import java.util.List;
39-
import java.util.Locale;
4039
import java.util.Map;
4140
import java.util.Set;
4241
import java.util.function.BiConsumer;
@@ -56,6 +55,7 @@
5655

5756
import jdk.graal.compiler.core.common.FieldIntrospection;
5857
import jdk.graal.compiler.debug.GraalError;
58+
import jdk.graal.compiler.replacements.SnippetTemplate;
5959
import jdk.internal.misc.Unsafe;
6060

6161
/**
@@ -92,7 +92,7 @@ public class ObjectCopier {
9292
/**
9393
* A builtin is specialized support for encoded and decoding values of specific types.
9494
*/
95-
abstract static class Builtin {
95+
public abstract static class Builtin {
9696
/**
9797
* The primary type for this builtin.
9898
*/
@@ -148,15 +148,15 @@ void makeChildIds(Encoder encoder, Object obj, ObjectPath objectPath) {
148148
* Encodes the value of {@code obj} to a String that does not contain {@code '\n'} or
149149
* {@code '\r'}.
150150
*/
151-
abstract String encode(Encoder encoder, Object obj);
151+
protected abstract String encode(Encoder encoder, Object obj);
152152

153153
/**
154154
* Decodes {@code encoded} to an object of a type handled by this builtin.
155155
*
156156
* @param encoding the non-default encoded used when encoded the object or null if the
157157
* default encoded was used
158158
*/
159-
abstract Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded);
159+
protected abstract Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded);
160160

161161
@Override
162162
public String toString() {
@@ -182,12 +182,12 @@ static final class ClassBuiltin extends Builtin {
182182
}
183183

184184
@Override
185-
String encode(Encoder encoder, Object obj) {
185+
protected String encode(Encoder encoder, Object obj) {
186186
return ((Class<?>) obj).getName();
187187
}
188188

189189
@Override
190-
Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
190+
protected Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
191191
return switch (encoded) {
192192
case "boolean" -> boolean.class;
193193
case "byte" -> byte.class;
@@ -230,7 +230,7 @@ String encodingName(Object obj) {
230230
}
231231

232232
@Override
233-
String encode(Encoder encoder, Object obj) {
233+
protected String encode(Encoder encoder, Object obj) {
234234
String s = obj instanceof String ? (String) obj : new String((char[]) obj);
235235
if ("escaped".equals(encodingName(s))) {
236236
return s.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r");
@@ -239,7 +239,7 @@ String encode(Encoder encoder, Object obj) {
239239
}
240240

241241
@Override
242-
Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
242+
protected Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
243243
String s = encoded;
244244
if (encoding != null) {
245245
GraalError.guarantee(encoding.equals("escaped"), "Unknown encoded: %s", encoding);
@@ -270,13 +270,13 @@ static final class EnumBuiltin extends Builtin {
270270
}
271271

272272
@Override
273-
String encode(Encoder encoder, Object obj) {
273+
protected String encode(Encoder encoder, Object obj) {
274274
return ((Enum<?>) obj).name();
275275
}
276276

277277
@SuppressWarnings({"unchecked", "rawtypes"})
278278
@Override
279-
Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
279+
protected Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
280280
return Enum.valueOf((Class) concreteType, encoded);
281281
}
282282
}
@@ -297,11 +297,13 @@ static final class HashMapBuiltin extends Builtin {
297297
final Map<Class<?>, Supplier<?>> factories;
298298

299299
HashMapBuiltin() {
300-
super(HashMap.class, IdentityHashMap.class, LinkedHashMap.class);
300+
super(HashMap.class, IdentityHashMap.class, LinkedHashMap.class, SnippetTemplate.LRUCache.class);
301+
int size = SnippetTemplate.Options.MaxTemplatesPerSnippet.getDefaultValue();
301302
factories = Map.of(
302303
HashMap.class, HashMap::new,
303304
IdentityHashMap.class, IdentityHashMap::new,
304-
LinkedHashMap.class, LinkedHashMap::new);
305+
LinkedHashMap.class, LinkedHashMap::new,
306+
SnippetTemplate.LRUCache.class, () -> new SnippetTemplate.LRUCache<>(size, size));
305307
}
306308

307309
@Override
@@ -311,14 +313,14 @@ void makeChildIds(Encoder encoder, Object obj, ObjectPath objectPath) {
311313
}
312314

313315
@Override
314-
String encode(Encoder encoder, Object obj) {
316+
protected String encode(Encoder encoder, Object obj) {
315317
Map<?, ?> map = (Map<?, ?>) obj;
316318
return encoder.encodeMap(new EconomicMapWrap<>(map));
317319
}
318320

319321
@SuppressWarnings("unchecked")
320322
@Override
321-
Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
323+
protected Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
322324
Map<Object, Object> map = (Map<Object, Object>) factories.get(concreteType).get();
323325
decoder.decodeMap(encoded, map::put);
324326
return map;
@@ -350,12 +352,12 @@ void makeChildIds(Encoder encoder, Object obj, ObjectPath objectPath) {
350352
}
351353

352354
@Override
353-
String encode(Encoder encoder, Object obj) {
355+
protected String encode(Encoder encoder, Object obj) {
354356
return encoder.encodeMap((UnmodifiableEconomicMap<?, ?>) obj);
355357
}
356358

357359
@Override
358-
Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
360+
protected Object decode(Decoder decoder, Class<?> concreteType, String encoding, String encoded) {
359361
if (EconomicMap.class.isAssignableFrom(concreteType)) {
360362
EconomicMap<Object, Object> map = EconomicMap.create();
361363
decoder.decodeMap(encoded, map::put);
@@ -374,8 +376,8 @@ Object decode(Decoder decoder, Class<?> concreteType, String encoding, String en
374376
* have the same name in which case the descriptor includes the qualified name of the
375377
* class declaring the field as a prefix.
376378
*/
377-
record ClassInfo(Class<?> clazz, Map<String, Field> fields) {
378-
static ClassInfo of(Class<?> declaringClass) {
379+
public record ClassInfo(Class<?> clazz, Map<String, Field> fields) {
380+
public static ClassInfo of(Class<?> declaringClass) {
379381
Map<String, Field> fields = new HashMap<>();
380382
for (Class<?> c = declaringClass; !c.equals(Object.class); c = c.getSuperclass()) {
381383
for (Field f : c.getDeclaredFields()) {
@@ -387,9 +389,6 @@ static ClassInfo of(Class<?> declaringClass) {
387389
}
388390
Field conflict = fields.put(fieldDesc, f);
389391
GraalError.guarantee(conflict == null, "Cannot support 2 fields with same name and declaring class: %s and %s", conflict, f);
390-
391-
// Try to avoid problems with identity hash codes
392-
GraalError.guarantee(!f.getName().toLowerCase(Locale.ROOT).contains("hash"), "Cannot serialize hash field: %s", f);
393392
}
394393
}
395394
}
@@ -403,7 +402,7 @@ static ClassInfo of(Class<?> declaringClass) {
403402
final Map<Class<?>, Builtin> builtinClasses = new HashMap<>();
404403
final Set<Class<?>> notBuiltins = new HashSet<>();
405404

406-
final void addBuiltin(Builtin builtin) {
405+
protected final void addBuiltin(Builtin builtin) {
407406
addBuiltin(builtin, builtin.clazz);
408407
}
409408

@@ -439,13 +438,9 @@ static String[] splitSpaceSeparatedElements(String elements) {
439438
}
440439

441440
/**
442-
* Encodes {@code root} to a String.
443-
*
444-
* @param externalValues static fields whose values should not be encoded but instead
445-
* represented as a reference to the field
441+
* Encodes {@code root} to a String using {@code encoder}.
446442
*/
447-
public static String encode(Object root, List<Field> externalValues) {
448-
Encoder encoder = new Encoder(externalValues);
443+
public static String encode(Encoder encoder, Object root) {
449444
int rootId = encoder.makeId(root, ObjectPath.of("[root]")).id();
450445
GraalError.guarantee(rootId == 1, "The root object should have id of 1, not %d", rootId);
451446
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -457,15 +452,19 @@ public static String encode(Object root, List<Field> externalValues) {
457452

458453
public static Object decode(String encoded, ClassLoader loader) {
459454
Decoder decoder = new Decoder(loader);
455+
return decode(decoder, encoded);
456+
}
457+
458+
public static Object decode(Decoder decoder, String encoded) {
460459
return decoder.decode(encoded);
461460
}
462461

463-
static class Decoder extends ObjectCopier {
462+
public static class Decoder extends ObjectCopier {
464463

465464
private final Map<Integer, Object> idToObject = new HashMap<>();
466465
private final ClassLoader loader;
467466

468-
Decoder(ClassLoader loader) {
467+
public Decoder(ClassLoader loader) {
469468
this.loader = loader;
470469
}
471470

@@ -779,7 +778,7 @@ final Builtin getBuiltin(Class<?> clazz, boolean onlyCheck) {
779778
return b;
780779
}
781780

782-
static class Encoder extends ObjectCopier {
781+
public static class Encoder extends ObjectCopier {
783782

784783
final Map<Object, ObjectID> objectToId = new IdentityHashMap<>();
785784
final List<Object> objects = new ArrayList<>();
@@ -790,14 +789,25 @@ static class Encoder extends ObjectCopier {
790789
*/
791790
final Map<Object, Field> externalValues = new IdentityHashMap<>();
792791

793-
Encoder(List<Field> externalValues) {
792+
public Encoder(List<Field> externalValues) {
794793
objects.add(null);
795794
objectToId.put(null, new ObjectID(0, null));
796795
for (Field f : externalValues) {
797796
addExternalValue(f);
798797
}
799798
}
800799

800+
/**
801+
* Gets a {@link ClassInfo} for encoding the fields of {@code declaringClass}.
802+
* <p>
803+
* A subclass can override this to enforce encoding invariants on classes or fields.
804+
*
805+
* @throws GraalError if an invariant is violated
806+
*/
807+
protected ClassInfo makeClassInfo(Class<?> declaringClass) {
808+
return ClassInfo.of(declaringClass);
809+
}
810+
801811
private void addExternalValue(Field field) {
802812
GraalError.guarantee(Modifier.isStatic(field.getModifiers()), "Field '%s' is not static. Only a static field can be used as known location for an instance.", field);
803813
Object value = readField(field, null);
@@ -814,6 +824,10 @@ private void addExternalValue(Field field) {
814824

815825
}
816826

827+
public Map<Object, Field> getExternalValues() {
828+
return externalValues;
829+
}
830+
817831
private String encodeMap(UnmodifiableEconomicMap<?, ?> map) {
818832
UnmodifiableMapCursor<?, ?> cursor = map.getEntries();
819833
StringBuilder value = new StringBuilder();
@@ -858,8 +872,6 @@ ObjectID makeId(Object obj, ObjectPath objectPath) {
858872
objectToId.put(field, id);
859873
return id;
860874
}
861-
checkIllegalValue(Field.class, obj, objectPath, "Field type is used in object copying implementation");
862-
checkIllegalValue(FieldIntrospection.class, obj, objectPath, "Graal metadata type cannot be copied");
863875

864876
objects.add(obj);
865877
objectToId.put(obj, id);
@@ -871,6 +883,10 @@ ObjectID makeId(Object obj, ObjectPath objectPath) {
871883
builtin.makeChildIds(this, obj, objectPath);
872884
return id;
873885
}
886+
887+
checkIllegalValue(Field.class, obj, objectPath, "Field type is used in object copying implementation");
888+
checkIllegalValue(FieldIntrospection.class, obj, objectPath, "Graal metadata type cannot be copied");
889+
874890
if (clazz.isArray()) {
875891
Class<?> componentType = clazz.getComponentType();
876892
if (!componentType.isPrimitive()) {
@@ -885,7 +901,7 @@ ObjectID makeId(Object obj, ObjectPath objectPath) {
885901
checkIllegalValue(LocationIdentity.class, obj, objectPath, "must come from a static field");
886902
checkIllegalValue(HashSet.class, obj, objectPath, "hashes are typically not stable across VM executions");
887903

888-
ClassInfo classInfo = classInfos.computeIfAbsent(clazz, ClassInfo::of);
904+
ClassInfo classInfo = classInfos.computeIfAbsent(clazz, this::makeClassInfo);
889905
for (Field f : classInfo.fields().values()) {
890906
makeId(f.getType(), objectPath.add(f.getName() + ":type"));
891907
if (!f.getType().isPrimitive()) {

substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse univers
5757
public void cleanupAfterAnalysis() {
5858
super.cleanupAfterAnalysis();
5959
// No need to keep method graphs for standalone analysis.
60-
universe.getMethods().forEach(m -> {
61-
m.setAnalyzedGraph(null);
62-
});
60+
universe.getMethods().forEach(AnalysisMethod::clearAnalyzedGraph);
6361
universe.getMethods().clear();
6462
universe.getFields().clear();
6563
addedClinits.clear();

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public final class AnalysisParsedGraph {
7070
private final EncodedGraph encodedGraph;
7171
private final boolean isIntrinsic;
7272

73-
private AnalysisParsedGraph(EncodedGraph encodedGraph, boolean isIntrinsic) {
73+
public AnalysisParsedGraph(EncodedGraph encodedGraph, boolean isIntrinsic) {
7474
this.isIntrinsic = isIntrinsic;
7575
this.encodedGraph = encodedGraph;
7676
}

0 commit comments

Comments
 (0)