Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ public Decoder(ClassLoader loader) {
this.loader = loader;
}

Class<?> loadClass(String className) {
public Class<?> loadClass(String className) {
try {
return Class.forName(className, false, loader);
} catch (ClassNotFoundException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,13 @@ public void registerTypeForBaseImage(Class<?> cls) {
}
}

@Override
public void registerMethodForBaseImage(AnalysisMethod method) {
if (classInclusionPolicy.isMethodIncluded(method)) {
classInclusionPolicy.includeMethod(method);
}
}

public static <T, U> U getOrDefault(T cls, Function<T, U> getMembers, U backup) {
try {
return getMembers.apply(cls);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,9 @@ default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType,
default void registerTypeForBaseImage(Class<?> cls) {

}

@SuppressWarnings("unused")
default void registerMethodForBaseImage(AnalysisMethod method) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@ public boolean isClassIncluded(Class<?> cls) {
* Determine if the given method needs to be included in the image according to the policy.
*/
public boolean isMethodIncluded(Executable method) {
return isMethodIncluded(bb.getMetaAccess().lookupJavaMethod(method));
}

public boolean isMethodIncluded(AnalysisMethod method) {
/*
* Methods annotated with @Fold should not be included in the base image as they must be
* inlined. An extension image would inline the method as well and would not use the method
* from the base image.
*/
return !AnnotationAccess.isAnnotationPresent(bb.getMetaAccess().lookupJavaMethod(method), Fold.class);
return !AnnotationAccess.isAnnotationPresent(method, Fold.class);
}

/**
Expand Down Expand Up @@ -105,6 +109,11 @@ public void includeClass(Class<?> cls) {
*/
public abstract void includeMethod(Executable method);

/**
* Includes the given method in the image.
*/
public abstract void includeMethod(AnalysisMethod method);

/**
* Includes the given field in the image.
*/
Expand Down Expand Up @@ -151,23 +160,35 @@ public boolean isMethodIncluded(Executable method) {
@Override
public void includeMethod(Executable method) {
bb.postTask(debug -> {
/*
* Non-abstract methods from an abstract class or default methods from an interface
* are not registered as implementation invoked by the analysis because their
* declaring class cannot be marked as instantiated and AnalysisType.getTypeFlow
* only includes instantiated types (see TypeFlow.addObserver). For now, to ensure
* those methods are included in the image, they are manually registered as
* implementation invoked.
*/
Class<?> declaringClass = method.getDeclaringClass();
if (!Modifier.isAbstract(method.getModifiers()) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) {
AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method);
analysisMethod.registerAsDirectRootMethod(reason);
analysisMethod.registerAsImplementationInvoked(reason);
}
AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method);
registerMethod(method.getModifiers(), declaringClass, analysisMethod);
bb.forcedAddRootMethod(analysisMethod, false, reason);
});
}

@Override
public void includeMethod(AnalysisMethod method) {
bb.postTask(debug -> {
Class<?> declaringClass = method.getDeclaringClass().getJavaClass();
registerMethod(method.getModifiers(), declaringClass, method);
bb.forcedAddRootMethod(method, false, reason);
});
}

private void registerMethod(int methodModifiers, Class<?> declaringClass, AnalysisMethod analysisMethod) {
/*
* Non-abstract methods from an abstract class or default methods from an interface are
* not registered as implementation invoked by the analysis because their declaring
* class cannot be marked as instantiated and AnalysisType.getTypeFlow only includes
* instantiated types (see TypeFlow.addObserver). For now, to ensure those methods are
* included in the image, they are manually registered as implementation invoked.
*/
if (!Modifier.isAbstract(methodModifiers) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) {
analysisMethod.registerAsDirectRootMethod(reason);
analysisMethod.registerAsImplementationInvoked(reason);
}
}
}

/**
Expand All @@ -184,6 +205,11 @@ public DefaultAllInclusionPolicy(Object reason) {
public void includeMethod(Executable method) {
bb.postTask(debug -> bb.addRootMethod(method, false, reason));
}

@Override
public void includeMethod(AnalysisMethod method) {
bb.postTask(debug -> bb.addRootMethod(method, false, reason));
}
}

protected boolean isAccessible(Member member) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,9 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob
}

@Override
public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) {
public AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) {
AnalysisError.guarantee(isBaseLayerAnalysisEnabled());
PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(metaAccess.lookupJavaMethod(method));
PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(method);
postTask(ignore -> {
MethodTypeFlow typeFlow = analysisMethod.getTypeFlow();
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public interface ReachabilityAnalysis {
* @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean, Object,
* MultiMethod.MultiMethodKey...)
*/
AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots);
AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots);

/**
* Waits until the analysis is done.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,11 @@ public class ImageLayerLoader {
protected final Map<Integer, ImageHeapConstant> constants = new ConcurrentHashMap<>();
private final List<Path> loadPaths;
private final Map<Integer, BaseLayerType> baseLayerTypes = new ConcurrentHashMap<>();
private final Map<Integer, Integer> typeToHubIdentityHashCode = new HashMap<>();
private final Map<Integer, Integer> typeToHubIdentityHashCode = new ConcurrentHashMap<>();
private final Map<Integer, BaseLayerMethod> baseLayerMethods = new ConcurrentHashMap<>();

/** Map from the type id to its identifier in the jsonMap. */
private final Map<Integer, String> typeIdToIdentifier = new HashMap<>();
protected final Map<Integer, String> typeIdToIdentifier = new HashMap<>();

/** Map from the method id to its identifier in the jsonMap. */
private final Map<Integer, String> methodIdToIdentifier = new HashMap<>();
Expand Down Expand Up @@ -348,6 +348,10 @@ public List<Path> getLoadPaths() {
return loadPaths;
}

public AnalysisUniverse getUniverse() {
return universe;
}

public void setUniverse(AnalysisUniverse newUniverse) {
this.universe = newUniverse;
}
Expand Down Expand Up @@ -449,6 +453,10 @@ protected void prepareConstantRelinking(EconomicMap<String, Object> constantData
private void loadType(EconomicMap<String, Object> typeData) {
int tid = get(typeData, ID_TAG);

if (imageLayerLoaderHelper.loadType(typeData, tid)) {
return;
}

String name = get(typeData, CLASS_JAVA_NAME_TAG);
Class<?> clazz = lookupBaseLayerTypeInHostVM(name);

Expand Down Expand Up @@ -581,7 +589,7 @@ public void initializeBaseLayerType(AnalysisType type) {
* Tries to look up the base layer type in the current VM. Some types cannot be looked up by
* name (for example $$Lambda types), so this method can return null.
*/
public static Class<?> lookupBaseLayerTypeInHostVM(String type) {
public Class<?> lookupBaseLayerTypeInHostVM(String type) {
int arrayType = 0;
String componentType = type;
/*
Expand All @@ -594,7 +602,7 @@ public static Class<?> lookupBaseLayerTypeInHostVM(String type) {
}
Class<?> clazz = lookupPrimitiveClass(componentType);
if (clazz == null) {
clazz = ReflectionUtil.lookupClass(true, componentType);
clazz = lookupClass(true, componentType);
}
if (clazz == null) {
return null;
Expand Down Expand Up @@ -637,7 +645,7 @@ private void loadMethod(EconomicMap<String, Object> methodData) {
Executable method = null;
Class<?> clazz = lookupBaseLayerTypeInHostVM(className);
if (clazz != null) {
Class<?>[] argumentClasses = arguments.stream().map(ImageLayerLoader::lookupBaseLayerTypeInHostVM).toList().toArray(new Class<?>[0]);
Class<?>[] argumentClasses = arguments.stream().map(this::lookupBaseLayerTypeInHostVM).toList().toArray(new Class<?>[0]);
method = lookupMethodByReflection(name, clazz, argumentClasses);
}

Expand Down Expand Up @@ -680,13 +688,17 @@ private void loadMethod(EconomicMap<String, Object> methodData) {
}

private static Executable lookupMethodByReflection(String name, Class<?> clazz, Class<?>[] argumentClasses) {
Executable method;
if (name.equals(CONSTRUCTOR_NAME)) {
method = ReflectionUtil.lookupConstructor(true, clazz, argumentClasses);
} else {
method = ReflectionUtil.lookupMethod(true, clazz, name, argumentClasses);
try {
Executable method;
if (name.equals(CONSTRUCTOR_NAME)) {
method = ReflectionUtil.lookupConstructor(true, clazz, argumentClasses);
} else {
method = ReflectionUtil.lookupMethod(true, clazz, name, argumentClasses);
}
return method;
} catch (NoClassDefFoundError e) {
return null;
}
return method;
}

private void createBaseLayerMethod(EconomicMap<String, Object> methodData, int mid, String name) {
Expand Down Expand Up @@ -1277,14 +1289,18 @@ private EconomicMap<String, Object> getElementData(String registry, String eleme
}

@SuppressWarnings("unchecked")
protected static Enum<?> getEnumValue(EconomicMap<String, Object> enumData) {
protected Enum<?> getEnumValue(EconomicMap<String, Object> enumData) {
String className = get(enumData, ENUM_CLASS_TAG);
Class<?> enumClass = ReflectionUtil.lookupClass(false, className);
Class<?> enumClass = lookupClass(false, className);
String name = get(enumData, ENUM_NAME_TAG);
/* asSubclass produces an "unchecked" warning */
return Enum.valueOf(enumClass.asSubclass(Enum.class), name);
}

public Class<?> lookupClass(boolean optional, String className) {
return ReflectionUtil.lookupClass(optional, className);
}

public static <T> T get(EconomicMap<String, Object> innerMap, String elementIdentifier) {
return cast(innerMap.get(elementIdentifier));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public ImageLayerLoaderHelper(ImageLayerLoader imageLayerLoader) {
this.imageLayerLoader = imageLayerLoader;
}

@SuppressWarnings("unused")
protected boolean loadType(EconomicMap<String, Object> typeData, int tid) {
return false;
}

@SuppressWarnings("unused")
protected boolean loadMethod(EconomicMap<String, Object> methodData, int mid) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ public class ImageLayerSnapshotUtil {
public static final String COMPONENT_TYPE_TAG = "component type";
public static final String SUPER_CLASS_TAG = "super class";
public static final String INTERFACES_TAG = "interfaces";
public static final String WRAPPED_TYPE_TAG = "wrapped type";
public static final String GENERATED_SERIALIZATION_TAG = "generated serialization";
public static final String RAW_DECLARING_CLASS_TAG = "raw declaring class";
public static final String RAW_TARGET_CONSTRUCTOR_CLASS_TAG = "raw target constructor class";
public static final String CONSTANTS_TAG = "constants";
public static final String CONSTANTS_TO_RELINK_TAG = "constants to relink";
public static final String TID_TAG = "tid";
Expand All @@ -110,7 +114,7 @@ public class ImageLayerSnapshotUtil {
public static final String ARGUMENT_IDS_TAG = "argument ids";
public static final String RETURN_TYPE_TAG = "return type";
public static final String IS_VAR_ARGS_TAG = "is varArg";
public static final String METHOD_TYPE_TAG = "method type";
public static final String WRAPPED_METHOD_TAG = "wrapped method";
public static final String METHOD_TYPE_PARAMETERS_TAG = "method type parameters";
public static final String METHOD_TYPE_RETURN_TAG = "method type return";
public static final String FACTORY_TAG = "factory";
Expand All @@ -120,6 +124,16 @@ public class ImageLayerSnapshotUtil {
public static final String IDENTITY_HASH_CODE_TAG = "identityHashCode";
public static final String HUB_IDENTITY_HASH_CODE_TAG = "hub identityHashCode";
public static final String IS_INITIALIZED_AT_BUILD_TIME_TAG = "is initialized at build time";
public static final String IS_NO_INITIALIZER_NO_TRACKING_TAG = "in no initializer no tracking";
public static final String IS_INITIALIZED_NO_TRACKING_TAG = "is initialized no tracking";
public static final String IS_FAILED_NO_TRACKING_TAG = "is failed no tracking";
public static final String INFO_IS_INITIALIZED_TAG = "info is initialized";
public static final String INFO_IS_IN_ERROR_STATE_TAG = "info is in error state";
public static final String INFO_IS_LINKED_TAG = "info is linked";
public static final String INFO_HAS_INITIALIZER_TAG = "info has initializer";
public static final String INFO_IS_BUILD_TIME_INITIALIZED_TAG = "info is build time initialized";
public static final String INFO_IS_TRACKED_TAG = "info is tracked";
public static final String INFO_CLASS_INITIALIZER_TAG = "info class initializer";
public static final String ID_TAG = "id";
public static final String ANALYSIS_PARSED_GRAPH_TAG = "analysis parsed graph";
public static final String STRENGTHENED_GRAPH_TAG = "strengthened graph";
Expand Down Expand Up @@ -234,9 +248,12 @@ public GraphEncoder(List<Field> externalValues, ImageLayerWriter imageLayerWrite
}

public static class GraphDecoder extends ObjectCopier.Decoder {
private final ImageLayerLoader imageLayerLoader;

@SuppressWarnings("this-escape")
public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) {
super(classLoader);
this.imageLayerLoader = imageLayerLoader;
addBuiltin(new NodeClassBuiltIn());
addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader));
addBuiltin(new AnalysisTypeBuiltIn(null, imageLayerLoader));
Expand All @@ -245,6 +262,11 @@ public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader,
addBuiltin(new FieldLocationIdentityBuiltIn(null, imageLayerLoader));
addBuiltin(new NamedLocationIdentityArrayBuiltIn());
}

@Override
public Class<?> loadClass(String className) {
return imageLayerLoader.lookupClass(false, className);
}
}

public static class NodeClassBuiltIn extends ObjectCopier.Builtin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ protected void persistType(AnalysisType type, EconomicMap<String, Object> typeMa
typeMap.put(IS_INSTANTIATED, type.isInstantiated());
typeMap.put(IS_UNSAFE_ALLOCATED, type.isUnsafeAllocated());
typeMap.put(IS_REACHABLE, type.isReachable());

imageLayerWriterHelper.persistType(type, typeMap);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.graalvm.collections.EconomicMap;

import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.graal.pointsto.meta.AnalysisType;

public class ImageLayerWriterHelper {
protected final ImageLayerWriter imageLayerWriter;
Expand All @@ -35,6 +36,11 @@ public ImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) {
this.imageLayerWriter = imageLayerWriter;
}

@SuppressWarnings("unused")
protected void persistType(AnalysisType type, EconomicMap<String, Object> typeMap) {
/* No additional information to persist */
}

@SuppressWarnings("unused")
protected void persistMethod(AnalysisMethod method, EconomicMap<String, Object> methodMap) {
/* No additional information to persist */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob
}

@Override
public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) {
public AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) {
return addRootMethod(method, invokeSpecial, reason, otherRoots);
}

Expand Down
Loading