Skip to content

[WIP] [GR-62047] Trace all dynamic accesses from native image. #11081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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 @@ -30,6 +30,7 @@
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.EXTREMELY_FAST_PATH_PROBABILITY;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
import static jdk.graal.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;

Expand Down Expand Up @@ -59,6 +60,7 @@
import com.oracle.svm.core.hub.RuntimeClassLoading;
import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport;
import com.oracle.svm.core.meta.SharedType;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.option.HostedOptionValues;
import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
import com.oracle.svm.core.snippets.SnippetRuntime;
Expand Down Expand Up @@ -126,8 +128,11 @@ public class SubstrateAllocationSnippets extends AllocationSnippets {
private static final SubstrateForeignCallDescriptor NEW_MULTI_ARRAY = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "newMultiArrayStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class,
"slowPathHubOrUnsafeInstantiationError", NO_SIDE_EFFECT);

private static final SubstrateForeignCallDescriptor TRACE_ARRAY_HUB = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "traceArrayHubStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor ARRAY_HUB_ERROR = SnippetRuntime.findForeignCall(SubstrateAllocationSnippets.class, "arrayHubErrorStub", NO_SIDE_EFFECT);
private static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{NEW_MULTI_ARRAY, SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR, ARRAY_HUB_ERROR};
private static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{NEW_MULTI_ARRAY, SLOW_PATH_HUB_OR_UNSAFE_INSTANTIATE_ERROR, TRACE_ARRAY_HUB,
ARRAY_HUB_ERROR};

public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) {
foreignCalls.register(FOREIGN_CALLS);
Expand Down Expand Up @@ -365,6 +370,12 @@ private static DynamicHub getCheckedArrayHub(DynamicHub elementType) {
if (probability(EXTREMELY_FAST_PATH_PROBABILITY, arrayHub != null)) {
DynamicHub nonNullArrayHub = (DynamicHub) PiNode.piCastNonNull(arrayHub, SnippetAnchorNode.anchor());
if (probability(EXTREMELY_FAST_PATH_PROBABILITY, nonNullArrayHub.isInstantiated())) {
if (MetadataTracer.Options.MetadataTracingSupport.getValue()) {
Class<?> clazz = DynamicHub.toClass(elementType);
if (!clazz.isPrimitive()) {
callTraceArrayHubStub(TRACE_ARRAY_HUB, clazz);
}
}
return nonNullArrayHub;
}
}
Expand All @@ -374,6 +385,18 @@ private static DynamicHub getCheckedArrayHub(DynamicHub elementType) {
throw UnreachableNode.unreachable();
}

@NodeIntrinsic(value = ForeignCallNode.class)
private static native void callTraceArrayHubStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);

/** Foreign call: {@link #TRACE_ARRAY_HUB}. */
@SubstrateForeignCallTarget(stubCallingConvention = true)
private static void traceArrayHubStub(DynamicHub elementType) {
assert MetadataTracer.Options.MetadataTracingSupport.getValue();
if (probability(SLOW_PATH_PROBABILITY, MetadataTracer.singleton().enabled())) {
MetadataTracer.singleton().traceReflectionType(elementType.getName());
}
}

@NodeIntrinsic(value = ForeignCallNode.class)
private static native void callArrayHubErrorStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;
Expand Down Expand Up @@ -231,6 +232,9 @@ private static Class<?> forName(String className, ClassLoader classLoader, boole

private Object forName0(String className, ClassLoader classLoader) {
var conditional = knownClasses.get(className);
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && conditional != null && MetadataTracer.singleton().enabled()) {
MetadataTracer.singleton().traceReflectionType(className);
}
Object result = conditional == null ? null : conditional.getValue();
if (result == NEGATIVE_QUERY || className.endsWith("[]")) {
/* Querying array classes with their "TypeName[]" name always throws */
Expand Down Expand Up @@ -276,7 +280,13 @@ public static boolean canUnsafeInstantiateAsInstance(DynamicHub hub) {
break;
}
}
return conditionSet != null && conditionSet.satisfied();
if (conditionSet != null) {
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
MetadataTracer.singleton().traceReflectionType(clazz.getName()).setUnsafeAllocated();
}
return conditionSet.satisfied();
}
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
*/
package com.oracle.svm.core.hub;

import static com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberAccessibility;
import static com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberDeclaration;
import static com.oracle.svm.core.MissingRegistrationUtils.throwMissingRegistrationErrors;
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
import static com.oracle.svm.core.annotate.TargetElement.CONSTRUCTOR_NAME;
Expand Down Expand Up @@ -86,6 +88,7 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CFunctionPointer;

import com.oracle.svm.configure.config.ConfigurationType;
import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse;
import com.oracle.svm.core.BuildPhaseProvider.CompileQueueFinished;
import com.oracle.svm.core.NeverInline;
Expand Down Expand Up @@ -116,6 +119,7 @@
import com.oracle.svm.core.jdk.ProtectionDomainSupport;
import com.oracle.svm.core.jdk.Resources;
import com.oracle.svm.core.meta.SharedType;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils;
import com.oracle.svm.core.reflect.RuntimeMetadataDecoder;
import com.oracle.svm.core.reflect.RuntimeMetadataDecoder.ConstructorDescriptor;
Expand Down Expand Up @@ -143,6 +147,7 @@
import jdk.internal.reflect.FieldAccessor;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
import jdk.vm.ci.meta.MetaUtil;
import jdk.vm.ci.meta.ResolvedJavaType;
import sun.reflect.annotation.AnnotationType;
import sun.reflect.generics.factory.GenericsFactory;
Expand Down Expand Up @@ -694,6 +699,9 @@ private ReflectionMetadata reflectionMetadata() {
}

private void checkClassFlag(int mask, String methodName) {
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
traceClassFlagQuery(mask);
}
if (throwMissingRegistrationErrors() && !(isClassFlagSet(mask) && getConditions().satisfied())) {
MissingReflectionRegistrationUtils.forBulkQuery(DynamicHub.toClass(this), methodName);
}
Expand All @@ -703,6 +711,25 @@ private boolean isClassFlagSet(int mask) {
return (reflectionMetadata() != null && (reflectionMetadata().classFlags & mask) != 0);
}

private void traceClassFlagQuery(int mask) {
ConfigurationType type = MetadataTracer.singleton().traceReflectionType(getName());
switch (mask) {
case ALL_FIELDS_FLAG -> type.setAllPublicFields(ConfigurationMemberAccessibility.ACCESSED);
case ALL_DECLARED_FIELDS_FLAG -> type.setAllDeclaredFields(ConfigurationMemberAccessibility.ACCESSED);
case ALL_METHODS_FLAG -> type.setAllPublicMethods(ConfigurationMemberAccessibility.QUERIED);
case ALL_DECLARED_METHODS_FLAG -> type.setAllDeclaredMethods(ConfigurationMemberAccessibility.QUERIED);
case ALL_CONSTRUCTORS_FLAG -> type.setAllPublicConstructors(ConfigurationMemberAccessibility.QUERIED);
case ALL_DECLARED_CONSTRUCTORS_FLAG -> type.setAllDeclaredConstructors(ConfigurationMemberAccessibility.QUERIED);
case ALL_CLASSES_FLAG -> type.setAllPublicClasses();
case ALL_DECLARED_CLASSES_FLAG -> type.setAllDeclaredClasses();
case ALL_RECORD_COMPONENTS_FLAG -> type.setAllRecordComponents();
case ALL_PERMITTED_SUBCLASSES_FLAG -> type.setAllPermittedSubclasses();
case ALL_NEST_MEMBERS_FLAG -> type.setAllNestMembers();
case ALL_SIGNERS_FLAG -> type.setAllSigners();
default -> throw VMError.shouldNotReachHere("unknown class flag " + mask);
}
}

/** Executed at runtime. */
private static Object initEnumConstantsAtRuntime(Method values) {
try {
Expand Down Expand Up @@ -1261,6 +1288,14 @@ private void checkField(String fieldName, Field field, boolean publicOnly) throw
*/
throw new NoSuchFieldException(fieldName);
} else {
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
ConfigurationMemberDeclaration declaration = publicOnly ? ConfigurationMemberDeclaration.PRESENT : ConfigurationMemberDeclaration.DECLARED;
// register declaring type and field
ConfigurationType declaringType = MetadataTracer.singleton().traceReflectionType(field.getDeclaringClass().getName());
declaringType.addField(fieldName, declaration, false);
// register receiver type
MetadataTracer.singleton().traceReflectionType(getName());
}
RuntimeMetadataDecoder decoder = ImageSingletons.lookup(RuntimeMetadataDecoder.class);
int fieldModifiers = field.getModifiers();
boolean negative = decoder.isNegative(fieldModifiers);
Expand Down Expand Up @@ -1328,13 +1363,31 @@ private boolean checkExecutableExists(String methodName, Class<?>[] parameterTyp
int methodModifiers = method.getModifiers();
boolean negative = decoder.isNegative(methodModifiers);
boolean hiding = decoder.isHiding(methodModifiers);
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
ConfigurationMemberDeclaration declaration = publicOnly ? ConfigurationMemberDeclaration.PRESENT : ConfigurationMemberDeclaration.DECLARED;
// register declaring type and method
ConfigurationType declaringType = MetadataTracer.singleton().traceReflectionType(method.getDeclaringClass().getName());
declaringType.addMethod(methodName, toInternalSignature(parameterTypes), declaration);
// register receiver type
MetadataTracer.singleton().traceReflectionType(getName());
}
if (throwMissingErrors && hiding) {
MissingReflectionRegistrationUtils.forMethod(clazz, methodName, parameterTypes);
}
return !(negative || hiding);
}
}

private static String toInternalSignature(Class<?>[] classes) {
StringBuilder sb = new StringBuilder("(");
if (classes != null) {
for (Class<?> clazz : classes) {
sb.append(MetaUtil.toInternalName(clazz.getName()));
}
}
return sb.append(')').toString();
}

private boolean allElementsRegistered(boolean publicOnly, int allDeclaredElementsFlag, int allPublicElementsFlag) {
return isClassFlagSet(allDeclaredElementsFlag) || (publicOnly && isClassFlagSet(allPublicElementsFlag));
}
Expand Down Expand Up @@ -1824,6 +1877,8 @@ public DynamicHub arrayType() {
}
if (companion.arrayHub == null) {
MissingReflectionRegistrationUtils.forClass(getTypeName() + "[]");
} else if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled() && !isPrimitive()) {
MetadataTracer.singleton().traceReflectionType(companion.arrayHub.getTypeName());
}
return companion.arrayHub;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import jdk.graal.compiler.java.LambdaUtils;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
Expand All @@ -45,8 +43,11 @@
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.fieldvaluetransformer.NewInstanceFieldValueTransformer;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.reflect.serialize.MissingSerializationRegistrationUtils;

import jdk.graal.compiler.java.LambdaUtils;

@TargetClass(java.io.FileDescriptor.class)
final class Target_java_io_FileDescriptor {

Expand All @@ -68,8 +69,8 @@ static ObjectStreamClass lookup(Class<?> cl, boolean all) {
return null;
}

if (Serializable.class.isAssignableFrom(cl)) {
if (!cl.isArray() && !DynamicHub.fromClass(cl).isRegisteredForSerialization()) {
if (Serializable.class.isAssignableFrom(cl) && !cl.isArray()) {
if (!DynamicHub.fromClass(cl).isRegisteredForSerialization()) {
boolean isLambda = cl.getTypeName().contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING);
boolean isProxy = Proxy.isProxyClass(cl);
if (isProxy || isLambda) {
Expand All @@ -87,6 +88,9 @@ static ObjectStreamClass lookup(Class<?> cl, boolean all) {
MissingSerializationRegistrationUtils.missingSerializationRegistration(cl, "type " + cl.getTypeName());
}
}
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
MetadataTracer.singleton().traceSerializationType(cl.getName());
}
}

return Target_java_io_ObjectStreamClass_Caches.localDescs0.get(cl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.GlobUtils;
Expand Down Expand Up @@ -385,6 +386,7 @@ public static ResourceStorageEntryBase getAtRuntime(Module module, String resour
return null;
}
}
traceResourceAccess(resourceName, moduleName);
if (!entry.getConditions().satisfied()) {
return missingMetadata(resourceName, throwOnMissing);
}
Expand Down Expand Up @@ -414,6 +416,12 @@ public static ResourceStorageEntryBase getAtRuntime(Module module, String resour
return unconditionalEntry;
}

private static void traceResourceAccess(String resourceName, String moduleName) {
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
MetadataTracer.singleton().traceResource(resourceName, moduleName);
}
}

private static ConditionalRuntimeValue<ResourceStorageEntryBase> getEntry(Module module, String canonicalResourceName) {
for (var r : layeredSingletons()) {
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = r.resources.get(createStorageKey(module, canonicalResourceName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.configure.RuntimeConditionSet;
import com.oracle.svm.core.jdk.Resources;
import com.oracle.svm.core.metadata.MetadataTracer;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;
Expand Down Expand Up @@ -293,6 +294,12 @@ public boolean isRegisteredBundleLookup(String baseName, Locale locale, Object c
/* Those cases will throw a NullPointerException before any lookup */
return true;
}
return registeredBundles.containsKey(baseName) && registeredBundles.get(baseName).satisfied();
if (registeredBundles.containsKey(baseName)) {
if (MetadataTracer.Options.MetadataTracingSupport.getValue() && MetadataTracer.singleton().enabled()) {
MetadataTracer.singleton().traceResourceBundle(baseName, locale);
}
return registeredBundles.get(baseName).satisfied();
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,19 @@ public boolean isClassInitializer() {
return WRAPPED_CSTRING_EQUIVALENCE.equals(name, INITIALIZER_NAME);
}

/**
* Returns the method name as a String. Can be used if the descriptor is known to be a String
* (i.e., it does not come from a JNI call); otherwise, use {@link #getNameConvertToString()}.
*/
public String getName() {
return (String) name;
}

/**
* Returns the method signature as a String. Can be used if the descriptor is known to be a
* String (i.e., it does not come from a JNI call); otherwise, use
* {@link #getSignatureConvertToString()}.
*/
public String getSignature() {
return (String) signature;
}
Expand All @@ -113,6 +122,13 @@ public String getNameConvertToString() {
return name.toString();
}

/**
* Performs a potentially costly conversion to string, only for slow paths.
*/
public String getSignatureConvertToString() {
return signature.toString();
}

public String getSignatureWithoutReturnType() {
String signatureString = signature.toString();
int parametersEnd = signatureString.lastIndexOf(')');
Expand Down
Loading