Skip to content

Commit 2055cc2

Browse files
author
Christian Wimmer
committed
Simulate class initializer
1 parent bb4a66d commit 2055cc2

File tree

39 files changed

+3079
-791
lines changed

39 files changed

+3079
-791
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/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This changelog summarizes major changes to GraalVM Native Image.
66
* (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases.
77
* (GR-45841) BellSoft added support for the JFR event ThreadCPULoad.
88
* (GR-45994) Removed the option `-H:EnableSignalAPI`. Please use the runtime option `EnableSignalHandling` if it is necessary to enable or disable signal handling explicitly.
9+
* (GR-39406) Simulation of class initializer: Class initializer of classes that are not marked for initialization at image build time are simulated at image build time to avoid executing them at image run time.
910

1011
## Version 23.0.0
1112
* (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning.

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.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class InlineBeforeAnalysisGraphDecoder extends PEGraphDecoder {
5959

6060
public class InlineBeforeAnalysisMethodScope extends PEMethodScope {
6161

62-
private final InlineBeforeAnalysisPolicy.AbstractPolicyScope policyScope;
62+
public final InlineBeforeAnalysisPolicy.AbstractPolicyScope policyScope;
6363

6464
private boolean inliningAborted;
6565

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;
@@ -907,6 +908,8 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
907908
originalProviders, platformConfig, classInitializationSupport, aMetaAccess);
908909
aUniverse.hostVM().initializeProviders(aProviders);
909910

911+
ImageSingletons.add(SimulateClassInitializerSupport.class, ((SVMHost) aUniverse.hostVM()).createSimulateClassInitializerSupport(aMetaAccess));
912+
910913
bb = createBigBang(options, aUniverse, aMetaAccess, aProviders, analysisExecutor, loader.watchdog::recordActivity,
911914
annotationSubstitutions);
912915
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
@@ -80,6 +80,7 @@
8080
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
8181
import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess;
8282
import com.oracle.graal.pointsto.meta.AnalysisField;
83+
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
8384
import com.oracle.graal.pointsto.meta.AnalysisMethod;
8485
import com.oracle.graal.pointsto.meta.AnalysisType;
8586
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
@@ -118,6 +119,7 @@
118119
import com.oracle.svm.hosted.analysis.SVMParsingSupport;
119120
import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions;
120121
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
122+
import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport;
121123
import com.oracle.svm.hosted.code.InliningUtilities;
122124
import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
123125
import com.oracle.svm.hosted.code.UninterruptibleAnnotationChecker;
@@ -127,6 +129,7 @@
127129
import com.oracle.svm.hosted.meta.HostedUniverse;
128130
import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase;
129131
import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase;
132+
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisGraphDecoderImpl;
130133
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyImpl;
131134
import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils;
132135
import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor;
@@ -298,7 +301,7 @@ public void onTypeReachable(AnalysisType analysisType) {
298301
}
299302

300303
/* Decide when the type should be initialized. */
301-
classInitializationSupport.maybeInitializeHosted(analysisType);
304+
classInitializationSupport.maybeInitializeAtBuildTime(analysisType);
302305

303306
/*
304307
* For reachable classes, registering class's package in appropriate class loader.
@@ -328,10 +331,10 @@ public void onTypeReachable(AnalysisType analysisType) {
328331

329332
@Override
330333
public boolean isInitialized(AnalysisType type) {
331-
boolean shouldInitializeAtRuntime = classInitializationSupport.shouldInitializeAtRuntime(type);
332-
assert shouldInitializeAtRuntime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;
334+
boolean initializedAtBuildTime = classInitializationSupport.maybeInitializeAtBuildTime(type);
335+
assert !initializedAtBuildTime || type.getWrapped().isInitialized() : "Types that are not marked for runtime initializations must have been initialized: " + type;
333336

334-
return !shouldInitializeAtRuntime;
337+
return initializedAtBuildTime;
335338
}
336339

337340
private final boolean parseOnce = SubstrateOptions.parseOnce();
@@ -765,7 +768,7 @@ private InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiM
765768

766769
@Override
767770
public InlineBeforeAnalysisGraphDecoder createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) {
768-
return new InlineBeforeAnalysisGraphDecoder(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method), null);
771+
return new InlineBeforeAnalysisGraphDecoderImpl(bb, inlineBeforeAnalysisPolicy(method.getMultiMethodKey()), resultGraph, bb.getProviders(method));
769772
}
770773

771774
public static class Options {
@@ -956,4 +959,8 @@ public Function<AnalysisType, ResolvedJavaType> getStrengthenGraphsToTargetFunct
956959
}
957960
return super.getStrengthenGraphsToTargetFunction(key);
958961
}
962+
963+
public SimulateClassInitializerSupport createSimulateClassInitializerSupport(AnalysisMetaAccess aMetaAccess) {
964+
return new SimulateClassInitializerSupport(aMetaAccess, this);
965+
}
959966
}

0 commit comments

Comments
 (0)