Skip to content

Commit 0643f9b

Browse files
author
Christian Wimmer
committed
Simulate class initializer
1 parent f065570 commit 0643f9b

File tree

37 files changed

+2939
-790
lines changed

37 files changed

+2939
-790
lines changed

compiler/src/jdk.internal.vm.compiler.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ protected void verify(StructuredGraph graph, CoreProviders context) {
122122
"org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidDumpUsagePhase.run",
123123
"org.graalvm.compiler.hotspot.SymbolicSnippetEncoder.verifySnippetEncodeDecode",
124124
"com.oracle.graal.pointsto.phases.InlineBeforeAnalysis.decodeGraph",
125+
"com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport.decodeGraph",
126+
"com.oracle.svm.hosted.classinitialization.SimulateClassInitializerAbortException.doAbort",
125127
"org.graalvm.compiler.truffle.compiler.phases.inlining.CallTree.dumpBasic",
126128
"org.graalvm.compiler.truffle.compiler.phases.inlining.GraphManager.peRoot"));
127129

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,11 @@ def cinterfacetutorial(args):
13301330

13311331
@mx.command(suite.name, 'clinittest', 'Runs the ')
13321332
def clinittest(args):
1333-
def build_and_test_clinittest_image(native_image, args=None):
1333+
def build_and_test_clinittest_images(native_image, args=None):
1334+
build_and_test_clinittest_image(native_image, args, True)
1335+
build_and_test_clinittest_image(native_image, args, False)
1336+
1337+
def build_and_test_clinittest_image(native_image, args, new_class_init_policy):
13341338
args = [] if args is None else args
13351339
test_cp = classpath('com.oracle.svm.test')
13361340
build_dir = join(svmbuild_dir(), 'clinittest')
@@ -1340,11 +1344,17 @@ def build_and_test_clinittest_image(native_image, args=None):
13401344
remove_tree(build_dir)
13411345
mkpath(build_dir)
13421346

1347+
if new_class_init_policy:
1348+
policy_args = ['-H:+UseNewExperimentalClassInitialization', '-H:+SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureNewPolicyFeature']
1349+
else:
1350+
policy_args = ['-H:-UseNewExperimentalClassInitialization', '-H:-SimulateClassInitializer', '-H:Features=com.oracle.svm.test.clinit.TestClassInitializationFeatureOldPolicyFeature']
1351+
13431352
# Build and run the example
13441353
native_image(
1345-
['-H:Path=' + build_dir, '-cp', test_cp, '-H:Class=com.oracle.svm.test.clinit.TestClassInitializationMustBeSafeEarly',
1346-
'-H:Features=com.oracle.svm.test.clinit.TestClassInitializationMustBeSafeEarlyFeature',
1347-
'-H:+PrintClassInitialization', '-H:Name=clinittest', '-H:+ReportExceptionStackTraces'] + args)
1354+
['-H:Path=' + build_dir, '-cp', test_cp, '-H:Class=com.oracle.svm.test.clinit.TestClassInitialization',
1355+
'-J--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED',
1356+
'-J-ea', '-J-esa',
1357+
'-H:+PrintClassInitialization', '-H:Name=clinittest', '-H:+ReportExceptionStackTraces'] + policy_args + args)
13481358
mx.run([join(build_dir, 'clinittest')])
13491359

13501360
# Check the reports for initialized classes
@@ -1358,9 +1368,17 @@ def checkLine(line, marker, init_kind, msg, wrongly_initialized_lines):
13581368
"Classes marked with " + marker + " must have init kind " + init_kind + " and message " + msg)]
13591369
with open(classes_file) as f:
13601370
for line in f:
1361-
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
1362-
checkLine(line, "MustBeSafeEarly", "BUILD_TIME", "class proven as side-effect free before analysis", wrongly_initialized_lines)
1363-
checkLine(line, "MustBeSafeLate", "BUILD_TIME", "class proven as side-effect free after analysis", wrongly_initialized_lines)
1371+
if new_class_init_policy:
1372+
checkLine(line, "MustBeSafeEarly", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
1373+
checkLine(line, "MustBeSafeLate", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
1374+
checkLine(line, "MustBeSimulated", "SIMULATED", "classes are initialized at run time by default", wrongly_initialized_lines)
1375+
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
1376+
else:
1377+
checkLine(line, "MustBeSafeEarly", "BUILD_TIME", "class proven as side-effect free before analysis", wrongly_initialized_lines)
1378+
checkLine(line, "MustBeSafeLate", "BUILD_TIME", "class proven as side-effect free after analysis", wrongly_initialized_lines)
1379+
checkLine(line, "MustBeSimulated", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
1380+
checkLine(line, "MustBeDelayed", "RUN_TIME", "classes are initialized at run time by default", wrongly_initialized_lines)
1381+
13641382
if len(wrongly_initialized_lines) > 0:
13651383
msg = ""
13661384
for (line, error) in wrongly_initialized_lines:
@@ -1372,7 +1390,7 @@ def checkLine(line, marker, init_kind, msg, wrongly_initialized_lines):
13721390

13731391
check_class_initialization(all_classes_file)
13741392

1375-
native_image_context_run(build_and_test_clinittest_image, args)
1393+
native_image_context_run(build_and_test_clinittest_images, args)
13761394

13771395

13781396
class SubstrateJvmFuncsFallbacksBuilder(mx.Project):

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
import java.lang.reflect.Array;
2828
import java.util.function.Consumer;
2929

30-
import org.graalvm.compiler.debug.GraalError;
31-
3230
import com.oracle.graal.pointsto.ObjectScanner;
3331
import com.oracle.graal.pointsto.meta.AnalysisType;
3432
import com.oracle.graal.pointsto.util.AnalysisError;
@@ -97,35 +95,10 @@ public JavaConstant readElementValue(int idx) {
9795

9896
@Override
9997
public void setElement(int idx, JavaConstant value) {
100-
/*
101-
* Constants for sub-integer types are often just integer constants, i.e., we cannot rely on
102-
* the JavaKind of the constant to match the type of the array.
103-
*/
104-
if (array instanceof boolean[] booleanArray) {
105-
booleanArray[idx] = value.asInt() != 0;
106-
} else if (array instanceof byte[] byteArray) {
107-
byte v = (byte) value.asInt();
108-
GraalError.guarantee(v == value.asInt(), "type mismatch");
109-
byteArray[idx] = v;
110-
} else if (array instanceof short[] shortArray) {
111-
short v = (short) value.asInt();
112-
GraalError.guarantee(v == value.asInt(), "type mismatch");
113-
shortArray[idx] = v;
114-
} else if (array instanceof char[] charArray) {
115-
char v = (char) value.asInt();
116-
GraalError.guarantee(v == value.asInt(), "type mismatch");
117-
charArray[idx] = v;
118-
} else if (array instanceof int[] intArray) {
119-
intArray[idx] = value.asInt();
120-
} else if (array instanceof long[] longArray) {
121-
longArray[idx] = value.asLong();
122-
} else if (array instanceof float[] floatArray) {
123-
floatArray[idx] = value.asFloat();
124-
} else if (array instanceof double[] doubleArray) {
125-
doubleArray[idx] = value.asDouble();
126-
} else {
127-
throw AnalysisError.shouldNotReachHere("Unexpected array type: " + array.getClass());
98+
if (value.getJavaKind() != type.getComponentType().getJavaKind()) {
99+
throw AnalysisError.shouldNotReachHere("Cannot store value of kind " + value.getJavaKind() + " into primitive array of type " + type);
128100
}
101+
Array.set(array, idx, value.asBoxedPrimitive());
129102
}
130103

131104
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ void markTypeInstantiated(AnalysisType type, ScanReason reason) {
181181
universe.getBigbang().registerTypeAsInHeap(type, reason);
182182
}
183183

184-
JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) {
184+
public JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) {
185185
if (isNonNullObjectConstant(constant)) {
186186
return getOrCreateImageHeapConstant(constant, reason);
187187
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ public enum UsageKind {
183183
}
184184

185185
private final AnalysisFuture<Void> onTypeReachableTask;
186+
private final AnalysisFuture<Void> initializeMetaDataTask;
187+
186188
/**
187189
* Additional information that is only available for types that are marked as reachable.
188190
*/
@@ -302,6 +304,7 @@ public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKi
302304

303305
/* The registration task initializes the type. */
304306
this.onTypeReachableTask = new AnalysisFuture<>(() -> universe.onTypeReachable(this), null);
307+
this.initializeMetaDataTask = new AnalysisFuture<>(() -> universe.initializeMetaData(this), null);
305308
this.typeData = new AnalysisFuture<>(() -> {
306309
AnalysisError.guarantee(universe.getHeapScanner() != null, "Heap scanner is not available.");
307310
return universe.getHeapScanner().computeTypeData(this);
@@ -689,6 +692,10 @@ public void ensureOnTypeReachableTaskDone() {
689692
onTypeReachableTask.ensureDone();
690693
}
691694

695+
public AnalysisFuture<Void> getInitializeMetaDataTask() {
696+
return initializeMetaDataTask;
697+
}
698+
692699
public boolean getReachabilityListenerNotified() {
693700
return reachabilityListenerNotified;
694701
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ public void onTypeReachable(AnalysisType type) {
702702
}
703703
}
704704

705+
public void initializeMetaData(AnalysisType type) {
706+
bb.initializeMetaData(type);
707+
}
708+
705709
public SubstitutionProcessor getSubstitutions() {
706710
return substitutions;
707711
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@
260260
import com.oracle.svm.hosted.cenum.CEnumCallWrapperSubstitutionProcessor;
261261
import com.oracle.svm.hosted.classinitialization.ClassInitializationFeature;
262262
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
263+
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
263264
import com.oracle.svm.hosted.code.CEntryPointCallStubSupport;
264265
import com.oracle.svm.hosted.code.CEntryPointData;
265266
import com.oracle.svm.hosted.code.CFunctionSubstitutionProcessor;
@@ -906,6 +907,8 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
906907
originalProviders, platformConfig, classInitializationSupport, aMetaAccess);
907908
aUniverse.hostVM().initializeProviders(aProviders);
908909

910+
ImageSingletons.add(SimulateClassInitializerSupport.class, ((SVMHost) aUniverse.hostVM()).createSimulateClassInitializerSupport(aMetaAccess));
911+
909912
bb = createBigBang(options, aUniverse, aMetaAccess, aProviders, analysisExecutor, loader.watchdog::recordActivity,
910913
annotationSubstitutions);
911914
aUniverse.setBigBang(bb);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
8080
import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess;
8181
import com.oracle.graal.pointsto.meta.AnalysisField;
82+
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
8283
import com.oracle.graal.pointsto.meta.AnalysisMethod;
8384
import com.oracle.graal.pointsto.meta.AnalysisType;
8485
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
@@ -117,6 +118,7 @@
117118
import com.oracle.svm.hosted.analysis.SVMParsingSupport;
118119
import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions;
119120
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
121+
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
120122
import com.oracle.svm.hosted.code.InliningUtilities;
121123
import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
122124
import com.oracle.svm.hosted.code.UninterruptibleAnnotationChecker;
@@ -126,6 +128,7 @@
126128
import com.oracle.svm.hosted.meta.HostedUniverse;
127129
import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase;
128130
import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase;
131+
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisGraphDecoderImpl;
129132
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyImpl;
130133
import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor;
131134
import com.oracle.svm.util.LogUtils;
@@ -283,7 +286,7 @@ public void onTypeReachable(AnalysisType analysisType) {
283286
}
284287

285288
/* Decide when the type should be initialized. */
286-
classInitializationSupport.maybeInitializeHosted(analysisType);
289+
classInitializationSupport.maybeInitializeAtBuildTime(analysisType);
287290

288291
/*
289292
* For reachable classes, registering class's package in appropriate class loader.
@@ -313,10 +316,10 @@ public void onTypeReachable(AnalysisType analysisType) {
313316

314317
@Override
315318
public boolean isInitialized(AnalysisType type) {
316-
boolean shouldInitializeAtRuntime = classInitializationSupport.shouldInitializeAtRuntime(type);
317-
assert shouldInitializeAtRuntime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;
319+
boolean initializedAtBuildTime = classInitializationSupport.maybeInitializeAtBuildTime(type);
320+
assert !initializedAtBuildTime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;
318321

319-
return !shouldInitializeAtRuntime;
322+
return initializedAtBuildTime;
320323
}
321324

322325
private final boolean parseOnce = SubstrateOptions.parseOnce();
@@ -740,7 +743,7 @@ protected InlineBeforeAnalysisPolicy<?> inlineBeforeAnalysisPolicy(MultiMethod.M
740743

741744
@Override
742745
public InlineBeforeAnalysisGraphDecoder<?> createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) {
743-
return new InlineBeforeAnalysisGraphDecoder<>(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method), null);
746+
return new InlineBeforeAnalysisGraphDecoderImpl<>(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method));
744747
}
745748

746749
public static class Options {
@@ -920,4 +923,8 @@ public boolean ignoreInstanceOfTypeDisallowed() {
920923
}
921924
return super.ignoreInstanceOfTypeDisallowed();
922925
}
926+
927+
public SimulateClassInitializerSupport createSimulateClassInitializerSupport(AnalysisMetaAccess aMetaAccess) {
928+
return new SimulateClassInitializerSupport(aMetaAccess, this);
929+
}
923930
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static JavaConstant readFieldValue(MetaAccessProvider metaAccess, ClassInitializ
5050
assert readableField.isValueAvailable() : "Field " + readableField.format("%H.%n") + " value not available for reading.";
5151
return readableField.readValue(metaAccess, classInitializationSupport, receiver);
5252

53-
} else if (classInitializationSupport.shouldInitializeAtRuntime(field.getDeclaringClass())) {
53+
} else if (!classInitializationSupport.maybeInitializeAtBuildTime(field.getDeclaringClass())) {
5454
/*
5555
* The class is initialized at image run time. We must not use any field value from the
5656
* image builder VM, even if the class is already initialized there. We need to return

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.svm.core.meta.MethodPointer;
4949
import com.oracle.svm.hosted.ExceptionSynthesizer;
5050
import com.oracle.svm.hosted.SVMHost;
51+
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
5152
import com.oracle.svm.util.ReflectionUtil;
5253

5354
import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -113,7 +114,7 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type)
113114
/* Support for Java enumerations. */
114115
if (type.isEnum()) {
115116
AnalysisError.guarantee(hub.shouldInitEnumConstants(), "Enum constants already initialized for %s.", type.toJavaName(true));
116-
if (hostVM.getClassInitializationSupport().shouldInitializeAtRuntime(type)) {
117+
if (!hostVM.getClassInitializationSupport().maybeInitializeAtBuildTime(type)) {
117118
hub.initEnumConstantsAtRuntime(javaClass);
118119
} else {
119120
hub.initEnumConstants(retrieveEnumConstantArray(type, javaClass));
@@ -164,12 +165,12 @@ private Enum<?>[] retrieveEnumConstantArray(AnalysisType type, Class<?> javaClas
164165

165166
private void buildClassInitializationInfo(ImageHeapScanner heapScanner, AnalysisType type, DynamicHub hub) {
166167
AnalysisError.guarantee(hub.getClassInitializationInfo() == null, "Class initialization info already computed for %s.", type.toJavaName(true));
168+
boolean initializedAtBuildTime = SimulateClassInitializerSupport.singleton().trySimulateClassInitializer(bb, type);
167169
ClassInitializationInfo info;
168-
if (hostVM.getClassInitializationSupport().shouldInitializeAtRuntime(type)) {
169-
info = buildRuntimeInitializationInfo(type);
170-
} else {
171-
assert type.isInitialized();
170+
if (initializedAtBuildTime) {
172171
info = type.getClassInitializer() == null ? ClassInitializationInfo.NO_INITIALIZER_INFO_SINGLETON : ClassInitializationInfo.INITIALIZED_INFO_SINGLETON;
172+
} else {
173+
info = buildRuntimeInitializationInfo(type);
173174
}
174175
hub.setClassInitializationInfo(info);
175176
heapScanner.rescanField(hub, dynamicHubClassInitializationInfoField);

0 commit comments

Comments
 (0)