Skip to content

Commit 0042c73

Browse files
Add agent support for getPermittedSubclasses
Add minimum java spec check to the agent
1 parent 6c255dc commit 0042c73

File tree

8 files changed

+68
-9
lines changed

8 files changed

+68
-9
lines changed

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ private static boolean getDeclaredClasses(JNIEnvironment jni, Breakpoint bp, Int
255255
return handleGetClasses(jni, bp, state);
256256
}
257257

258+
private static boolean getPermittedSubclasses(JNIEnvironment jni, Breakpoint bp, InterceptedState state) {
259+
return handleGetClasses(jni, bp, state);
260+
}
261+
258262
private static boolean handleGetClasses(JNIEnvironment jni, Breakpoint bp, InterceptedState state) {
259263
JNIObjectHandle callerClass = state.getDirectCallerClass();
260264
JNIObjectHandle self = getObjectArgument(0);
@@ -1295,6 +1299,9 @@ public static void onVMInit(JvmtiEnv jvmti, JNIEnvironment jni) {
12951299
System.arraycopy(REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS, 0, breakpointSpecifications, BREAKPOINT_SPECIFICATIONS.length, REFLECTION_QUERIES_BREAKPOINT_SPECIFICATIONS.length);
12961300
}
12971301
for (BreakpointSpecification br : breakpointSpecifications) {
1302+
if (br == null) {
1303+
continue;
1304+
}
12981305
JNIObjectHandle clazz = nullHandle();
12991306
if (lastClassName != null && lastClassName.equals(br.className)) {
13001307
clazz = lastClass;
@@ -1421,6 +1428,8 @@ private interface BreakpointHandler {
14211428
brk("java/lang/Class", "getDeclaredFields", "()[Ljava/lang/reflect/Field;", BreakpointInterceptor::getDeclaredFields),
14221429
brk("java/lang/Class", "getDeclaredClasses", "()[Ljava/lang/Class;", BreakpointInterceptor::getDeclaredClasses),
14231430

1431+
brk("java/lang/Class", "getPermittedSubclasses", "()[Ljava/lang/Class;", BreakpointInterceptor::getPermittedSubclasses, 17),
1432+
14241433
brk("java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", BreakpointInterceptor::getField),
14251434
brk("java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", BreakpointInterceptor::getDeclaredField),
14261435

@@ -1538,6 +1547,15 @@ private interface BreakpointHandler {
15381547
brk("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", BreakpointInterceptor::getConstructor),
15391548
};
15401549

1550+
private static BreakpointSpecification brk(String className, String methodName, String signature, BreakpointHandler handler, double minimumJavaSpec) {
1551+
double version = Double.parseDouble(System.getProperty("java.specification.version"));
1552+
if (version >= minimumJavaSpec) {
1553+
return new BreakpointSpecification(className, methodName, signature, handler, false);
1554+
} else {
1555+
return null;
1556+
}
1557+
}
1558+
15411559
private static BreakpointSpecification brk(String className, String methodName, String signature, BreakpointHandler handler) {
15421560
return new BreakpointSpecification(className, methodName, signature, handler, false);
15431561
}

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,7 @@ static ConfigurationType copyAndSubtract(ConfigurationType type, ConfigurationTy
7474
private Map<ConfigurationMethod, ConfigurationMemberInfo> methods;
7575

7676
private boolean allDeclaredClasses;
77+
private boolean allPermittedSubclasses;
7778
private boolean allPublicClasses;
7879
private boolean allDeclaredFields;
7980
private boolean allPublicFields;
@@ -211,6 +212,7 @@ private void removeMethods(ConfigurationType other) {
211212
private void setFlagsFromOther(ConfigurationType other, BiPredicate<Boolean, Boolean> flagPredicate,
212213
BiFunction<ConfigurationMemberAccessibility, ConfigurationMemberAccessibility, ConfigurationMemberAccessibility> accessCombiner) {
213214
allDeclaredClasses = flagPredicate.test(allDeclaredClasses, other.allDeclaredClasses);
215+
allPermittedSubclasses = flagPredicate.test(allPermittedSubclasses, other.allPermittedSubclasses);
214216
allPublicClasses = flagPredicate.test(allPublicClasses, other.allPublicClasses);
215217
allDeclaredFields = flagPredicate.test(allDeclaredFields, other.allDeclaredFields);
216218
allPublicFields = flagPredicate.test(allPublicFields, other.allPublicFields);
@@ -225,7 +227,7 @@ private boolean isEmpty() {
225227
}
226228

227229
private boolean allFlagsFalse() {
228-
return !(allDeclaredClasses || allPublicClasses || allDeclaredFields || allPublicFields ||
230+
return !(allDeclaredClasses || allPermittedSubclasses || allPublicClasses || allDeclaredFields || allPublicFields ||
229231
allDeclaredMethodsAccess != ConfigurationMemberAccessibility.NONE || allPublicMethodsAccess != ConfigurationMemberAccessibility.NONE ||
230232
allDeclaredConstructorsAccess != ConfigurationMemberAccessibility.NONE || allPublicConstructorsAccess != ConfigurationMemberAccessibility.NONE);
231233
}
@@ -310,6 +312,10 @@ public synchronized void setAllDeclaredClasses() {
310312
allDeclaredClasses = true;
311313
}
312314

315+
public synchronized void setAllPermittedSubclasses() {
316+
allPermittedSubclasses = true;
317+
}
318+
313319
public synchronized void setAllPublicClasses() {
314320
allPublicClasses = true;
315321
}
@@ -365,6 +371,7 @@ public synchronized void printJson(JsonWriter writer) throws IOException {
365371
optionallyPrintJsonBoolean(writer, allDeclaredConstructorsAccess == ConfigurationMemberAccessibility.ACCESSED, "allDeclaredConstructors");
366372
optionallyPrintJsonBoolean(writer, allPublicConstructorsAccess == ConfigurationMemberAccessibility.ACCESSED, "allPublicConstructors");
367373
optionallyPrintJsonBoolean(writer, allDeclaredClasses, "allDeclaredClasses");
374+
optionallyPrintJsonBoolean(writer, allPermittedSubclasses, "allPermittedSubclasses");
368375
optionallyPrintJsonBoolean(writer, allPublicClasses, "allPublicClasses");
369376
optionallyPrintJsonBoolean(writer, allDeclaredMethodsAccess == ConfigurationMemberAccessibility.QUERIED, "queryAllDeclaredMethods");
370377
optionallyPrintJsonBoolean(writer, allPublicMethodsAccess == ConfigurationMemberAccessibility.QUERIED, "queryAllPublicMethods");
@@ -463,6 +470,10 @@ public static boolean haveAllDeclaredClasses(ConfigurationType type) {
463470
return type.allDeclaredClasses;
464471
}
465472

473+
public static boolean haveAllPermittedSubclasses(ConfigurationType type) {
474+
return type.allPermittedSubclasses;
475+
}
476+
466477
public static boolean haveAllPublicClasses(ConfigurationType type) {
467478
return type.allPublicClasses;
468479
}

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -98,6 +98,11 @@ public void registerDeclaredClasses(ConfigurationType type) {
9898
type.setAllDeclaredClasses();
9999
}
100100

101+
@Override
102+
public void registerPermittedSubclasses(ConfigurationType type) {
103+
type.setAllPermittedSubclasses();
104+
}
105+
101106
@Override
102107
public void registerPublicFields(ConfigurationType type) {
103108
type.setAllPublicFields();

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ public void processEntry(Map<String, ?> entry) {
156156
configuration.getOrCreateType(condition, clazz).setAllDeclaredClasses();
157157
break;
158158
}
159+
case "getPermittedSubclasses": {
160+
configuration.getOrCreateType(condition, clazz).setAllPermittedSubclasses();
161+
break;
162+
}
159163
case "getClasses": {
160164
configuration.getOrCreateType(condition, clazz).setAllPublicClasses();
161165
break;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@ public final class ReflectionConfigurationParser<T> extends ConfigurationParser
5252
private final boolean allowIncompleteClasspath;
5353
private static final List<String> OPTIONAL_REFLECT_CONFIG_OBJECT_ATTRS = Arrays.asList("allDeclaredConstructors", "allPublicConstructors",
5454
"allDeclaredMethods", "allPublicMethods", "allDeclaredFields", "allPublicFields",
55-
"allDeclaredClasses", "allPublicClasses", "methods", "queriedMethods", "fields", CONDITIONAL_KEY,
55+
"allDeclaredClasses", "allPermittedSubclasses", "allPublicClasses", "methods", "queriedMethods", "fields", CONDITIONAL_KEY,
5656
"queryAllDeclaredConstructors", "queryAllPublicConstructors", "queryAllDeclaredMethods", "queryAllPublicMethods");
5757

5858
public ReflectionConfigurationParser(ReflectionConfigurationParserDelegate<T> delegate) {
@@ -139,6 +139,11 @@ private void parseClass(Map<String, Object> data) {
139139
delegate.registerDeclaredClasses(clazz);
140140
}
141141
break;
142+
case "allPermittedSubclasses":
143+
if (asBoolean(value, "allPermittedSubclasses")) {
144+
delegate.registerPermittedSubclasses(clazz);
145+
}
146+
break;
142147
case "allPublicClasses":
143148
if (asBoolean(value, "allPublicClasses")) {
144149
delegate.registerPublicClasses(clazz);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParserDelegate.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,8 @@ public interface ReflectionConfigurationParserDelegate<T> {
4242

4343
void registerDeclaredClasses(T type);
4444

45+
void registerPermittedSubclasses(T type);
46+
4547
void registerPublicFields(T type);
4648

4749
void registerDeclaredFields(T type);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Map;
3434
import java.util.Optional;
3535
import java.util.concurrent.ConcurrentHashMap;
36+
import java.util.stream.Collectors;
3637

3738
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
3839
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
@@ -107,7 +108,15 @@ public void initializeMetaData(AnalysisType type) {
107108
/*
108109
* Support for permitted subclasses of a sealed class.
109110
*/
110-
hub.setPermittedSubclasses(SealedClassSupport.singleton().getPermittedSubclasses(type.getJavaClass()));
111+
Class<?>[] permitted = SealedClassSupport.singleton().getPermittedSubclasses(type.getJavaClass());
112+
if (permitted != null) {
113+
hub.setPermittedSubclasses(
114+
Arrays.stream(permitted)
115+
.filter(clazz -> metaAccess.lookupJavaType(clazz).isReachable())
116+
.collect(Collectors.toList())
117+
.toArray(new Class<?>[0])
118+
);
119+
}
111120

112121
/*
113122
* Support for Java annotations.

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ReflectionRegistryAdapter.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,9 @@
3434
import com.oracle.svm.core.TypeResult;
3535
import com.oracle.svm.core.configure.ConditionalElement;
3636
import com.oracle.svm.core.configure.ReflectionConfigurationParserDelegate;
37+
import com.oracle.svm.core.jdk.SealedClassSupport;
3738
import com.oracle.svm.hosted.ImageClassLoader;
3839
import com.oracle.svm.util.ClassUtil;
39-
4040
import jdk.vm.ci.meta.MetaUtil;
4141

4242
public class ReflectionRegistryAdapter implements ReflectionConfigurationParserDelegate<ConditionalElement<Class<?>>> {
@@ -87,6 +87,11 @@ public void registerDeclaredClasses(ConditionalElement<Class<?>> type) {
8787
registry.register(type.getCondition(), type.getElement().getDeclaredClasses());
8888
}
8989

90+
@Override
91+
public void registerPermittedSubclasses(ConditionalElement<Class<?>> type) {
92+
registry.register(type.getCondition(), SealedClassSupport.singleton().getPermittedSubclasses(type.getElement()));
93+
}
94+
9095
@Override
9196
public void registerPublicFields(ConditionalElement<Class<?>> type) {
9297
registry.register(type.getCondition(), false, type.getElement().getFields());

0 commit comments

Comments
 (0)