2828import static com .oracle .svm .core .SubstrateOptions .JNIVerboseLookupErrors ;
2929
3030import java .io .PrintStream ;
31+ import java .util .EnumSet ;
3132import java .util .Map ;
3233import java .util .function .Function ;
3334
4647import com .oracle .svm .core .jni .MissingJNIRegistrationUtils ;
4748import com .oracle .svm .core .jni .headers .JNIFieldId ;
4849import 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 ;
4953import com .oracle .svm .core .log .Log ;
5054import com .oracle .svm .core .snippets .KnownIntrinsics ;
5155import com .oracle .svm .core .util .ImageHeapMap ;
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