Skip to content

Commit 2bdc50b

Browse files
committed
[GR-59148] Read JNI dictionary from all layers.
PullRequest: graal/19728
2 parents 4b171c8 + 1385d81 commit 2bdc50b

File tree

3 files changed

+125
-81
lines changed

3 files changed

+125
-81
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/JNITestingBackdoor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static int getThreadLocalPinnedObjectCount() {
4444
}
4545

4646
public static long getMethodID(Class<?> clazz, String name, String signature, boolean isStatic) {
47-
return JNIReflectionDictionary.singleton().getMethodID(clazz, name, signature, isStatic).rawValue();
47+
return JNIReflectionDictionary.getMethodID(clazz, name, signature, isStatic).rawValue();
4848
}
4949

5050
public static int getThreadLocalOwnedMonitorsCount() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java

Lines changed: 114 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static com.oracle.svm.core.SubstrateOptions.JNIVerboseLookupErrors;
2929

3030
import java.io.PrintStream;
31+
import java.util.EnumSet;
3132
import java.util.Map;
3233
import java.util.function.Function;
3334

@@ -46,6 +47,9 @@
4647
import com.oracle.svm.core.jni.MissingJNIRegistrationUtils;
4748
import com.oracle.svm.core.jni.headers.JNIFieldId;
4849
import com.oracle.svm.core.jni.headers.JNIMethodId;
50+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
51+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
52+
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
4953
import com.oracle.svm.core.log.Log;
5054
import com.oracle.svm.core.snippets.KnownIntrinsics;
5155
import com.oracle.svm.core.util.ImageHeapMap;
@@ -61,7 +65,7 @@
6165
/**
6266
* Provides JNI access to predetermined classes, methods and fields at runtime.
6367
*/
64-
public final class JNIReflectionDictionary {
68+
public final class JNIReflectionDictionary implements MultiLayeredImageSingleton, UnsavedSingleton {
6569
/**
6670
* Enables lookups with {@link WrappedAsciiCString}, which avoids many unnecessary character set
6771
* conversions and allocations.
@@ -91,47 +95,56 @@ public static void create() {
9195
ImageSingletons.add(JNIReflectionDictionary.class, new JNIReflectionDictionary());
9296
}
9397

98+
@Platforms(HOSTED_ONLY.class)
9499
public static JNIReflectionDictionary singleton() {
95100
return ImageSingletons.lookup(JNIReflectionDictionary.class);
96101
}
97102

103+
private static JNIReflectionDictionary[] layeredSingletons() {
104+
return MultiLayeredImageSingleton.getAllLayers(JNIReflectionDictionary.class);
105+
}
106+
98107
private final EconomicMap<CharSequence, JNIAccessibleClass> classesByName = ImageHeapMap.create(WRAPPED_CSTRING_EQUIVALENCE);
99108
private final EconomicMap<Class<?>, JNIAccessibleClass> classesByClassObject = ImageHeapMap.create();
100109
private final EconomicMap<JNINativeLinkage, JNINativeLinkage> nativeLinkages = ImageHeapMap.create();
101110

102111
private JNIReflectionDictionary() {
103112
}
104113

105-
private void dump(boolean condition, String label) {
114+
private static void dump(boolean condition, String label) {
106115
if (JNIVerboseLookupErrors.getValue() && condition) {
107-
PrintStream ps = Log.logStream();
108-
ps.println(label);
109-
ps.println(" classesByName:");
110-
MapCursor<CharSequence, JNIAccessibleClass> nameCursor = classesByName.getEntries();
111-
while (nameCursor.advance()) {
112-
ps.print(" ");
113-
ps.println(nameCursor.getKey());
114-
JNIAccessibleClass clazz = nameCursor.getValue();
115-
ps.println(" methods:");
116-
MapCursor<JNIAccessibleMethodDescriptor, JNIAccessibleMethod> methodsCursor = clazz.getMethods();
117-
while (methodsCursor.advance()) {
118-
ps.print(" ");
119-
ps.print(methodsCursor.getKey().getName());
120-
ps.println(methodsCursor.getKey().getSignature());
116+
int layerNum = 0;
117+
for (var dictionary : layeredSingletons()) {
118+
PrintStream ps = Log.logStream();
119+
ps.println("Layer " + layerNum);
120+
ps.println(label);
121+
ps.println(" classesByName:");
122+
MapCursor<CharSequence, JNIAccessibleClass> nameCursor = dictionary.classesByName.getEntries();
123+
while (nameCursor.advance()) {
124+
ps.print(" ");
125+
ps.println(nameCursor.getKey());
126+
JNIAccessibleClass clazz = nameCursor.getValue();
127+
ps.println(" methods:");
128+
MapCursor<JNIAccessibleMethodDescriptor, JNIAccessibleMethod> methodsCursor = clazz.getMethods();
129+
while (methodsCursor.advance()) {
130+
ps.print(" ");
131+
ps.print(methodsCursor.getKey().getName());
132+
ps.println(methodsCursor.getKey().getSignature());
133+
}
134+
ps.println(" fields:");
135+
UnmodifiableMapCursor<CharSequence, JNIAccessibleField> fieldsCursor = clazz.getFields();
136+
while (fieldsCursor.advance()) {
137+
ps.print(" ");
138+
ps.println(fieldsCursor.getKey());
139+
}
121140
}
122-
ps.println(" fields:");
123-
UnmodifiableMapCursor<CharSequence, JNIAccessibleField> fieldsCursor = clazz.getFields();
124-
while (fieldsCursor.advance()) {
125-
ps.print(" ");
126-
ps.println(fieldsCursor.getKey());
127-
}
128-
}
129141

130-
ps.println(" classesByClassObject:");
131-
MapCursor<Class<?>, JNIAccessibleClass> cursor = classesByClassObject.getEntries();
132-
while (cursor.advance()) {
133-
ps.print(" ");
134-
ps.println(cursor.getKey());
142+
ps.println(" classesByClassObject:");
143+
MapCursor<Class<?>, JNIAccessibleClass> cursor = dictionary.classesByClassObject.getEntries();
144+
while (cursor.advance()) {
145+
ps.print(" ");
146+
ps.println(cursor.getKey());
147+
}
135148
}
136149
}
137150
}
@@ -151,6 +164,7 @@ public JNIAccessibleClass addClassIfAbsent(Class<?> classObj, Function<Class<?>,
151164
return classesByClassObject.get(classObj);
152165
}
153166

167+
@Platforms(HOSTED_ONLY.class)
154168
public void addNegativeClassLookupIfAbsent(String typeName) {
155169
String internalName = MetaUtil.toInternalName(typeName);
156170
String queryName = internalName.startsWith("L") ? internalName.substring(1, internalName.length() - 1) : internalName;
@@ -162,15 +176,21 @@ public void addLinkages(Map<JNINativeLinkage, JNINativeLinkage> linkages) {
162176
nativeLinkages.putAll(EconomicMap.wrapMap(linkages));
163177
}
164178

179+
@Platforms(HOSTED_ONLY.class)
165180
public Iterable<JNIAccessibleClass> getClasses() {
166181
return classesByClassObject.getValues();
167182
}
168183

169-
public Class<?> getClassObjectByName(CharSequence name) {
170-
JNIAccessibleClass clazz = classesByName.get(name);
171-
clazz = checkClass(clazz, name);
172-
dump(clazz == null, "getClassObjectByName");
173-
return (clazz != null) ? clazz.getClassObject() : null;
184+
public static Class<?> getClassObjectByName(CharSequence name) {
185+
for (var dictionary : layeredSingletons()) {
186+
JNIAccessibleClass clazz = dictionary.classesByName.get(name);
187+
clazz = checkClass(clazz, name);
188+
if (clazz != null) {
189+
return clazz.getClassObject();
190+
}
191+
}
192+
dump(true, "getClassObjectByName");
193+
return null;
174194
}
175195

176196
private static JNIAccessibleClass checkClass(JNIAccessibleClass clazz, CharSequence name) {
@@ -192,20 +212,28 @@ private static JNIAccessibleClass checkClass(JNIAccessibleClass clazz, CharSeque
192212
* method
193213
* @return the linkage for the native method or {@code null} if no linkage exists
194214
*/
195-
public JNINativeLinkage getLinkage(CharSequence declaringClass, CharSequence name, CharSequence descriptor) {
215+
public static JNINativeLinkage getLinkage(CharSequence declaringClass, CharSequence name, CharSequence descriptor) {
196216
JNINativeLinkage key = new JNINativeLinkage(declaringClass, name, descriptor);
197-
return nativeLinkages.get(key);
217+
for (var dictionary : layeredSingletons()) {
218+
var linkage = dictionary.nativeLinkages.get(key);
219+
if (linkage != null) {
220+
return linkage;
221+
}
222+
}
223+
return null;
198224
}
199225

200-
public void unsetEntryPoints(String declaringClass) {
201-
for (JNINativeLinkage linkage : nativeLinkages.getKeys()) {
202-
if (declaringClass.equals(linkage.getDeclaringClassName())) {
203-
linkage.unsetEntryPoint();
226+
public static void unsetEntryPoints(String declaringClass) {
227+
for (var dictionary : layeredSingletons()) {
228+
for (JNINativeLinkage linkage : dictionary.nativeLinkages.getKeys()) {
229+
if (declaringClass.equals(linkage.getDeclaringClassName())) {
230+
linkage.unsetEntryPoint();
231+
}
204232
}
205233
}
206234
}
207235

208-
private JNIAccessibleMethod findMethod(Class<?> clazz, JNIAccessibleMethodDescriptor descriptor, String dumpLabel) {
236+
private static JNIAccessibleMethod findMethod(Class<?> clazz, JNIAccessibleMethodDescriptor descriptor, String dumpLabel) {
209237
JNIAccessibleMethod method = getDeclaredMethod(clazz, descriptor, dumpLabel);
210238
if (descriptor.isConstructor() || descriptor.isClassInitializer()) { // never recurse
211239
return method;
@@ -220,7 +248,7 @@ private JNIAccessibleMethod findMethod(Class<?> clazz, JNIAccessibleMethodDescri
220248
return method;
221249
}
222250

223-
private JNIAccessibleMethod findSuperinterfaceMethod(Class<?> clazz, JNIAccessibleMethodDescriptor descriptor) {
251+
private static JNIAccessibleMethod findSuperinterfaceMethod(Class<?> clazz, JNIAccessibleMethodDescriptor descriptor) {
224252
for (Class<?> parent : clazz.getInterfaces()) {
225253
JNIAccessibleMethod method = getDeclaredMethod(parent, descriptor, null);
226254
if (method == null) {
@@ -234,23 +262,29 @@ private JNIAccessibleMethod findSuperinterfaceMethod(Class<?> clazz, JNIAccessib
234262
return null;
235263
}
236264

237-
public JNIMethodId getDeclaredMethodID(Class<?> classObject, JNIAccessibleMethodDescriptor descriptor, boolean isStatic) {
265+
public static JNIMethodId getDeclaredMethodID(Class<?> classObject, JNIAccessibleMethodDescriptor descriptor, boolean isStatic) {
238266
JNIAccessibleMethod method = getDeclaredMethod(classObject, descriptor, "getDeclaredMethodID");
239267
boolean match = (method != null && method.isStatic() == isStatic);
240268
return toMethodID(match ? method : null);
241269
}
242270

243-
private JNIAccessibleMethod getDeclaredMethod(Class<?> classObject, JNIAccessibleMethodDescriptor descriptor, String dumpLabel) {
244-
JNIAccessibleClass clazz = classesByClassObject.get(classObject);
245-
dump(clazz == null && dumpLabel != null, dumpLabel);
246-
JNIAccessibleMethod method = null;
247-
if (clazz != null) {
248-
method = clazz.getMethod(descriptor);
271+
private static JNIAccessibleMethod getDeclaredMethod(Class<?> classObject, JNIAccessibleMethodDescriptor descriptor, String dumpLabel) {
272+
boolean foundClass = false;
273+
for (var dictionary : layeredSingletons()) {
274+
JNIAccessibleClass clazz = dictionary.classesByClassObject.get(classObject);
275+
if (clazz != null) {
276+
foundClass = true;
277+
JNIAccessibleMethod method = clazz.getMethod(descriptor);
278+
if (method != null) {
279+
return method;
280+
}
281+
}
249282
}
250-
return method;
283+
dump(!foundClass && dumpLabel != null, dumpLabel);
284+
return null;
251285
}
252286

253-
public JNIMethodId getMethodID(Class<?> classObject, CharSequence name, CharSequence signature, boolean isStatic) {
287+
public static JNIMethodId getMethodID(Class<?> classObject, CharSequence name, CharSequence signature, boolean isStatic) {
254288
JNIAccessibleMethod method = findMethod(classObject, new JNIAccessibleMethodDescriptor(name, signature), "getMethodID");
255289
method = checkMethod(method, classObject, name, signature);
256290
boolean match = (method != null && method.isStatic() == isStatic && method.isDiscoverableIn(classObject));
@@ -289,25 +323,29 @@ private static JNIAccessibleMethod checkMethod(JNIAccessibleMethod method, Class
289323
return method;
290324
}
291325

292-
private JNIAccessibleField getDeclaredField(Class<?> classObject, CharSequence name, boolean isStatic, String dumpLabel) {
293-
JNIAccessibleClass clazz = classesByClassObject.get(classObject);
294-
dump(clazz == null && dumpLabel != null, dumpLabel);
295-
if (clazz != null) {
296-
JNIAccessibleField field = clazz.getField(name);
297-
if (field != null && (field.isStatic() == isStatic || field.isNegative())) {
298-
return field;
326+
private static JNIAccessibleField getDeclaredField(Class<?> classObject, CharSequence name, boolean isStatic, String dumpLabel) {
327+
boolean foundClass = false;
328+
for (var dictionary : layeredSingletons()) {
329+
JNIAccessibleClass clazz = dictionary.classesByClassObject.get(classObject);
330+
if (clazz != null) {
331+
foundClass = true;
332+
JNIAccessibleField field = clazz.getField(name);
333+
if (field != null && (field.isStatic() == isStatic || field.isNegative())) {
334+
return field;
335+
}
299336
}
300337
}
338+
dump(!foundClass && dumpLabel != null, dumpLabel);
301339
return null;
302340
}
303341

304-
public JNIFieldId getDeclaredFieldID(Class<?> classObject, String name, boolean isStatic) {
342+
public static JNIFieldId getDeclaredFieldID(Class<?> classObject, String name, boolean isStatic) {
305343
JNIAccessibleField field = getDeclaredField(classObject, name, isStatic, "getDeclaredFieldID");
306344
field = checkField(field, classObject, name);
307345
return (field != null) ? field.getId() : Word.nullPointer();
308346
}
309347

310-
private JNIAccessibleField findField(Class<?> clazz, CharSequence name, boolean isStatic, String dumpLabel) {
348+
private static JNIAccessibleField findField(Class<?> clazz, CharSequence name, boolean isStatic, String dumpLabel) {
311349
// Lookup according to JVM spec 5.4.3.2: local fields, superinterfaces, superclasses
312350
JNIAccessibleField field = getDeclaredField(clazz, name, isStatic, dumpLabel);
313351
if (field == null && isStatic) {
@@ -319,7 +357,7 @@ private JNIAccessibleField findField(Class<?> clazz, CharSequence name, boolean
319357
return field;
320358
}
321359

322-
private JNIAccessibleField findSuperinterfaceField(Class<?> clazz, CharSequence name) {
360+
private static JNIAccessibleField findSuperinterfaceField(Class<?> clazz, CharSequence name) {
323361
for (Class<?> parent : clazz.getInterfaces()) {
324362
JNIAccessibleField field = getDeclaredField(parent, name, true, null);
325363
if (field == null) {
@@ -332,21 +370,23 @@ private JNIAccessibleField findSuperinterfaceField(Class<?> clazz, CharSequence
332370
return null;
333371
}
334372

335-
public JNIFieldId getFieldID(Class<?> clazz, CharSequence name, boolean isStatic) {
373+
public static JNIFieldId getFieldID(Class<?> clazz, CharSequence name, boolean isStatic) {
336374
JNIAccessibleField field = findField(clazz, name, isStatic, "getFieldID");
337375
field = checkField(field, clazz, name);
338376
return (field != null && field.isDiscoverableIn(clazz)) ? field.getId() : Word.nullPointer();
339377
}
340378

341-
public String getFieldNameByID(Class<?> classObject, JNIFieldId id) {
342-
JNIAccessibleClass clazz = classesByClassObject.get(classObject);
343-
if (clazz != null) {
344-
UnmodifiableMapCursor<CharSequence, JNIAccessibleField> fieldsCursor = clazz.getFields();
345-
while (fieldsCursor.advance()) {
346-
JNIAccessibleField field = fieldsCursor.getValue();
347-
if (id.equal(field.getId())) {
348-
VMError.guarantee(!field.isNegative(), "Existing fields can't correspond to a negative query");
349-
return (String) fieldsCursor.getKey();
379+
public static String getFieldNameByID(Class<?> classObject, JNIFieldId id) {
380+
for (var dictionary : layeredSingletons()) {
381+
JNIAccessibleClass clazz = dictionary.classesByClassObject.get(classObject);
382+
if (clazz != null) {
383+
UnmodifiableMapCursor<CharSequence, JNIAccessibleField> fieldsCursor = clazz.getFields();
384+
while (fieldsCursor.advance()) {
385+
JNIAccessibleField field = fieldsCursor.getValue();
386+
if (id.equal(field.getId())) {
387+
VMError.guarantee(!field.isNegative(), "Existing fields can't correspond to a negative query");
388+
return (String) fieldsCursor.getKey();
389+
}
350390
}
351391
}
352392
}
@@ -375,4 +415,8 @@ public static JNIAccessibleMethodDescriptor getMethodDescriptor(JNIAccessibleMet
375415
return null;
376416
}
377417

418+
@Override
419+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
420+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
421+
}
378422
}

0 commit comments

Comments
 (0)