Skip to content

Commit a9883bc

Browse files
committed
[GR-55278] [GR-58056] Collect all external values for Layered Image
PullRequest: graal/18949
2 parents 013e7eb + 3dad2f2 commit a9883bc

File tree

17 files changed

+345
-373
lines changed

17 files changed

+345
-373
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@
3535
import java.util.concurrent.TimeUnit;
3636
import java.util.stream.Collectors;
3737

38-
import jdk.graal.compiler.core.test.SubprocessTest;
3938
import org.graalvm.collections.EconomicMap;
4039
import org.junit.Assert;
4140
import org.junit.Test;
4241

42+
import jdk.graal.compiler.core.test.SubprocessTest;
4343
import jdk.graal.compiler.util.ObjectCopier;
4444

4545
/**
@@ -172,10 +172,10 @@ public void testIt() {
172172
root.put("singleton2", TestObject.TEST_OBJECT_SINGLETON);
173173
root.put("singleton2_2", TestObject.TEST_OBJECT_SINGLETON);
174174

175-
List<Field> externalValues = List.of(ObjectCopier.getField(BaseClass.class, "BASE_SINGLETON"),
175+
List<Field> externalValueFields = List.of(ObjectCopier.getField(BaseClass.class, "BASE_SINGLETON"),
176176
ObjectCopier.getField(TestObject.class, "TEST_OBJECT_SINGLETON"));
177177

178-
String encoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValues), root);
178+
String encoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValueFields), 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(new ObjectCopier.Encoder(externalValues), decoded);
187+
String reencoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValueFields), decoded);
188188
if (DEBUG) {
189189
System.out.printf("reencoded:%n%s%n", reencoded);
190190
}

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

Lines changed: 7 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,29 @@
2424
*/
2525
package jdk.graal.compiler.hotspot.libgraal;
2626

27-
import java.io.IOException;
2827
import java.lang.reflect.Field;
29-
import java.lang.reflect.Modifier;
30-
import java.net.URI;
31-
import java.nio.file.FileSystem;
32-
import java.nio.file.FileSystems;
3328
import java.nio.file.Files;
3429
import java.nio.file.Path;
3530
import java.util.ArrayList;
36-
import java.util.Collections;
3731
import java.util.List;
3832
import java.util.Locale;
39-
import java.util.stream.Stream;
4033

41-
import jdk.graal.compiler.core.common.spi.ForeignCallSignature;
42-
import jdk.graal.compiler.core.target.Backend;
43-
import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkage;
44-
import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
45-
import jdk.graal.compiler.truffle.hotspot.HotSpotTruffleCompilerImpl;
4634
import org.graalvm.collections.EconomicMap;
4735
import org.graalvm.collections.MapCursor;
48-
import org.graalvm.word.LocationIdentity;
4936

37+
import jdk.graal.compiler.core.common.spi.ForeignCallSignature;
38+
import jdk.graal.compiler.core.target.Backend;
5039
import jdk.graal.compiler.debug.GraalError;
5140
import jdk.graal.compiler.hotspot.EncodedSnippets;
41+
import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkage;
5242
import jdk.graal.compiler.hotspot.HotSpotGraalCompiler;
5343
import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider;
5444
import jdk.graal.compiler.hotspot.HotSpotReplacementsImpl;
5545
import jdk.graal.compiler.hotspot.SymbolicSnippetEncoder;
46+
import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
5647
import jdk.graal.compiler.hotspot.meta.HotSpotProviders;
5748
import jdk.graal.compiler.options.OptionValues;
49+
import jdk.graal.compiler.truffle.hotspot.HotSpotTruffleCompilerImpl;
5850
import jdk.graal.compiler.util.ObjectCopier;
5951
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
6052

@@ -84,13 +76,13 @@ public static void main(String[] args) throws Exception {
8476

8577
List<ForeignCallSignature> foreignCallSignatures = getForeignCallSignatures(replacements, options, graalRuntime);
8678
EncodedSnippets encodedSnippets = getEncodedSnippets(replacements, options);
87-
List<Field> externalValues = getExternalValues();
79+
List<Field> externalValueFields = ObjectCopier.getExternalValueFields();
8880

8981
EconomicMap<String, Object> encodedObjects = EconomicMap.create();
9082
encodedObjects.put("encodedSnippets", encodedSnippets);
9183
encodedObjects.put("foreignCallSignatures", foreignCallSignatures);
9284

93-
ObjectCopier.Encoder encoder = new ObjectCopier.Encoder(externalValues) {
85+
ObjectCopier.Encoder encoder = new ObjectCopier.Encoder(externalValueFields) {
9486
@Override
9587
protected ClassInfo makeClassInfo(Class<?> declaringClass) {
9688
ClassInfo ci = ClassInfo.of(declaringClass);
@@ -152,77 +144,4 @@ private static void collectForeignCalls(HotSpotHostForeignCallsProvider foreignC
152144
}
153145
});
154146
}
155-
156-
private static List<Field> getExternalValues() throws IOException {
157-
List<Field> externalValues = new ArrayList<>();
158-
addImmutableCollectionsFields(externalValues);
159-
addStaticFinalObjectFields(LocationIdentity.class, externalValues);
160-
161-
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap())) {
162-
for (String module : List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise")) {
163-
Path top = fs.getPath("/modules/" + module);
164-
try (Stream<Path> files = Files.find(top, Integer.MAX_VALUE, (path, attrs) -> attrs.isRegularFile())) {
165-
files.forEach(p -> {
166-
String fileName = p.getFileName().toString();
167-
if (fileName.endsWith(".class") && !fileName.equals("module-info.class")) {
168-
// Strip module prefix and convert to dotted form
169-
int nameCount = p.getNameCount();
170-
String className = p.subpath(2, nameCount).toString().replace('/', '.');
171-
// Strip ".class" suffix
172-
className = className.replace('/', '.').substring(0, className.length() - ".class".length());
173-
try {
174-
Class<?> graalClass = Class.forName(className);
175-
addStaticFinalObjectFields(graalClass, externalValues);
176-
} catch (ClassNotFoundException e) {
177-
throw new GraalError(e);
178-
}
179-
}
180-
});
181-
}
182-
}
183-
}
184-
return externalValues;
185-
}
186-
187-
/**
188-
* Adds the static, final, non-primitive fields of non-enum {@code declaringClass} to
189-
* {@code fields}. In the process, the fields are made {@linkplain Field#setAccessible
190-
* accessible}.
191-
*/
192-
private static void addStaticFinalObjectFields(Class<?> declaringClass, List<Field> fields) {
193-
if (Enum.class.isAssignableFrom(declaringClass)) {
194-
return;
195-
}
196-
for (Field field : declaringClass.getDeclaredFields()) {
197-
int fieldModifiers = field.getModifiers();
198-
int fieldMask = Modifier.STATIC | Modifier.FINAL;
199-
if ((fieldModifiers & fieldMask) != fieldMask) {
200-
continue;
201-
}
202-
if (field.getType().isPrimitive()) {
203-
continue;
204-
}
205-
field.setAccessible(true);
206-
fields.add(field);
207-
}
208-
}
209-
210-
/**
211-
* Adds the EMPTY* fields from {@code java.util.ImmutableCollections} to {@code fields}, making
212-
* them {@linkplain Field#setAccessible accessible} in the process.
213-
*/
214-
private static void addImmutableCollectionsFields(List<Field> fields) {
215-
Class<?> c = List.of().getClass().getDeclaringClass();
216-
GraalError.guarantee(c.getName().equals("java.util.ImmutableCollections"), "Incompatible ImmutableCollections class");
217-
for (Field f : c.getDeclaredFields()) {
218-
if (f.getName().startsWith("EMPTY")) {
219-
int modifiers = f.getModifiers();
220-
GraalError.guarantee(Modifier.isStatic(modifiers), "Expect %s to be static", f);
221-
GraalError.guarantee(Modifier.isFinal(modifiers), "Expect %s to be final", f);
222-
GraalError.guarantee(!f.getType().isPrimitive(), "Expect %s to be non-primitive", f);
223-
f.setAccessible(true);
224-
fields.add(f);
225-
}
226-
}
227-
}
228147
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/EncodedGraph.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import jdk.graal.compiler.debug.GraalError;
3131
import jdk.graal.compiler.graph.Node;
3232
import jdk.graal.compiler.graph.NodeClass;
33-
3433
import jdk.vm.ci.meta.Assumptions;
3534
import jdk.vm.ci.meta.ResolvedJavaMethod;
3635

@@ -139,6 +138,10 @@ public Object getObject(int i) {
139138
return objects[i];
140139
}
141140

141+
public void setObject(int i, Object object) {
142+
objects[i] = object;
143+
}
144+
142145
public NodeClass<?>[] getNodeClasses() {
143146
return types;
144147
}

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

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,18 @@
2525
package jdk.graal.compiler.util;
2626

2727
import java.io.ByteArrayOutputStream;
28+
import java.io.IOException;
2829
import java.io.PrintStream;
2930
import java.lang.reflect.Array;
3031
import java.lang.reflect.Field;
3132
import java.lang.reflect.Modifier;
33+
import java.net.URI;
34+
import java.nio.file.FileSystem;
35+
import java.nio.file.FileSystems;
36+
import java.nio.file.Files;
37+
import java.nio.file.Path;
3238
import java.util.ArrayList;
39+
import java.util.Collections;
3340
import java.util.HashMap;
3441
import java.util.HashSet;
3542
import java.util.IdentityHashMap;
@@ -785,16 +792,30 @@ public static class Encoder extends ObjectCopier {
785792

786793
/**
787794
* Map from values to static final fields. In a serialized object graph, references to such
788-
* values are encoded with a reference to the field.
795+
* values are encoded using the static final field they come from. This field is then looked
796+
* up via reflection when the value needs to be decoded.
789797
*/
790-
final Map<Object, Field> externalValues = new IdentityHashMap<>();
798+
final Map<Object, Field> externalValues;
791799

792-
public Encoder(List<Field> externalValues) {
800+
public Encoder(List<Field> externalValueFields) {
801+
this(gatherExternalValues(externalValueFields));
802+
}
803+
804+
/**
805+
* Use precomputed {@code externalValues} to avoid recomputing them.
806+
*/
807+
public Encoder(Map<Object, Field> externalValues) {
793808
objects.add(null);
794809
objectToId.put(null, new ObjectID(0, null));
795-
for (Field f : externalValues) {
796-
addExternalValue(f);
810+
this.externalValues = externalValues;
811+
}
812+
813+
public static Map<Object, Field> gatherExternalValues(List<Field> externalValueFields) {
814+
Map<Object, Field> result = new IdentityHashMap<>();
815+
for (Field f : externalValueFields) {
816+
addExternalValue(result, f);
797817
}
818+
return result;
798819
}
799820

800821
/**
@@ -808,7 +829,7 @@ protected ClassInfo makeClassInfo(Class<?> declaringClass) {
808829
return ClassInfo.of(declaringClass);
809830
}
810831

811-
private void addExternalValue(Field field) {
832+
private static void addExternalValue(Map<Object, Field> externalValues, Field field) {
812833
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);
813834
Object value = readField(field, null);
814835
if (value == null) {
@@ -825,7 +846,7 @@ private void addExternalValue(Field field) {
825846
}
826847

827848
public Map<Object, Field> getExternalValues() {
828-
return externalValues;
849+
return Collections.unmodifiableMap(externalValues);
829850
}
830851

831852
private String encodeMap(UnmodifiableEconomicMap<?, ?> map) {
@@ -1000,6 +1021,79 @@ public static Field getField(Class<?> declaredClass, String fieldName) {
10001021
}
10011022
}
10021023

1024+
public static List<Field> getExternalValueFields() throws IOException {
1025+
List<Field> externalValues = new ArrayList<>();
1026+
addImmutableCollectionsFields(externalValues);
1027+
addStaticFinalObjectFields(LocationIdentity.class, externalValues);
1028+
1029+
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap())) {
1030+
for (String module : List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise")) {
1031+
Path top = fs.getPath("/modules/" + module);
1032+
try (Stream<Path> files = Files.find(top, Integer.MAX_VALUE, (path, attrs) -> attrs.isRegularFile())) {
1033+
files.forEach(p -> {
1034+
String fileName = p.getFileName().toString();
1035+
if (fileName.endsWith(".class") && !fileName.equals("module-info.class")) {
1036+
// Strip module prefix and convert to dotted form
1037+
int nameCount = p.getNameCount();
1038+
String className = p.subpath(2, nameCount).toString().replace('/', '.');
1039+
// Strip ".class" suffix
1040+
className = className.replace('/', '.').substring(0, className.length() - ".class".length());
1041+
try {
1042+
Class<?> graalClass = Class.forName(className);
1043+
addStaticFinalObjectFields(graalClass, externalValues);
1044+
} catch (ClassNotFoundException e) {
1045+
throw new GraalError(e);
1046+
}
1047+
}
1048+
});
1049+
}
1050+
}
1051+
}
1052+
return externalValues;
1053+
}
1054+
1055+
/**
1056+
* Adds the static, final, non-primitive fields of non-enum {@code declaringClass} to
1057+
* {@code fields}. In the process, the fields are made {@linkplain Field#setAccessible
1058+
* accessible}.
1059+
*/
1060+
public static void addStaticFinalObjectFields(Class<?> declaringClass, List<Field> fields) {
1061+
if (Enum.class.isAssignableFrom(declaringClass)) {
1062+
return;
1063+
}
1064+
for (Field field : declaringClass.getDeclaredFields()) {
1065+
int fieldModifiers = field.getModifiers();
1066+
int fieldMask = Modifier.STATIC | Modifier.FINAL;
1067+
if ((fieldModifiers & fieldMask) != fieldMask) {
1068+
continue;
1069+
}
1070+
if (field.getType().isPrimitive()) {
1071+
continue;
1072+
}
1073+
field.setAccessible(true);
1074+
fields.add(field);
1075+
}
1076+
}
1077+
1078+
/**
1079+
* Adds the EMPTY* fields from {@code java.util.ImmutableCollections} to {@code fields}, making
1080+
* them {@linkplain Field#setAccessible accessible} in the process.
1081+
*/
1082+
private static void addImmutableCollectionsFields(List<Field> fields) {
1083+
Class<?> c = List.of().getClass().getDeclaringClass();
1084+
GraalError.guarantee(c.getName().equals("java.util.ImmutableCollections"), "Incompatible ImmutableCollections class");
1085+
for (Field f : c.getDeclaredFields()) {
1086+
if (f.getName().startsWith("EMPTY")) {
1087+
int modifiers = f.getModifiers();
1088+
GraalError.guarantee(Modifier.isStatic(modifiers), "Expect %s to be static", f);
1089+
GraalError.guarantee(Modifier.isFinal(modifiers), "Expect %s to be final", f);
1090+
GraalError.guarantee(!f.getType().isPrimitive(), "Expect %s to be non-primitive", f);
1091+
f.setAccessible(true);
1092+
fields.add(f);
1093+
}
1094+
}
1095+
}
1096+
10031097
/**
10041098
* Describes the path from a root object to a target object. That is, the sequence of field and
10051099
* array reads performed on the root object to access the target object.

0 commit comments

Comments
 (0)