Skip to content

Commit

Permalink
Review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Wimmer committed Jun 30, 2022
1 parent 7fa6385 commit c521f01
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.registerInvocationPlugins;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand Down Expand Up @@ -292,6 +293,7 @@
import com.oracle.svm.hosted.substitute.DeletedFieldsPlugin;
import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor;
import com.oracle.svm.util.AnnotationExtracter;
import com.oracle.svm.util.ClassUtil;
import com.oracle.svm.util.ImageBuildStatistics;
import com.oracle.svm.util.ReflectionUtil;
import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
Expand Down Expand Up @@ -1602,7 +1604,7 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP

for (Method method : loader.findAnnotatedMethods(CConstant.class)) {
if (LibCBase.isMethodProvidedInCurrentLibc(method)) {
classInitializationSupport.initializeAtBuildTime(method.getDeclaringClass(), "classes with " + CConstant.class.getSimpleName() + " annotations are always initialized");
initializeAtBuildTime(method.getDeclaringClass(), classInitializationSupport, CConstant.class);
nativeLibs.loadJavaMethod(metaAccess.lookupJavaMethod(method));
}
}
Expand All @@ -1613,38 +1615,38 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP
}
for (Class<?> clazz : loader.findAnnotatedClasses(CStruct.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CStruct.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, CStruct.class);
nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz));
}
}
for (Class<?> clazz : loader.findAnnotatedClasses(RawStructure.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + RawStructure.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, RawStructure.class);
nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz));
}
}
for (Class<?> clazz : loader.findAnnotatedClasses(CPointerTo.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CPointerTo.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, CPointerTo.class);
nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz));
}
}
for (Class<?> clazz : loader.findAnnotatedClasses(RawPointerTo.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + RawPointerTo.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, RawPointerTo.class);
nativeLibs.loadJavaType(metaAccess.lookupJavaType(clazz));
}
}
for (Class<?> clazz : loader.findAnnotatedClasses(CEnum.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CEnum.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, CEnum.class);
nativeLibs.loadJavaType(type);
}
}
for (Class<?> clazz : loader.findAnnotatedClasses(CContext.class, false)) {
if (LibCBase.isTypeProvidedInCurrentLibc(clazz)) {
classInitializationSupport.initializeAtBuildTime(clazz, "classes annotated with " + CContext.class.getSimpleName() + " are always initialized");
initializeAtBuildTime(clazz, classInitializationSupport, CContext.class);
}
}
nativeLibs.processCLibraryAnnotations(loader);
Expand All @@ -1653,6 +1655,12 @@ private void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessP
nativeLibs.reportErrors();
}

private static void initializeAtBuildTime(Class<?> clazz, ClassInitializationSupport classInitializationSupport, Class<? extends Annotation> annotationForMessage) {
String message = "classes annotated with " + ClassUtil.getUnqualifiedName(annotationForMessage) + " are always initialized at image build time";
classInitializationSupport.initializeAtBuildTime(clazz, message);
classInitializationSupport.forceInitializeHosted(clazz, message, false);
}

public AbstractImage getBuiltImage() {
return image;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.ImageClassLoader;

import jdk.internal.misc.Unsafe;
import jdk.vm.ci.meta.MetaAccessProvider;

class AllowAllHostedUsagesClassInitializationSupport extends ClassInitializationSupport {
Expand All @@ -43,23 +42,42 @@ class AllowAllHostedUsagesClassInitializationSupport extends ClassInitialization
super(metaAccess, loader);
}

@Override
public void initializeAtBuildTime(Class<?> aClass, String reason) {
UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis.");
Class<?> cur = aClass;
do {
classInitializationConfiguration.insert(cur.getTypeName(), InitKind.BUILD_TIME, cur == aClass ? reason : "super type of " + aClass.getTypeName(), true);
initializeInterfacesAtBuildTime(cur.getInterfaces(), "interface of " + aClass.getTypeName());
cur = cur.getSuperclass();
} while (cur != null);
}

private void initializeInterfacesAtBuildTime(Class<?>[] interfaces, String reason) {
for (Class<?> iface : interfaces) {
if (metaAccess.lookupJavaType(iface).declaresDefaultMethods()) {
classInitializationConfiguration.insert(iface.getTypeName(), InitKind.BUILD_TIME, reason, true);
}
initializeInterfacesAtBuildTime(iface.getInterfaces(), reason);
}
}

@Override
public void initializeAtRunTime(Class<?> clazz, String reason) {
UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis.");
classInitializationConfiguration.insert(clazz.getTypeName(), InitKind.RUN_TIME, reason, true);
setSubclassesAsRunTime(clazz);
}

@Override
public void rerunInitialization(Class<?> clazz, String reason) {
UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis.");
classInitializationConfiguration.insert(clazz.getTypeName(), InitKind.RERUN, reason, true);
/* There is no more difference between RUN_TIME and RERUN. */
initializeAtRunTime(clazz, reason);
}

try {
Unsafe.getUnsafe().ensureClassInitialized(clazz);
} catch (Throwable ex) {
throw UserError.abort(ex, "Class initialization failed for %s. The class is requested for re-running (reason: %s)", clazz.getTypeName(), reason);
}
@Override
public void rerunInitialization(String name, String reason) {
/* There is no more difference between RUN_TIME and RERUN. */
initializeAtRunTime(name, reason);
}

@Override
Expand All @@ -75,21 +93,6 @@ String reasonForClass(Class<?> clazz) {
}
}

private void setSubclassesAsRunTime(Class<?> clazz) {
if (clazz.isInterface() && !metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) {
/*
* An interface that does not declare a default method is independent from a class
* initialization point of view, i.e., it is not initialized when a class implementing
* that interface is initialized.
*/
return;
}
loader.findSubclasses(clazz, false).stream()
.filter(c -> !c.equals(clazz))
.filter(c -> !(c.isInterface() && !metaAccess.lookupJavaType(c).declaresDefaultMethods()))
.forEach(c -> classInitializationConfiguration.insert(c.getTypeName(), InitKind.RUN_TIME, "subtype of " + clazz.getTypeName(), true));
}

@Override
public void forceInitializeHosted(Class<?> clazz, String reason, boolean allowInitializationErrors) {
if (clazz == null) {
Expand Down Expand Up @@ -149,11 +152,6 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
return InitKind.BUILD_TIME;
}

if (clazz.getTypeName().contains("$$StringConcat")) {
forceInitializeHosted(clazz, "string concatenation classes are initialized at build time", false);
return InitKind.BUILD_TIME;
}

InitKind specifiedInitKind = specifiedInitKindFor(clazz);
InitKind clazzResult = specifiedInitKind != null ? specifiedInitKind : InitKind.RUN_TIME;

Expand All @@ -175,18 +173,10 @@ InitKind computeInitKindAndMaybeInitializeClass(Class<?> clazz, boolean memoize)
result = result.max(ensureClassInitialized(clazz, false));
}

/*
* Unfortunately, the computation of canInitializeWithoutSideEffects is not completely
* deterministic: Consider a class A whose class initializer depends on class B. Assume
* class B has no other dependencies and can therefore be initialized at build time.
* When class A is analyzed after class B has been initialized, it can also be
* initialized at build time. But when class A is analyzed before class B has been
* initialized, it cannot. Since two threads can analyze class A at the same time (there
* is no per-class locking) and another thread can initialize B at the same time, we can
* have a conflicting initialization status. In that case, BUILD_TIME must win over
* RUN_TIME because one thread has already initialized class A.
*/
result = classInitKinds.merge(clazz, result, InitKind::min);
InitKind previous = classInitKinds.putIfAbsent(clazz, result);
if (previous != null && previous != result) {
throw VMError.shouldNotReachHere("Conflicting class initialization kind: " + previous + " != " + result + " for " + clazz);
}
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,13 +318,6 @@ static String getTraceString(StackTraceElement[] trace) {
return b.toString();
}

@Override
public void initializeAtBuildTime(Class<?> aClass, String reason) {
UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis.");
classInitializationConfiguration.insert(aClass.getTypeName(), InitKind.BUILD_TIME, reason, true);
forceInitializeHosted(aClass, reason, false);
}

@Override
public void reportClassInitialized(Class<?> clazz, StackTraceElement[] stackTrace) {
assert TraceClassInitialization.hasBeenSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ public void rerunInitialization(Class<?> clazz, String reason) {
}
}

@Override
public void initializeAtBuildTime(Class<?> aClass, String reason) {
UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis.");
classInitializationConfiguration.insert(aClass.getTypeName(), InitKind.BUILD_TIME, reason, true);
forceInitializeHosted(aClass, reason, false);
}

private void setSubclassesAsRunTime(Class<?> clazz) {
if (clazz.isInterface() && !metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) {
/*
Expand Down

0 comments on commit c521f01

Please sign in to comment.