package com.oracle.svm.hosted;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.jdk.JavaLangSubstitutions.ClassValueSupport;
import com.oracle.svm.util.ReflectionUtil;
@AutomaticFeature
public final class ClassValueFeature implements Feature {
private final Map<ClassValue<?>, Map<Class<?>, Object>> values = new ConcurrentHashMap<>();
@Override
public void afterRegistration(AfterRegistrationAccess access) {
ClassValueSupport support = new ClassValueSupport(values);
ImageSingletons.add(ClassValueSupport.class, support);
}
@Override
public void duringSetup(DuringSetupAccess access) {
access.registerObjectReplacer(this::processObject);
}
private Object processObject(Object obj) {
if (obj instanceof ClassValue) {
values.putIfAbsent((ClassValue<?>) obj, new ConcurrentHashMap<>());
}
return obj;
}
@Override
public void duringAnalysis(DuringAnalysisAccess access) {
FeatureImpl.DuringAnalysisAccessImpl impl = (FeatureImpl.DuringAnalysisAccessImpl) access;
List<AnalysisType> types = impl.getUniverse().getTypes();
for (AnalysisType t : types) {
if (!t.isReachable()) {
continue;
}
Class<?> clazz = t.getJavaClass();
for (Map.Entry<ClassValue<?>, Map<Class<?>, Object>> e : values.entrySet()) {
ClassValue<?> v = e.getKey();
Map<Class<?>, Object> m = e.getValue();
if (!m.containsKey(clazz) && hasValue(v, clazz)) {
Object value = v.get(clazz);
if (value == null) {
value = ClassValueSupport.NULL_MARKER;
}
m.put(clazz, value);
access.requireAnalysisIteration();
}
}
}
}
private static final java.lang.reflect.Field IDENTITY = ReflectionUtil.lookupField(ClassValue.class, "identity");
private static final java.lang.reflect.Field CLASS_VALUE_MAP = ReflectionUtil.lookupField(Class.class, "classValueMap");
private static boolean hasValue(ClassValue<?> v, Class<?> c) {
try {
Map<?, ?> map = (Map<?, ?>) CLASS_VALUE_MAP.get(c);
final Object id = IDENTITY.get(v);
final boolean res = map != null && map.containsKey(id);
return res;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}