Skip to content

Commit c11dd2e

Browse files
committed
[GR-67940] Update documentation.
PullRequest: graal/21583
2 parents fe9c585 + adee114 commit c11dd2e

File tree

11 files changed

+134
-29
lines changed

11 files changed

+134
-29
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/SubstitutionProcessor.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,22 @@
2424
*/
2525
package com.oracle.graal.pointsto.infrastructure;
2626

27+
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
28+
2729
import jdk.vm.ci.meta.ResolvedJavaField;
2830
import jdk.vm.ci.meta.ResolvedJavaMethod;
2931
import jdk.vm.ci.meta.ResolvedJavaType;
3032

33+
/**
34+
* A substitution processor is a facility that allows modifying code elements coming from class
35+
* files without modifying the class files. It is queried by the {@link AnalysisUniverse} when
36+
* creating the analysis model of a hosted element (type, method, field) to check if a substitution
37+
* is available. How a substitution processor is implemented, i.e., when a processor decides to
38+
* replace an element and how that element is constructed, is not specified. The substitution
39+
* processors form a chain, created via {@link #chainUpInOrder(SubstitutionProcessor...)} and
40+
* {@link #extendsTheChain(SubstitutionProcessor, SubstitutionProcessor[])} utility methods, and are
41+
* queried in the order in which they were installed.
42+
*/
3143
public abstract class SubstitutionProcessor {
3244

3345
/**
@@ -40,10 +52,24 @@ public ResolvedJavaType lookup(ResolvedJavaType type) {
4052
return type;
4153
}
4254

55+
/**
56+
* Get the substitution of an original field.
57+
*
58+
* @param field the original field
59+
* @return the substitution field, or the original field if it isn't covered by this
60+
* substitution
61+
*/
4362
public ResolvedJavaField lookup(ResolvedJavaField field) {
4463
return field;
4564
}
4665

66+
/**
67+
* Get the substitution of an original method.
68+
*
69+
* @param method the original method
70+
* @return the substitution method, or the original method if it isn't covered by this
71+
* substitution
72+
*/
4773
public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
4874
return method;
4975
}
@@ -80,7 +106,7 @@ public static SubstitutionProcessor chainUpInOrder(SubstitutionProcessor... proc
80106
return current;
81107
}
82108

83-
public static SubstitutionProcessor chain(SubstitutionProcessor first, SubstitutionProcessor second) {
109+
private static SubstitutionProcessor chain(SubstitutionProcessor first, SubstitutionProcessor second) {
84110
if (first == IDENTITY) {
85111
return second;
86112
} else if (second == IDENTITY) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Uninterruptible.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
* semantics. Covariant return types are not allowed when overriding a method, i.e., the base method
6767
* and the override must have the exact same declared return type. Covariant return types require a
6868
* synthetic bridge method that is generated automatically by the Java compiler, and not all Java
69-
* compilers put the {@link Uninterruptible} annotation on the bridge metod too (for example ECJ).
69+
* compilers put the {@link Uninterruptible} annotation on the bridge method too (for example ECJ).
7070
* For consistency reasons, synthetic methods are therefore never treated as uninterruptible.
7171
* <p>
7272
* Annotated methods give a terse {@link #reason} why they are annotated. Often the reason is that

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
/**
5353
* Information about the runtime class initialization state of a {@link DynamicHub class}, and
54-
* {@link #slowPath(ClassInitializationInfo, DynamicHub)} implementation} of class initialization
54+
* {@link #slowPath(ClassInitializationInfo, DynamicHub) implementation} of class initialization
5555
* according to the Java VM specification.
5656
* <p>
5757
* The information is not directly stored in {@link DynamicHub} because 1) the class initialization

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public static Resources[] layeredSingletons() {
129129
* {see com.oracle.svm.hosted.ModuleLayerFeature}.
130130
*/
131131
private final EconomicMap<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> resources = ImageHeapMap.createNonLayeredMap();
132+
/** Regexp patterns used to match names of resources to be included in the image. */
132133
private final EconomicMap<RequestedPattern, RuntimeConditionSet> requestedPatterns = ImageHeapMap.createNonLayeredMap();
133134

134135
/**
@@ -152,7 +153,7 @@ public static Resources[] layeredSingletons() {
152153
@Platforms(Platform.HOSTED_ONLY.class) //
153154
private final Set<String> previousLayerPatterns;
154155

155-
public record RequestedPattern(String module, String resource) {
156+
public record RequestedPattern(String module, String pattern) {
156157
}
157158

158159
public interface ModuleResourceKey {
@@ -437,6 +438,7 @@ public void registerIncludePattern(ConfigurationCondition condition, String modu
437438
}
438439
}
439440

441+
@Platforms(Platform.HOSTED_ONLY.class)
440442
private void addPattern(RequestedPattern pattern, RuntimeConditionSet condition) {
441443
if (!previousLayerPatterns.contains(pattern.toString())) {
442444
requestedPatterns.put(pattern, condition);
@@ -451,7 +453,7 @@ private void addPattern(RequestedPattern pattern, RuntimeConditionSet condition)
451453

452454
/*
453455
* This handles generated include patterns which start and end with \Q and \E. The actual
454-
* resource name is located inbetween those tags.
456+
* resource name is located in between those tags.
455457
*/
456458
@Platforms(Platform.HOSTED_ONLY.class)
457459
private static String handleEscapedCharacters(String pattern) {
@@ -574,7 +576,7 @@ private static boolean missingResourceMatchesIncludePattern(String resourceName,
574576
MapCursor<RequestedPattern, RuntimeConditionSet> cursor = r.requestedPatterns.getEntries();
575577
while (cursor.advance()) {
576578
RequestedPattern moduleResourcePair = cursor.getKey();
577-
if (Objects.equals(moduleName, moduleResourcePair.module) && matchResource(moduleResourcePair.resource, resourceName) && cursor.getValue().satisfied()) {
579+
if (Objects.equals(moduleName, moduleResourcePair.module) && matchResource(moduleResourcePair.pattern, resourceName) && cursor.getValue().satisfied()) {
578580
return true;
579581
}
580582
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ApplicationLayerOnlyImageSingleton.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@
2727
import org.graalvm.nativeimage.ImageSingletons;
2828

2929
import com.oracle.svm.core.SubstrateOptions;
30+
import com.oracle.svm.core.graal.nodes.LoadImageSingletonNode;
3031
import com.oracle.svm.core.option.HostedOptionValues;
3132

3233
/**
3334
* Identifies a singleton for which all lookups refer to a single singleton which will be created in
3435
* the application layer. See {@link LayeredImageSingleton} for full explanation.
36+
* <p>
37+
* Referring to fields of an {@link ApplicationLayerOnlyImageSingleton} object from a code compiled
38+
* in a shared layer, i.e., even before the value of the field can be known, is safe because an
39+
* {@link ApplicationLayerOnlyImageSingleton} will never be constant-folded in a shared layer. It is
40+
* instead implemented via {@link LoadImageSingletonNode} which is lowered to a singleton table
41+
* read.
3542
*/
3643
public interface ApplicationLayerOnlyImageSingleton extends LayeredImageSingleton {
3744

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/FastThreadLocalFactory.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import org.graalvm.word.WordBase;
3434

3535
/**
36-
* This class contains factory methods to create fast thread local variables. A thread local
36+
* This class contains factory methods to create {@link FastThreadLocal} variables. A thread local
3737
* variable is represented as an object, with different classes for primitive {@code int} (class
3838
* {@link FastThreadLocalInt}), primitive {@code long} (class {@link FastThreadLocalLong}),
3939
* {@link Object} (class {@link FastThreadLocalObject}), and {@link WordBase word} (class
4040
* {@link FastThreadLocalWord}) values. Access to such thread local variables is significantly
41-
* faster than regular Java {@link ThreadLocal} variables. However, there are several restrictions:
41+
* faster than regular Java {@link ThreadLocal} variables. This is achieved by determining all the
42+
* {@link FastThreadLocal} values and their size at build time and reserving space in the
43+
* {@link IsolateThread} data structure. However, there are several restrictions:
4244
* <ul>
4345
* <li>The thread local object must be created during native image generation. Otherwise, the size
4446
* of the {@link IsolateThread} data structure would not be a compile time constant.</li>
@@ -63,6 +65,9 @@
6365
* The implementation of fast thread local variables and the way the data is stored is
6466
* implementation specific and transparent for users of it. However, the access is fast and never
6567
* requires object allocation.
68+
* <p>
69+
* See also {@link VMThreadLocalInfo} for additional information about how a {@link FastThreadLocal}
70+
* is handled during build time.
6671
*/
6772
@Platforms(Platform.HOSTED_ONLY.class)
6873
public final class FastThreadLocalFactory {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@
2828

2929
import java.util.function.IntSupplier;
3030

31+
import org.graalvm.nativeimage.IsolateThread;
3132
import org.graalvm.nativeimage.Platform;
3233
import org.graalvm.nativeimage.Platforms;
3334
import org.graalvm.word.LocationIdentity;
3435
import org.graalvm.word.WordBase;
3536

3637
import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation;
3738
import com.oracle.svm.core.config.ConfigurationValues;
39+
import com.oracle.svm.core.graal.thread.LoadVMThreadLocalNode;
40+
import com.oracle.svm.core.graal.thread.StoreVMThreadLocalNode;
3841
import com.oracle.svm.core.heap.UnknownPrimitiveField;
3942

4043
import jdk.vm.ci.meta.JavaKind;
@@ -74,7 +77,18 @@ public static Class<?> getValueClass(Class<? extends FastThreadLocal> threadLoca
7477
public final boolean allowFloatingReads;
7578
public final String name;
7679

80+
/**
81+
* Offset of this thread local variable from its holder thread {@link IsolateThread} data
82+
* structure. It is a compile time constant, determined by collecting and sorting all thread
83+
* locals, and used during lowering of {@link FastThreadLocal} specific operations, e.g.,
84+
* {@link LoadVMThreadLocalNode}, {@link StoreVMThreadLocalNode} and others.
85+
*/
7786
@UnknownPrimitiveField(availability = ReadyForCompilation.class) public int offset;
87+
/**
88+
* How many bytes does this thread local need for storage. Just like the {@link #offset} this is
89+
* a compile-time constant, determined by taking into account the {@link #storageKind} or via
90+
* the {@link #sizeSupplier}, and it is used to lay out the thread locals in memory.
91+
*/
7892
@UnknownPrimitiveField(availability = ReadyForCompilation.class) public int sizeInBytes;
7993

8094
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapMap.java

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,17 @@
3838

3939
/**
4040
* A thread-safe map implementation that optimizes its run time representation for space efficiency.
41-
*
42-
* At image build time the map is implemented as a {@link ConcurrentHashMap} wrapped into an
43-
* {@link EconomicMap}. The ImageHeapMapFeature intercepts each build time map and transforms it
44-
* into an actual memory-efficient {@link EconomicMap} backed by a flat object array during
45-
* analysis. The later image building stages see only the {@link EconomicMap}.
46-
*
41+
* <p>
42+
* At image build time the map is implemented as a {@link ConcurrentHashMap} or
43+
* {@link ConcurrentIdentityHashMap} wrapped into an {@link EconomicMapWrap}. The
44+
* ImageHeapCollectionFeature intercepts each build time map and transforms it into an actual
45+
* memory-efficient {@link EconomicMap} backed by a flat object array during analysis. The later
46+
* image building stages see only the {@link EconomicMap}.
47+
* <p>
48+
* Additionally, in layered builds, at run time this map can be part of a
49+
* {@link LayeredImageHeapMap} structure, i.e., conceptually a linked list of {@link EconomicMap}s
50+
* that spans across multiple layers.
51+
* <p>
4752
* This map implementation allows thread-safe collection of data at image build time and storing it
4853
* into a space efficient data structure at run time.
4954
*/
@@ -54,27 +59,43 @@ private ImageHeapMap() {
5459
}
5560

5661
/**
57-
* Create a hosted representation of an {@link ImageHeapMap}: a {@link ConcurrentHashMap}
58-
* wrapped into an {@link EconomicMap}. At run time this will be an actual memory-efficient
59-
* {@link EconomicMap} backed by a flat object array.
62+
* In non-layered builds this creates a regular {@link ImageHeapMap} (see above).
63+
* <p>
64+
* In layered builds this creates a map that expands across layers. During the current layer
65+
* build this is a {@link ConcurrentHashMap} wrapped by an {@link EconomicMapWrap}. At run time
66+
* it is part of a {@link LayeredImageHeapMap} structure, i.e., conceptually a linked list of
67+
* {@link EconomicMap}s that spans across multiple layers.
6068
*/
6169
@Platforms(Platform.HOSTED_ONLY.class) //
6270
public static <K, V> EconomicMap<K, V> create(String key) {
6371
return create(Equivalence.DEFAULT, key);
6472
}
6573

66-
@Platforms(Platform.HOSTED_ONLY.class) //
67-
public static <K, V> EconomicMap<K, V> createNonLayeredMap() {
68-
return createNonLayeredMap(Equivalence.DEFAULT);
69-
}
70-
74+
/**
75+
* Same as {@link #create(String)}, but if the {@code strategy} is {@link Equivalence#IDENTITY}
76+
* the hosted map is a {@link ConcurrentIdentityHashMap}.
77+
*/
7178
@Platforms(Platform.HOSTED_ONLY.class) //
7279
public static <K, V> EconomicMap<K, V> create(Equivalence strategy, String key) {
7380
assert key != null : "The key should not be null if the map needs to be automatically layered";
7481
VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to create an ImageHeapMap after analysis.");
7582
return HostedImageHeapMap.create(strategy, key, true);
7683
}
7784

85+
/**
86+
* Create an {@link ImageHeapMap}. At build time it is a {@link ConcurrentHashMap} wrapped into
87+
* an {@link EconomicMapWrap}. At run time this will be an actual memory-efficient
88+
* {@link EconomicMap} backed by a flat object array.
89+
*/
90+
@Platforms(Platform.HOSTED_ONLY.class) //
91+
public static <K, V> EconomicMap<K, V> createNonLayeredMap() {
92+
return createNonLayeredMap(Equivalence.DEFAULT);
93+
}
94+
95+
/**
96+
* Same as {@link #createNonLayeredMap()}, but if the {@code strategy} is
97+
* {@link Equivalence#IDENTITY} the hosted map is a {@link ConcurrentIdentityHashMap}.
98+
*/
7899
@Platforms(Platform.HOSTED_ONLY.class) //
79100
public static <K, V> EconomicMap<K, V> createNonLayeredMap(Equivalence strategy) {
80101
VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to create an ImageHeapMap after analysis.");
@@ -115,12 +136,10 @@ public EconomicMap<Object, Object> getRuntimeMap() {
115136
return runtimeMap;
116137
}
117138

118-
public static <K, V> HostedImageHeapMap<K, V> create(Equivalence strategy, String key, boolean needLayeredMap) {
139+
public static <K, V> HostedImageHeapMap<K, V> create(Equivalence strategy, String key, boolean isLayeredMap) {
119140
Map<K, V> hostedMap = (strategy == Equivalence.IDENTITY) ? new ConcurrentIdentityHashMap<>() : new ConcurrentHashMap<>();
120141
EconomicMap<Object, Object> currentLayerMap = EconomicMap.create(strategy);
121-
if (!needLayeredMap || !ImageLayerBuildingSupport.buildingImageLayer()) {
122-
return new HostedImageHeapMap<>(hostedMap, currentLayerMap, currentLayerMap);
123-
} else {
142+
if (ImageLayerBuildingSupport.buildingImageLayer() && isLayeredMap) {
124143
LayeredImageHeapMap<Object, Object> runtimeMap = new LayeredImageHeapMap<>(strategy, key);
125144
var previousMap = LayeredImageHeapMapStore.currentLayer().getImageHeapMapStore().put(key, currentLayerMap);
126145
if (previousMap != null) {
@@ -132,6 +151,8 @@ public static <K, V> HostedImageHeapMap<K, V> create(Equivalence strategy, Strin
132151
singleton.registerPreviousLayerHostedImageHeapMap(hostedImageHeapMap);
133152
}
134153
return hostedImageHeapMap;
154+
} else {
155+
return new HostedImageHeapMap<>(hostedMap, currentLayerMap, currentLayerMap);
135156
}
136157
}
137158
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/LayeredImageHeapMapStore.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
3838
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
3939

40+
/**
41+
* Per layer store for the {@link LayeredImageHeapMap}s. There exists one
42+
* {@link LayeredImageHeapMapStore} per layer and each entry in the underlying
43+
* {@link #imageHeapMapStore} corresponds to a specific {@link LayeredImageHeapMap}, identified by
44+
* its {@link LayeredImageHeapMap#getMapKey()}.
45+
*/
4046
public class LayeredImageHeapMapStore implements MultiLayeredImageSingleton, UnsavedSingleton {
4147
private final Map<String, EconomicMap<Object, Object>> imageHeapMapStore = new HashMap<>();
4248

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import java.util.function.Predicate;
4949
import java.util.function.Supplier;
5050

51-
import com.oracle.svm.hosted.SVMHost;
5251
import org.graalvm.nativeimage.AnnotationAccess;
5352
import org.graalvm.nativeimage.ImageSingletons;
5453
import org.graalvm.nativeimage.Platform;
@@ -58,6 +57,7 @@
5857
import com.oracle.graal.pointsto.BigBang;
5958
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
6059
import com.oracle.graal.pointsto.meta.AnalysisField;
60+
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
6161
import com.oracle.svm.core.SubstrateOptions;
6262
import com.oracle.svm.core.SubstrateUtil;
6363
import com.oracle.svm.core.Uninterruptible;
@@ -84,8 +84,10 @@
8484
import com.oracle.svm.hosted.ImageClassLoader;
8585
import com.oracle.svm.hosted.NativeImageGenerator;
8686
import com.oracle.svm.hosted.NativeImageOptions;
87+
import com.oracle.svm.hosted.SVMHost;
8788
import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport;
8889
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
90+
import com.oracle.svm.hosted.meta.HostedUniverse;
8991
import com.oracle.svm.util.ReflectionUtil;
9092
import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
9193

@@ -94,6 +96,28 @@
9496
import jdk.vm.ci.meta.ResolvedJavaMethod;
9597
import jdk.vm.ci.meta.ResolvedJavaType;
9698

99+
/**
100+
* The main substitution processor for Native Image. The annotations supported by this processor
101+
* are:
102+
* <ul>
103+
* <li>{@link TargetClass}</li>
104+
* <li>{@link Substitute}</li>
105+
* <li>{@link TargetElement}</li>
106+
* <li>{@link Alias}</li>
107+
* <li>{@link AnnotateOriginal}</li>
108+
* <li>{@link Delete}</li>
109+
* <li>{@link Inject}</li>
110+
* <li>{@link InjectAccessors}</li>
111+
* <li>{@link KeepOriginal}</li>
112+
* <li>{@link RecomputeFieldValue}</li>
113+
* </ul>
114+
* Code tagged with these annotations is preprocessed during Native Image setup when the processor
115+
* is {@link AnnotationSubstitutionProcessor#init(FieldValueInterceptionSupport) initialized}. Then,
116+
* hosted code corresponding to the substitution code is intercepted and replaced without modifying
117+
* the class files during {@link AnalysisUniverse} lookups. See each annotation's JavaDoc for more
118+
* details, starting with {@link TargetClass}. See also {@link HostedUniverse} for a comprehensive
119+
* description of the substitution layer.
120+
*/
97121
public class AnnotationSubstitutionProcessor extends SubstitutionProcessor {
98122

99123
/**
@@ -306,7 +330,7 @@ public void registerUnsafeAccessedFields(BigBang bb) {
306330
}
307331

308332
public void init(FieldValueInterceptionSupport newFieldValueInterceptionSupport) {
309-
/**
333+
/*
310334
* Cannot set this field in the constructor due to cyclic dependencies between the two
311335
* classes.
312336
*/

0 commit comments

Comments
 (0)