|
30 | 30 | import java.lang.invoke.MethodType; |
31 | 31 | import java.lang.invoke.StringConcatFactory; |
32 | 32 | import java.lang.invoke.TypeDescriptor; |
33 | | -import java.lang.reflect.Executable; |
34 | | -import java.lang.reflect.Method; |
35 | 33 | import java.lang.reflect.Proxy; |
36 | 34 | import java.lang.runtime.ObjectMethods; |
37 | 35 | import java.lang.runtime.SwitchBootstraps; |
| 36 | +import java.util.HashSet; |
38 | 37 | import java.util.Set; |
39 | | -import java.util.concurrent.ConcurrentHashMap; |
40 | | -import java.util.concurrent.ConcurrentMap; |
41 | 38 |
|
42 | 39 | import org.graalvm.nativeimage.ImageSingletons; |
43 | 40 |
|
44 | | -import com.oracle.svm.core.bootstrap.BootstrapMethodInfo; |
| 41 | +import com.oracle.graal.pointsto.meta.AnalysisMethod; |
45 | 42 | import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; |
46 | 43 | import com.oracle.svm.core.feature.InternalFeature; |
47 | 44 | import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly; |
48 | 45 | import com.oracle.svm.core.traits.BuiltinTraits.NoLayeredCallbacks; |
49 | 46 | import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent; |
50 | 47 | import com.oracle.svm.core.traits.SingletonTraits; |
51 | | -import com.oracle.svm.util.ReflectionUtil; |
| 48 | +import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor; |
| 49 | +import com.oracle.svm.util.GraalAccess; |
| 50 | +import com.oracle.svm.util.JVMCIReflectionUtil; |
52 | 51 |
|
| 52 | +import jdk.vm.ci.meta.MetaAccessProvider; |
53 | 53 | import jdk.vm.ci.meta.ResolvedJavaMethod; |
| 54 | +import jdk.vm.ci.meta.ResolvedJavaType; |
54 | 55 |
|
55 | 56 | /** |
56 | 57 | * Class storing a list of bootstrap methods that are allowed to be executed at build time. Those |
|
60 | 61 | @SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class, layeredInstallationKind = Independent.class) |
61 | 62 | @AutomaticallyRegisteredFeature |
62 | 63 | public class BootstrapMethodConfiguration implements InternalFeature { |
63 | | - |
64 | | - public record BootstrapMethodRecord(int bci, int cpi, ResolvedJavaMethod method) { |
65 | | - } |
66 | | - |
67 | | - /* |
68 | | - * Map used to cache the BootstrapMethodInfo and reuse it for duplicated bytecode, avoiding |
69 | | - * execution of the bootstrap method for the same bci and method pair. This can happen during |
70 | | - * bytecode parsing as some blocks are duplicated, or for methods that are parsed multiple times |
71 | | - * (see MultiMethod). |
72 | | - */ |
73 | | - private final ConcurrentMap<BootstrapMethodRecord, BootstrapMethodInfo> bootstrapMethodInfoCache = new ConcurrentHashMap<>(); |
74 | | - private final Set<Executable> indyBuildTimeAllowList; |
75 | | - private final Set<Executable> condyBuildTimeAllowList; |
76 | | - private final Method metafactory; |
77 | | - private final Method altMetafactory; |
| 64 | + private final Set<ResolvedJavaMethod> buildTimeIndy = new HashSet<>(); |
| 65 | + private final Set<ResolvedJavaMethod> buildTimeCondy = new HashSet<>(); |
78 | 66 |
|
79 | 67 | public static BootstrapMethodConfiguration singleton() { |
80 | 68 | return ImageSingletons.lookup(BootstrapMethodConfiguration.class); |
81 | 69 | } |
82 | 70 |
|
83 | | - public BootstrapMethodConfiguration() { |
| 71 | + @Override |
| 72 | + public void duringSetup(DuringSetupAccess access) { |
| 73 | + MetaAccessProvider metaAccess = GraalAccess.getOriginalProviders().getMetaAccess(); |
84 | 74 | /* |
85 | 75 | * Bootstrap method used for Lambdas. Executing this method at run time implies defining |
86 | 76 | * hidden class at run time, which is unsupported. |
87 | 77 | */ |
88 | | - metafactory = ReflectionUtil.lookupMethod(LambdaMetafactory.class, "metafactory", MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, |
89 | | - MethodType.class); |
| 78 | + ResolvedJavaType lambdaMetaFactory = metaAccess.lookupJavaType(LambdaMetafactory.class); |
| 79 | + ResolvedJavaMethod metafactory = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, lambdaMetaFactory, "metafactory", MethodHandles.Lookup.class, String.class, MethodType.class, |
| 80 | + MethodType.class, MethodHandle.class, MethodType.class); |
90 | 81 | /* Alternate version of LambdaMetafactory.metafactory. */ |
91 | | - altMetafactory = ReflectionUtil.lookupMethod(LambdaMetafactory.class, "altMetafactory", MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); |
| 82 | + ResolvedJavaMethod altMetafactory = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, lambdaMetaFactory, "altMetafactory", MethodHandles.Lookup.class, String.class, MethodType.class, |
| 83 | + Object[].class); |
| 84 | + buildTimeIndy.add(metafactory); |
| 85 | + buildTimeIndy.add(altMetafactory); |
92 | 86 |
|
93 | 87 | /* |
94 | 88 | * Bootstrap method used to optimize String concatenation. Executing it at run time |
95 | 89 | * currently causes a StackOverFlow error as it infinitely calls itself. |
96 | 90 | */ |
97 | | - Method makeConcat = ReflectionUtil.lookupMethod(StringConcatFactory.class, "makeConcat", MethodHandles.Lookup.class, String.class, MethodType.class); |
| 91 | + ResolvedJavaType stringConcatFactory = metaAccess.lookupJavaType(StringConcatFactory.class); |
| 92 | + ResolvedJavaMethod makeConcat = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, stringConcatFactory, "makeConcat", MethodHandles.Lookup.class, String.class, MethodType.class); |
98 | 93 | /* Alternate version of StringConcatFactory.makeConcat with constant arguments. */ |
99 | | - Method makeConcatWithConstants = ReflectionUtil.lookupMethod(StringConcatFactory.class, "makeConcatWithConstants", MethodHandles.Lookup.class, String.class, MethodType.class, String.class, |
100 | | - Object[].class); |
| 94 | + ResolvedJavaMethod makeConcatWithConstants = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, stringConcatFactory, "makeConcatWithConstants", MethodHandles.Lookup.class, String.class, |
| 95 | + MethodType.class, String.class, Object[].class); |
| 96 | + buildTimeIndy.add(makeConcat); |
| 97 | + buildTimeIndy.add(makeConcatWithConstants); |
101 | 98 |
|
102 | 99 | /* Causes deadlock in Permission feature. */ |
103 | | - Method bootstrap = ReflectionUtil.lookupMethod(ObjectMethods.class, "bootstrap", MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, |
104 | | - MethodHandle[].class); |
| 100 | + ResolvedJavaType objectMethods = metaAccess.lookupJavaType(ObjectMethods.class); |
| 101 | + ResolvedJavaMethod bootstrap = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, objectMethods, "bootstrap", MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, |
| 102 | + String.class, MethodHandle[].class); |
| 103 | + buildTimeIndy.add(bootstrap); |
105 | 104 |
|
106 | 105 | /* |
107 | 106 | * Bootstrap methods used for switch statements. Executing these methods at run time implies |
108 | 107 | * defining hidden classes at run time, which is unsupported. |
109 | 108 | */ |
110 | | - Method typeSwitch = ReflectionUtil.lookupMethod(SwitchBootstraps.class, "typeSwitch", MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); |
111 | | - Method enumSwitch = ReflectionUtil.lookupMethod(SwitchBootstraps.class, "enumSwitch", MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); |
| 109 | + ResolvedJavaType switchBootstraps = metaAccess.lookupJavaType(SwitchBootstraps.class); |
| 110 | + ResolvedJavaMethod typeSwitch = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, switchBootstraps, "typeSwitch", MethodHandles.Lookup.class, String.class, MethodType.class, |
| 111 | + Object[].class); |
| 112 | + ResolvedJavaMethod enumSwitch = JVMCIReflectionUtil.getUniqueDeclaredMethod(metaAccess, switchBootstraps, "enumSwitch", MethodHandles.Lookup.class, String.class, MethodType.class, |
| 113 | + Object[].class); |
| 114 | + buildTimeIndy.add(typeSwitch); |
| 115 | + buildTimeIndy.add(enumSwitch); |
| 116 | + } |
112 | 117 |
|
113 | | - /* Bootstrap method used for retrieving the value of static final processors. */ |
114 | | - indyBuildTimeAllowList = Set.of(metafactory, altMetafactory, makeConcat, makeConcatWithConstants, bootstrap, typeSwitch, enumSwitch); |
| 118 | + public void addBuildTimeIndy(ResolvedJavaMethod method) { |
| 119 | + buildTimeIndy.add(method); |
| 120 | + } |
115 | 121 |
|
116 | | - /* Set of bootstrap methods for constant dynamic allowed at build time is empty for now */ |
117 | | - condyBuildTimeAllowList = Set.of(); |
| 122 | + public void addBuildTimeCondy(ResolvedJavaMethod method) { |
| 123 | + buildTimeCondy.add(method); |
118 | 124 | } |
119 | 125 |
|
120 | 126 | /** |
121 | 127 | * Check if the provided method is allowed to be executed at build time. |
122 | 128 | */ |
123 | | - public boolean isIndyAllowedAtBuildTime(Executable method) { |
124 | | - return method != null && indyBuildTimeAllowList.contains(method); |
125 | | - } |
126 | | - |
127 | | - public boolean isMetafactory(Executable method) { |
128 | | - return method != null && (method.equals(metafactory) || method.equals(altMetafactory)); |
| 129 | + public boolean isIndyAllowedAtBuildTime(ResolvedJavaMethod method) { |
| 130 | + ResolvedJavaMethod m = getWrapped(method); |
| 131 | + return m != null && buildTimeIndy.contains(m); |
129 | 132 | } |
130 | 133 |
|
131 | 134 | /** |
132 | 135 | * Check if the provided method is allowed to be executed at build time. |
133 | 136 | */ |
134 | | - public boolean isCondyAllowedAtBuildTime(Executable method) { |
135 | | - return method != null && (condyBuildTimeAllowList.contains(method) || isProxyCondy(method)); |
| 137 | + public boolean isCondyAllowedAtBuildTime(ResolvedJavaMethod method) { |
| 138 | + ResolvedJavaMethod m = getWrapped(method); |
| 139 | + return m != null && (buildTimeCondy.contains(m) || isProxyCondy(m)); |
| 140 | + } |
| 141 | + |
| 142 | + private static ResolvedJavaMethod getWrapped(ResolvedJavaMethod method) { |
| 143 | + if (method instanceof AnalysisMethod analysisMethod) { |
| 144 | + return analysisMethod.getWrapped(); |
| 145 | + } else { |
| 146 | + return method; |
| 147 | + } |
136 | 148 | } |
137 | 149 |
|
138 | 150 | /** |
139 | 151 | * Every {@link Proxy} class has its own bootstrap method that is used for a constant dynamic. |
140 | 152 | */ |
141 | | - private static boolean isProxyCondy(Executable method) { |
142 | | - return Proxy.isProxyClass(method.getDeclaringClass()) && method.getName().equals("$getMethod"); |
143 | | - } |
144 | | - |
145 | | - public ConcurrentMap<BootstrapMethodRecord, BootstrapMethodInfo> getBootstrapMethodInfoCache() { |
146 | | - return bootstrapMethodInfoCache; |
| 153 | + private static boolean isProxyCondy(ResolvedJavaMethod method) { |
| 154 | + return ProxyRenamingSubstitutionProcessor.isProxyType(method.getDeclaringClass()) && method.getName().equals("$getMethod"); |
147 | 155 | } |
148 | 156 | } |
0 commit comments