Skip to content

Commit a75a349

Browse files
committed
Initialization of runtime loaded classes.
1 parent e07a6f5 commit a75a349

File tree

6 files changed

+59
-17
lines changed

6 files changed

+59
-17
lines changed

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.oracle.svm.core.hub.DynamicHub;
4343
import com.oracle.svm.core.hub.PredefinedClassesSupport;
4444
import com.oracle.svm.core.hub.RuntimeClassLoading;
45+
import com.oracle.svm.core.hub.crema.CremaSupport;
4546
import com.oracle.svm.core.jdk.InternalVMMethod;
4647
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
4748
import com.oracle.svm.core.stack.StackOverflowCheck;
@@ -54,6 +55,7 @@
5455

5556
import jdk.graal.compiler.word.Word;
5657
import jdk.internal.reflect.Reflection;
58+
import jdk.vm.ci.meta.ResolvedJavaMethod;
5759

5860
/**
5961
* Information about the runtime class initialization state of a {@link DynamicHub class}, and
@@ -86,6 +88,12 @@ public final class ClassInitializationInfo {
8688
private static final ClassInitializationInfo FAILED_NO_CLINIT_NO_TRACKING = new ClassInitializationInfo(InitState.InitializationError, false, false);
8789
private static final ClassInitializationInfo FAILED_HAS_CLINIT_NO_TRACKING = new ClassInitializationInfo(InitState.InitializationError, true, false);
8890

91+
/**
92+
* Marks that a runtime-loaded class has a class initializer that should be executed in the
93+
* interpreter.
94+
*/
95+
private static final FunctionPointerHolder INTERPRETER_INITIALIZATION_MARKER = new FunctionPointerHolder(null);
96+
8997
/**
9098
* Function pointer to the class initializer that should be called at run-time. In some cases,
9199
* this may be an arbitrary helper method instead of the {@code <clinit>} of the class. This
@@ -188,12 +196,12 @@ private ClassInitializationInfo(CFunctionPointer runtimeClassInitializer, boolea
188196
}
189197

190198
/** For classes that are loaded at run-time. */
191-
private ClassInitializationInfo(boolean typeReachedTracked) {
199+
private ClassInitializationInfo(boolean typeReachedTracked, boolean hasClassInitializer) {
192200
assert RuntimeClassLoading.isSupported();
193201

194202
this.buildTimeInitialized = false;
195-
this.hasInitializer = true;
196-
this.runtimeClassInitializer = null;
203+
this.hasInitializer = hasClassInitializer;
204+
this.runtimeClassInitializer = hasClassInitializer ? INTERPRETER_INITIALIZATION_MARKER : null;
197205
this.slowPathRequired = true;
198206
this.initLock = new ReentrantLock();
199207
/* GR-59739: Needs a new state "Loaded". */
@@ -224,8 +232,8 @@ public static ClassInitializationInfo forRuntimeTimeInitializedClass(CFunctionPo
224232
return new ClassInitializationInfo(methodPointer, typeReachedTracked);
225233
}
226234

227-
public static ClassInitializationInfo forRuntimeLoadedClass(boolean typeReachedTracked) {
228-
return new ClassInitializationInfo(typeReachedTracked);
235+
public static ClassInitializationInfo forRuntimeLoadedClass(boolean typeReachedTracked, boolean hasClassInitializer) {
236+
return new ClassInitializationInfo(typeReachedTracked, hasClassInitializer);
229237
}
230238

231239
public boolean isBuildTimeInitialized() {
@@ -533,7 +541,7 @@ private void tryInitialize0(DynamicHub hub) {
533541
*/
534542
Throwable exception = null;
535543
try {
536-
invokeClassInitializer();
544+
invokeClassInitializer(hub);
537545
} catch (Throwable ex) {
538546
exception = ex;
539547
}
@@ -694,27 +702,35 @@ private void setInitializationStateAndNotify0(InitState state) {
694702
}
695703

696704
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-26+13/src/hotspot/share/oops/instanceKlass.cpp#L1675-L1715")
697-
private void invokeClassInitializer() {
705+
private void invokeClassInitializer(DynamicHub hub) {
698706
if (runtimeClassInitializer == null) {
699707
return;
700708
}
701709

702-
ClassInitializerFunctionPointer functionPointer = (ClassInitializerFunctionPointer) runtimeClassInitializer.functionPointer;
703-
VMError.guarantee(functionPointer.isNonNull());
704-
705710
/* Protect the yellow zone before executing arbitrary Java code. */
706711
if (Platform.includedIn(NATIVE_ONLY.class)) {
707712
StackOverflowCheck.singleton().protectYellowZone();
708713
}
709714
try {
710-
functionPointer.invoke();
715+
invokeClassInitializer0(hub);
711716
} finally {
712717
if (Platform.includedIn(NATIVE_ONLY.class)) {
713718
StackOverflowCheck.singleton().makeYellowZoneAvailable();
714719
}
715720
}
716721
}
717722

723+
private void invokeClassInitializer0(DynamicHub hub) {
724+
if (RuntimeClassLoading.isSupported() && runtimeClassInitializer == INTERPRETER_INITIALIZATION_MARKER) {
725+
ResolvedJavaMethod classInitializer = hub.getInterpreterType().getClassInitializer();
726+
CremaSupport.singleton().execute(classInitializer, new Object[0]);
727+
} else {
728+
ClassInitializerFunctionPointer functionPointer = (ClassInitializerFunctionPointer) runtimeClassInitializer.functionPointer;
729+
VMError.guarantee(functionPointer.isNonNull());
730+
functionPointer.invoke();
731+
}
732+
}
733+
718734
public enum InitState {
719735
/**
720736
* Successfully linked/verified (but not initialized yet). Linking happens during image

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,9 @@ public DynamicHub(Class<?> hostedJavaClass, String name, byte hubType, Reference
474474
@NeverInline("Fields of DynamicHub are immutable. Immutable reads could float above ANY_LOCATION writes.")
475475
public static DynamicHub allocate(String name, DynamicHub superHub, Object interfacesEncoding, DynamicHub componentHub, String sourceFileName,
476476
int modifiers, short flags, ClassLoader classLoader, String simpleBinaryName, Module module,
477-
Object declaringClass, String signature, int typeID, int interfaceID,
477+
Object declaringClass, String signature,
478+
int typeID, int interfaceID,
479+
boolean hasClassInitializer,
478480
short numClassTypes,
479481
short typeIDDepth,
480482
short numIterableInterfaceTypes,
@@ -508,7 +510,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
508510

509511
/* Always allow unsafe allocation for classes that were loaded at run-time. */
510512
companion.canUnsafeAllocate = true;
511-
companion.classInitializationInfo = ClassInitializationInfo.forRuntimeLoadedClass(false);
513+
companion.classInitializationInfo = ClassInitializationInfo.forRuntimeLoadedClass(false, hasClassInitializer);
512514

513515
assert !isFlagSet(flags, IS_PRIMITIVE_FLAG_BIT);
514516
boolean isInterface = isFlagSet(flags, IS_INTERFACE_FLAG_BIT);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/registry/AbstractRuntimeClassRegistry.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ private Class<?> createClass(ParserKlass parsed, ClassDefinitionInfo info, Symbo
404404

405405
DynamicHub hub = DynamicHub.allocate(externalName, superHub, interfacesEncoding, null,
406406
sourceFile, modifiers, flags, getClassLoader(), simpleBinaryName, module, enclosingClass, classSignature,
407-
typeID, interfaceID, numClassTypes, typeIDDepth, numIterableInterfaces, openTypeWorldTypeCheckSlots, openTypeWorldInterfaceHashTable, openTypeWorldInterfaceHashParam,
407+
typeID, interfaceID,
408+
hasClassInitializer(parsed), numClassTypes, typeIDDepth, numIterableInterfaces, openTypeWorldTypeCheckSlots, openTypeWorldInterfaceHashTable, openTypeWorldInterfaceHashParam,
408409
dispatchTableLength,
409410
dispatchTable.getDeclaredInstanceReferenceFieldOffsets(), afterFieldsOffset, isValueBased);
410411

@@ -430,6 +431,15 @@ private static void checkNotHybrid(ParserKlass parsed) {
430431

431432
}
432433

434+
private static boolean hasClassInitializer(ParserKlass parsed) {
435+
for (ParserMethod method : parsed.getMethods()) {
436+
if (method.getName() == ParserNames._clinit_) {
437+
return true;
438+
}
439+
}
440+
return false;
441+
}
442+
433443
private static boolean declaresDefaultMethods(ParserKlass parsed) {
434444
for (ParserMethod method : parsed.getMethods()) {
435445
int flags = method.getFlags();

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaResolvedObjectType.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.oracle.svm.espresso.classfile.descriptors.Type;
3636

3737
import jdk.vm.ci.meta.JavaType;
38+
import jdk.vm.ci.meta.ResolvedJavaMethod;
3839
import jdk.vm.ci.meta.ResolvedJavaType;
3940

4041
public final class CremaResolvedObjectType extends InterpreterResolvedObjectType implements CremaResolvedJavaType {
@@ -83,6 +84,16 @@ public CremaResolvedJavaMethod[] getDeclaredConstructors() {
8384
return result.toArray(new CremaResolvedJavaMethod[0]);
8485
}
8586

87+
@Override
88+
public ResolvedJavaMethod getClassInitializer() {
89+
for (InterpreterResolvedJavaMethod method : getDeclaredMethods(false)) {
90+
if (method.isClassInitializer()) {
91+
return method;
92+
}
93+
}
94+
return null;
95+
}
96+
8697
@Override
8798
public CremaResolvedJavaRecordComponent[] getRecordComponents() {
8899
// (GR-69095)

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.svm.espresso.classfile.ParserMethod;
4545
import com.oracle.svm.espresso.classfile.attributes.CodeAttribute;
4646
import com.oracle.svm.espresso.classfile.descriptors.Name;
47+
import com.oracle.svm.espresso.classfile.descriptors.ParserSymbols;
4748
import com.oracle.svm.espresso.classfile.descriptors.Signature;
4849
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
4950
import com.oracle.svm.espresso.shared.vtable.PartialMethod;
@@ -330,12 +331,12 @@ public final boolean isDeclared() {
330331

331332
@Override
332333
public final boolean isClassInitializer() {
333-
return "<clinit>".equals(getName()) && isStatic();
334+
return ParserSymbols.ParserNames._clinit_ == getSymbolicName() && isStatic();
334335
}
335336

336337
@Override
337338
public final boolean isConstructor() {
338-
return "<init>".equals(getName()) && !isStatic();
339+
return ParserSymbols.ParserNames._init_ == getSymbolicName() && !isStatic();
339340
}
340341

341342
@Override

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,9 @@ public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
304304
}
305305

306306
@Override
307-
public final ResolvedJavaMethod getClassInitializer() {
307+
public ResolvedJavaMethod getClassInitializer() {
308+
// We currently do not expect this to be called for any other type than
309+
// CremaResolvedObjectType.
308310
throw VMError.intentionallyUnimplemented();
309311
}
310312

0 commit comments

Comments
 (0)