@@ -209,61 +209,64 @@ public boolean shouldIgnore(LazyValue<String> queriedClass, LazyValue<String> ca
209209 return shouldIgnore (queriedClass , callerClass , true );
210210 }
211211
212- record JNICallDescriptor (String declaringClass , String name , String signature , boolean required ) {
213- public boolean matches (String otherDeclaringClass , String otherName , String otherSignature ) {
214- return (declaringClass == null || declaringClass .equals (otherDeclaringClass )) &&
212+ record JNICallDescriptor (String jniFunction , String declaringClass , String name , String signature , boolean required ) {
213+ public boolean matches (String otherJniFunction , String otherDeclaringClass , String otherName , String otherSignature ) {
214+ return jniFunction .equals (otherJniFunction ) &&
215+ (declaringClass == null || declaringClass .equals (otherDeclaringClass )) &&
215216 (otherName == null || name .equals (otherName )) &&
216217 (otherSignature == null || signature .equals (otherSignature ));
217218 }
218219 }
219220
220221 private static final JNICallDescriptor [] JNI_STARTUP_SEQUENCE = new JNICallDescriptor []{
221- new JNICallDescriptor ("sun.launcher.LauncherHelper" , "getApplicationClass" , "()Ljava/lang/Class;" , true ),
222- new JNICallDescriptor ("java.lang.Class" , "getCanonicalName" , "()Ljava/lang/String;" , false ),
223- new JNICallDescriptor ("java.lang.String" , "lastIndexOf" , "(I)I" , false ),
224- new JNICallDescriptor ("java.lang.String" , "substring" , "(I)Ljava/lang/String;" , false ),
225- new JNICallDescriptor ("java.lang.System" , "getProperty" , "(Ljava/lang/String;)Ljava/lang/String;" , false ),
226- new JNICallDescriptor ("java.lang.System" , "setProperty" , "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" , false ),
227- new JNICallDescriptor (null , "main" , "([Ljava/lang/String;)V" , true ),
222+ new JNICallDescriptor ("GetStaticMethodID" , " sun.launcher.LauncherHelper" , "getApplicationClass" , "()Ljava/lang/Class;" , true ),
223+ new JNICallDescriptor ("GetMethodID" , " java.lang.Class" , "getCanonicalName" , "()Ljava/lang/String;" , false ),
224+ new JNICallDescriptor ("GetMethodID" , " java.lang.String" , "lastIndexOf" , "(I)I" , false ),
225+ new JNICallDescriptor ("GetMethodID" , " java.lang.String" , "substring" , "(I)Ljava/lang/String;" , false ),
226+ new JNICallDescriptor ("GetStaticMethodID" , " java.lang.System" , "getProperty" , "(Ljava/lang/String;)Ljava/lang/String;" , false ),
227+ new JNICallDescriptor ("GetStaticMethodID" , " java.lang.System" , "setProperty" , "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" , false ),
228+ new JNICallDescriptor ("GetStaticMethodID" , null , "main" , "([Ljava/lang/String;)V" , true ),
228229 };
230+ private static final int JNI_STARTUP_COMPLETE = JNI_STARTUP_SEQUENCE .length ;
231+ private static final int JNI_STARTUP_MISMATCH_COMPLETE = JNI_STARTUP_COMPLETE + 1 ;
229232
230- public boolean shouldIgnoreJniLookup (LazyValue <String > queriedClass , LazyValue <String > name , LazyValue <String > signature , LazyValue <String > callerClass ) {
231- assert !shouldIgnore (queriedClass , callerClass ) : "must have been checked before" ;
232- if (!heuristicsEnabled ) {
233+ /**
234+ * The JVM uses JNI calls internally when starting up. To avoid emitting configuration for these
235+ * calls, we ignore calls until an expected sequence of calls ({@link #JNI_STARTUP_SEQUENCE}) is
236+ * observed.
237+ */
238+ public boolean shouldIgnoreJniLookup (String jniFunction , LazyValue <String > queriedClass , LazyValue <String > name , LazyValue <String > signature , LazyValue <String > callerClass ) {
239+ if (shouldIgnore (queriedClass , callerClass )) {
240+ throw new AssertionError ("shouldIgnore must have been checked before shouldIgnoreJniLookup" );
241+ }
242+ if (!heuristicsEnabled || launchPhase >= JNI_STARTUP_COMPLETE ) {
243+ // Startup sequence completed (or we're not using the startup heuristics).
233244 return false ;
234245 }
235- if (launchPhase >= 0 ) {
236- JNICallDescriptor expectedCall = JNI_STARTUP_SEQUENCE [launchPhase ];
237- while (!expectedCall .matches (queriedClass .get (), name .get (), signature .get ())) {
238- if ("sun.launcher.LauncherHelper" .equals (queriedClass .get ())) {
239- return true ;
240- }
241- if (!expectedCall .required ) {
242- launchPhase ++;
243- expectedCall = JNI_STARTUP_SEQUENCE [launchPhase ];
244- } else {
245- launchPhase = -1 ;
246- return false ;
247- }
248- }
249- if (name .get () != null && signature .get () != null ) {
250- /*
251- * We ignore class lookups before field/method lookups but don't skip to the next
252- * query
253- */
254- launchPhase ++;
246+ if (!"GetStaticMethodID" .equals (jniFunction ) && !"GetMethodID" .equals (jniFunction )) {
247+ // Ignore function calls for functions not tracked by the startup sequence.
248+ return true ;
249+ }
250+
251+ JNICallDescriptor expectedCall = JNI_STARTUP_SEQUENCE [launchPhase ];
252+ while (!expectedCall .matches (jniFunction , queriedClass .get (), name .get (), signature .get ())) {
253+ if ("sun.launcher.LauncherHelper" .equals (queriedClass .get ())) {
254+ // Ignore mismatched calls from sun.launcher.LauncherHelper.
255+ return true ;
255256 }
256- if (launchPhase == JNI_STARTUP_SEQUENCE .length ) {
257- launchPhase = -1 ;
257+
258+ if (expectedCall .required ) {
259+ // Mismatch on a required call. Mark startup as complete and start tracing JNI
260+ // calls. (We prefer to emit extraneous configuration than to lose configuration).
261+ launchPhase = JNI_STARTUP_MISMATCH_COMPLETE ;
262+ return false ;
258263 }
259- return true ;
264+
265+ // The call is optional (e.g., it only happens on some platforms). Skip it.
266+ launchPhase ++;
267+ expectedCall = JNI_STARTUP_SEQUENCE [launchPhase ];
260268 }
261- /*
262- * NOTE: JVM invocations cannot be reliably filtered with callerClass == null because these
263- * could also be calls in a manually launched thread which is attached to JNI, but is not
264- * executing Java code (yet).
265- */
266- return false ;
269+ return true ;
267270 }
268271
269272 public static boolean shouldIgnoreResourceLookup (LazyValue <String > resource ) {
0 commit comments