Skip to content

[GR-67922] Refactor layered class initialization: load base layer simulation result. #11951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import com.oracle.svm.core.hub.RuntimeClassLoading;
import jdk.graal.compiler.word.Word;
import org.graalvm.nativeimage.CurrentIsolate;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.Platform;
Expand All @@ -39,13 +37,15 @@
import com.oracle.svm.core.c.InvokeJavaFunctionPointer;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.PredefinedClassesSupport;
import com.oracle.svm.core.hub.RuntimeClassLoading;
import com.oracle.svm.core.jdk.InternalVMMethod;
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
import com.oracle.svm.core.thread.ContinuationSupport;
import com.oracle.svm.core.thread.JavaThreads;
import com.oracle.svm.core.thread.Target_jdk_internal_vm_Continuation;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.word.Word;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.Reflection;

Expand Down Expand Up @@ -246,6 +246,14 @@ public ClassInitializationInfo(boolean typeReachedTracked) {
this.initLock = new ReentrantLock();
}

public InitState getInitState() {
return initState;
}

public boolean isSlowPathRequired() {
return slowPathRequired;
}

public boolean hasInitializer() {
return hasInitializer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,38 @@ struct PersistedAnalysisType {
isInitialized @9 :Bool;
# True if the type was configured as initialized at BUILD_TIME but initialization failed so it was registered as RUN_TIME.
isFailedInitialization @10 :Bool;
isLinked @11 :Bool;
sourceFileName @12 :Text;
enclosingTypeId @13 :TypeId;
componentTypeId @14 :TypeId;
superClassTypeId @15 :TypeId;
isInstantiated @16 :Bool;
isUnsafeAllocated @17 :Bool;
isReachable @18 :Bool;
interfaces @19 :List(TypeId);
instanceFieldIds @20 :List(FieldId);
instanceFieldIdsWithSuper @21 :List(FieldId);
staticFieldIds @22 :List(FieldId);
annotationList @23 :List(Annotation);
classInitializationInfo @24 :ClassInitializationInfo;
hasArrayType @25 :Bool;
subTypes @26 :List(TypeId);
isAnySubtypeInstantiated @27 :Bool;
# Type's initializer simulation succeeded. We'll also persist simulated field values.
isSuccessfulSimulation @11 :Bool;
# Type's initializer simulation failed.
isFailedSimulation @12 :Bool;
isLinked @13 :Bool;
sourceFileName @14 :Text;
enclosingTypeId @15 :TypeId;
componentTypeId @16 :TypeId;
superClassTypeId @17 :TypeId;
isInstantiated @18 :Bool;
isUnsafeAllocated @19 :Bool;
isReachable @20 :Bool;
interfaces @21 :List(TypeId);
instanceFieldIds @22 :List(FieldId);
instanceFieldIdsWithSuper @23 :List(FieldId);
staticFieldIds @24 :List(FieldId);
annotationList @25 :List(Annotation);
classInitializationInfo @26 :ClassInitializationInfo;
hasArrayType @27 :Bool;
hasClassInitInfo @28 :Bool;
subTypes @29 :List(TypeId);
isAnySubtypeInstantiated @30 :Bool;
wrappedType :union {
none @28 :Void; # default
none @31 :Void; # default
serializationGenerated :group {
rawDeclaringClass @29 :Text;
rawTargetConstructor @30 :Text;
rawDeclaringClass @32 :Text;
rawTargetConstructor @33 :Text;
}
lambda :group {
capturingClass @31 :Text;
capturingClass @34 :Text;
}
proxyType @32 :Void;
proxyType @35 :Void;
}
}

Expand Down Expand Up @@ -151,6 +156,7 @@ struct PersistedAnalysisField {
name @16 :Text;
priorInstalledLayerNum @17 :Int32;
assignmentStatus @18 :Int32;
simulatedFieldValue @19 :ConstantReference;
}

struct CEntryPointLiteralReference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,9 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
aUniverse = createAnalysisUniverse(options, target, loader, originalMetaAccess, annotationSubstitutions, cEnumProcessor,
classInitializationSupport, Collections.singletonList(harnessSubstitutions), missingRegistrationSupport);

SVMImageLayerWriter imageLayerWriter = null;
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
SVMImageLayerWriter imageLayerWriter = HostedImageLayerBuildingSupport.singleton().getWriter();
imageLayerWriter = HostedImageLayerBuildingSupport.singleton().getWriter();
aUniverse.setImageLayerWriter(imageLayerWriter);
imageLayerWriter.setAnalysisUniverse(aUniverse);
}
Expand All @@ -1045,7 +1046,11 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
HostedProviders aProviders = createHostedProviders(target, aUniverse, originalProviders, platformConfig, aMetaAccess, classInitializationSupport);
aUniverse.hostVM().initializeProviders(aProviders);

ImageSingletons.add(SimulateClassInitializerSupport.class, (hostVM).createSimulateClassInitializerSupport(aMetaAccess));
SimulateClassInitializerSupport simulateClassInitializerSupport = hostVM.createSimulateClassInitializerSupport(aMetaAccess);
ImageSingletons.add(SimulateClassInitializerSupport.class, simulateClassInitializerSupport);
if (imageLayerWriter != null) {
imageLayerWriter.setSimulateClassInitializerSupport(simulateClassInitializerSupport);
}

bb = createBigBang(debug, options, aUniverse, aMetaAccess, aProviders, annotationSubstitutions);
aUniverse.setBigBang(bb);
Expand All @@ -1064,8 +1069,8 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
ImageHeapScanner heapScanner = new SVMImageHeapScanner(bb, imageHeap, loader, aMetaAccess, aProviders.getSnippetReflection(),
aProviders.getConstantReflection(), aScanningObserver, hostedValuesProvider);
aUniverse.setHeapScanner(heapScanner);
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
HostedImageLayerBuildingSupport.singleton().getWriter().setImageHeap(imageHeap);
if (imageLayerWriter != null) {
imageLayerWriter.setImageHeap(imageHeap);
}
((HostedSnippetReflectionProvider) aProviders.getSnippetReflection()).setHeapScanner(heapScanner);
if (imageLayerLoader != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.oracle.svm.core.encoder.IdentitySymbolEncoder;
import com.oracle.svm.core.encoder.SymbolEncoder;
import org.graalvm.nativeimage.c.function.CFunctionPointer;

import com.oracle.graal.pointsto.BigBang;
Expand All @@ -45,6 +43,8 @@
import com.oracle.graal.pointsto.util.AnalysisError;
import com.oracle.svm.core.BuildPhaseProvider;
import com.oracle.svm.core.classinitialization.ClassInitializationInfo;
import com.oracle.svm.core.encoder.IdentitySymbolEncoder;
import com.oracle.svm.core.encoder.SymbolEncoder;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubCompanion;
import com.oracle.svm.core.hub.RuntimeClassLoading;
Expand All @@ -57,6 +57,7 @@
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader;
import com.oracle.svm.hosted.jdk.HostedClassLoaderPackageManagement;
import com.oracle.svm.util.ReflectionUtil;

Expand All @@ -81,6 +82,7 @@ public class DynamicHubInitializer {
private final Field hubCompanionInterfacesEncoding;
private final Field hubCompanionAnnotationsEnumConstantsReference;
private final Field hubCompanionInterpreterType;
private final SVMImageLayerLoader layerLoader;

public DynamicHubInitializer(BigBang bb) {
this.bb = bb;
Expand All @@ -96,6 +98,7 @@ public DynamicHubInitializer(BigBang bb) {
hubCompanionInterfacesEncoding = ReflectionUtil.lookupField(DynamicHubCompanion.class, "interfacesEncoding");
hubCompanionAnnotationsEnumConstantsReference = ReflectionUtil.lookupField(DynamicHubCompanion.class, "enumConstantsReference");
hubCompanionInterpreterType = ReflectionUtil.lookupField(DynamicHubCompanion.class, "interpreterType");
layerLoader = HostedImageLayerBuildingSupport.singleton().getLoader();
}

public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) {
Expand Down Expand Up @@ -242,18 +245,19 @@ private Enum<?>[] retrieveEnumConstantArray(AnalysisType type, Class<?> javaClas

private void buildClassInitializationInfo(ImageHeapScanner heapScanner, AnalysisType type, DynamicHub hub, boolean rescan) {
AnalysisError.guarantee(hub.getClassInitializationInfo() == null, "Class initialization info already computed for %s.", type.toJavaName(true));
boolean initializedAtBuildTime = SimulateClassInitializerSupport.singleton().trySimulateClassInitializer(bb, type);
boolean initializedOrSimulated = SimulateClassInitializerSupport.singleton().trySimulateClassInitializer(bb, type);
ClassInitializationInfo info;
if (type.getWrapped() instanceof BaseLayerType) {
info = HostedImageLayerBuildingSupport.singleton().getLoader().getClassInitializationInfo(type);
info = layerLoader.getClassInitializationInfo(type);
} else {
boolean typeReachedTracked = ClassInitializationSupport.singleton().requiresInitializationNodeForTypeReached(type);
if (initializedAtBuildTime) {
if (initializedOrSimulated) {
info = type.getClassInitializer() == null ? ClassInitializationInfo.forNoInitializerInfo(typeReachedTracked)
: ClassInitializationInfo.forInitializedInfo(typeReachedTracked);
} else {
info = buildRuntimeInitializationInfo(type, typeReachedTracked);
}
VMError.guarantee(!type.isInBaseLayer() || layerLoader.isInitializationInfoStable(type, info));
}
hub.setClassInitializationInfo(info);
if (rescan) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ private void reportKind(AfterAnalysisAccessImpl access, PrintWriter writer, Init
if (kind != BUILD_TIME) {
Optional<AnalysisType> type = access.getMetaAccess().optionalLookupJavaType(clazz);
if (type.isPresent()) {
simulated = SimulateClassInitializerSupport.singleton().isClassInitializerSimulated(type.get());
simulated = SimulateClassInitializerSupport.singleton().isSimulatedOrInitializedAtBuildTime(type.get());
}
}
if (simulated) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public final class SimulateClassInitializerClusterMember {
final AnalysisType type;

final EconomicSet<SimulateClassInitializerClusterMember> dependencies = EconomicSet.create();
/** Keeps track of why the type could not be simulated as initialized. */
final List<Object> notInitializedReasons = new ArrayList<>();
/** The values resulting from a successful simulation. */
final EconomicMap<AnalysisField, JavaConstant> staticFieldValues = EconomicMap.create();

/** The mutable status field of the cluster member. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ final class SimulateClassInitializerConstantFieldProvider extends AnalysisConsta

@Override
protected boolean isClassInitialized(ResolvedJavaField field) {
return support.isClassInitializerSimulated((AnalysisType) field.getDeclaringClass());
return support.isSimulatedOrInitializedAtBuildTime((AnalysisType) field.getDeclaringClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@
*/
final class SimulateClassInitializerResult {

/** We didn't try simulation either because the feature is disabled or type's linking failed. */
static final SimulateClassInitializerResult NOT_SIMULATED_INITIALIZED = new SimulateClassInitializerResult(false, null);
/** We tried simulating the type's initializer but failed. */
static final SimulateClassInitializerResult FAILED_SIMULATED_INITIALIZED = new SimulateClassInitializerResult(false, null);
/** Type was already initialized in the host VM. We didn't try to simulate it. */
static final SimulateClassInitializerResult INITIALIZED_HOSTED = SimulateClassInitializerResult.forInitialized(EconomicMap.emptyMap());

/** True if the class initializer was successfully simulated as initialized. */
final boolean simulatedInitialized;
/** The simulated field values published in case of a successful simulation. */
final UnmodifiableEconomicMap<AnalysisField, JavaConstant> staticFieldValues;

static SimulateClassInitializerResult forInitialized(EconomicMap<AnalysisField, JavaConstant> staticFieldValues) {
Expand Down
Loading
Loading