Bug 1448428 - Part 1a: Split generated JNI wrappers into multiple files. r=snorp,geckoview-reviewers
authorNick Alexander <nalexander@mozilla.com>
Wed, 13 May 2020 17:46:46 +0000
changeset 529692 298f90202eda7df9de5c918a218057ce973c4f72
parent 529691 941aaea7104eb93ff0f767c7ced85152128f2590
child 529693 9464ad22d4129fc97988e990883e5eb7d379753d
push id37414
push usernbeleuzu@mozilla.com
push dateThu, 14 May 2020 02:40:10 +0000
treeherdermozilla-central@045d696faa87 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, geckoview-reviewers
bugs1448428
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1448428 - Part 1a: Split generated JNI wrappers into multiple files. r=snorp,geckoview-reviewers This handles the build system bits. The subsequent patch will restore the "unified" GeneratedJNI{Natives,Wrappers}.h header files, and will be folded into this one before landing. What will still remain is to update the consumers of the .h files (all the current #include lines) to use the fine-grained imports. At that time the "unified" header files can be removed entirely. Differential Revision: https://phabricator.services.mozilla.com/D58572
mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/classloader/ClassWithOptions.java
widget/android/moz.build
--- a/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
+++ b/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/AnnotationProcessor.java
@@ -24,119 +24,125 @@ public class AnnotationProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
             "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
             "// from annotations on Java methods. To update, change the annotations on the\n" +
             "// corresponding Java methods and rerun the build. Manually updating this file\n" +
             "// will cause your build to fail.\n" +
             "\n";
 
-    private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-    private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-    private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
-
     public static void main(String[] args) {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length < 2) {
             System.err.println("Usage: java AnnotationProcessor outprefix jarfiles ...");
             System.exit(1);
         }
 
         final String OUTPUT_PREFIX = args[0];
-        final String SOURCE_FILE = OUTPUT_PREFIX + "JNIWrappers.cpp";
-        final String HEADER_FILE = OUTPUT_PREFIX + "JNIWrappers.h";
-        final String NATIVES_FILE = OUTPUT_PREFIX + "JNINatives.h";
 
         System.out.println("Processing annotations...");
 
         // We want to produce the same output as last time as often as possible. Ordering of
         // generated statements, therefore, needs to be consistent.
         final String[] jars = Arrays.copyOfRange(args, 1, args.length);
         Arrays.sort(jars);
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
+        int ret = 0;
+
         // Get an iterator over the classes in the jar files given...
         Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(jars);
 
-        headerFile.append(
-                "#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" +
-                "#define " + getHeaderGuardName(HEADER_FILE) + "\n" +
-                "\n" +
-                "#ifndef MOZ_PREPROCESSOR\n" +
-                "#include \"mozilla/jni/Refs.h\"\n" +
-                "#endif\n" +
-                "\n" +
-                "namespace mozilla {\n" +
-                "namespace java {\n" +
-                "\n");
+        while (jarClassIterator.hasNext()) {
+            final ClassWithOptions annotatedClass = jarClassIterator.next();
+            if (!annotatedClass.hasGenerated()) {
+                continue;
+            }
+
+            final String sourceFileName = OUTPUT_PREFIX + annotatedClass.generatedName + "JNIWrappers.cpp";
+            final String headerFileName = OUTPUT_PREFIX + annotatedClass.generatedName + "JNIWrappers.h";
+            final String nativesFileName = OUTPUT_PREFIX + annotatedClass.generatedName + "JNINatives.h";
 
-        implementationFile.append(
-                "#ifndef MOZ_PREPROCESSOR\n" +
-                "#include \"" + HEADER_FILE + "\"\n" +
-                "#include \"mozilla/jni/Accessors.h\"\n" +
-                "#endif\n" +
-                "\n" +
-                "namespace mozilla {\n" +
-                "namespace java {\n" +
-                "\n");
+            final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
+            final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
+            final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
+
+            headerFile.append(
+                    "#ifndef " + getHeaderGuardName(headerFileName) + "\n" +
+                    "#define " + getHeaderGuardName(headerFileName) + "\n" +
+                    "\n" +
+                    "#ifndef MOZ_PREPROCESSOR\n" +
+                    "#include \"mozilla/jni/Refs.h\"\n" +
+                    "#endif\n" +
+                    "\n" +
+                    "namespace mozilla {\n" +
+                    "namespace java {\n" +
+                    "\n");
 
-        nativesFile.append(
-                "#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" +
-                "#define " + getHeaderGuardName(NATIVES_FILE) + "\n" +
-                "\n" +
-                "#ifndef MOZ_PREPROCESSOR\n" +
-                "#include \"" + HEADER_FILE + "\"\n" +
-                "#include \"mozilla/jni/Natives.h\"\n" +
-                "#endif\n" +
-                "\n" +
-                "namespace mozilla {\n" +
-                "namespace java {\n" +
-                "\n");
-
-        while (jarClassIterator.hasNext()) {
-            generateClass(jarClassIterator.next());
-        }
+            implementationFile.append(
+                    "#ifndef MOZ_PREPROCESSOR\n" +
+                    "#include \"" + headerFileName + "\"\n" +
+                    "#include \"mozilla/jni/Accessors.h\"\n" +
+                    "#endif\n" +
+                    "\n" +
+                    "namespace mozilla {\n" +
+                    "namespace java {\n" +
+                    "\n");
 
-        implementationFile.append(
-                "} /* java */\n" +
-                "} /* mozilla */\n");
+            nativesFile.append(
+                    "#ifndef " + getHeaderGuardName(nativesFileName) + "\n" +
+                    "#define " + getHeaderGuardName(nativesFileName) + "\n" +
+                    "\n" +
+                    "#ifndef MOZ_PREPROCESSOR\n" +
+                    "#include \"" + headerFileName + "\"\n" +
+                    "#include \"mozilla/jni/Natives.h\"\n" +
+                    "#endif\n" +
+                    "\n" +
+                    "namespace mozilla {\n" +
+                    "namespace java {\n" +
+                    "\n");
 
-        headerFile.append(
-                "} /* java */\n" +
-                "} /* mozilla */\n" +
-                "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
+            generateClass(annotatedClass, headerFile, implementationFile, nativesFile);
 
-        nativesFile.append(
-                "} /* java */\n" +
-                "} /* mozilla */\n" +
-                "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
+            implementationFile.append(
+                    "} /* java */\n" +
+                    "} /* mozilla */\n");
+
+            headerFile.append(
+                    "} /* java */\n" +
+                    "} /* mozilla */\n" +
+                    "#endif // " + getHeaderGuardName(headerFileName) + "\n");
 
-        int ret = 0;
-        ret |= writeOutputFile(SOURCE_FILE, implementationFile);
-        ret |= writeOutputFile(HEADER_FILE, headerFile);
-        ret |= writeOutputFile(NATIVES_FILE, nativesFile);
+            nativesFile.append(
+                    "} /* java */\n" +
+                    "} /* mozilla */\n" +
+                    "#endif // " + getHeaderGuardName(nativesFileName) + "\n");
+
+            ret |= writeOutputFile(sourceFileName, implementationFile);
+            ret |= writeOutputFile(headerFileName, headerFile);
+            ret |= writeOutputFile(nativesFileName, nativesFile);
+        }
 
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
 
         System.exit(ret);
     }
 
-    private static void generateClass(final ClassWithOptions annotatedClass) {
+    private static void generateClass(final ClassWithOptions annotatedClass,
+                                      final StringBuilder headerFile,
+                                      final StringBuilder implementationFile,
+                                      final StringBuilder nativesFile) {
         // Get an iterator over the appropriately generated methods of this class
         final GeneratableElementIterator methodIterator
                 = new GeneratableElementIterator(annotatedClass);
         final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
 
-        if (!methodIterator.hasNext() && innerClasses.length == 0) {
-            return;
-        }
-
         final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass);
         generatorInstance.generateClasses(innerClasses);
 
         // Iterate all annotated members in this class..
         while (methodIterator.hasNext()) {
             AnnotatableEntity aElementTuple = methodIterator.next();
             switch (aElementTuple.mEntityType) {
                 case METHOD:
@@ -154,17 +160,17 @@ public class AnnotationProcessor {
             }
         }
 
         headerFile.append(generatorInstance.getHeaderFileContents());
         implementationFile.append(generatorInstance.getWrapperFileContents());
         nativesFile.append(generatorInstance.getNativesFileContents());
 
         for (ClassWithOptions innerClass : innerClasses) {
-            generateClass(innerClass);
+            generateClass(innerClass, headerFile, implementationFile, nativesFile);
         }
     }
 
     private static String getHeaderGuardName(final String name) {
         return name.replaceAll("\\W", "_");
     }
 
     private static int writeOutputFile(final String name, final StringBuilder content) {
--- a/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/classloader/ClassWithOptions.java
+++ b/mobile/android/annotations/src/main/java/org/mozilla/gecko/annotationProcessors/classloader/ClassWithOptions.java
@@ -1,17 +1,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.annotationProcessors.classloader;
 
+import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+
 public class ClassWithOptions {
     public final Class<?> wrappedClass;
     public final String generatedName;
     public final String ifdef;
 
     public ClassWithOptions(Class<?> someClass, String name, String ifdef) {
         wrappedClass = someClass;
         generatedName = name;
         this.ifdef = ifdef;
     }
+
+    public boolean hasGenerated() {
+        final GeneratableElementIterator methodIterator
+                = new GeneratableElementIterator(this);
+
+        if (methodIterator.hasNext()) {
+            return true;
+        }
+
+        final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
+        for (ClassWithOptions innerClass : innerClasses) {
+            if (innerClass.hasGenerated()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
 }
--- a/widget/android/moz.build
+++ b/widget/android/moz.build
@@ -21,30 +21,94 @@ XPIDL_SOURCES += [
 ]
 
 XPIDL_MODULE = 'widget_android'
 
 EXPORTS += [
     'AndroidBridge.h',
 ]
 
-EXPORTS += [
-    '!GeneratedJNINatives.h',
-    '!GeneratedJNIWrappers.h',
+classes_with_WrapForJNI = [
+    'AndroidGamepadManager',
+    'Base64Utils',
+    'Clipboard',
+    'CodecProxy',
+    'EventCallback',
+    'EventDispatcher',
+    'GeckoAppShell',
+    'GeckoAudioInfo',
+    'GeckoBatteryManager',
+    'GeckoBundle',
+    'GeckoEditableChild',
+    'GeckoHLSDemuxerWrapper',
+    'GeckoHLSResourceWrapper',
+    'GeckoHLSSample',
+    'GeckoInputStream',
+    'GeckoJavaSampler',
+    'GeckoNetworkManager',
+    'GeckoProcessManager',
+    'GeckoResult',
+    'GeckoRuntime',
+    'GeckoScreenOrientation',
+    'GeckoServiceChildProcess',
+    'GeckoSession',
+    'GeckoSurface',
+    'GeckoSurfaceTexture',
+    'GeckoSystemStateListener',
+    'GeckoThread',
+    'GeckoVRManager',
+    'GeckoVideoInfo',
+    'GeckoWebExecutor',
+    'HardwareCodecCapabilityUtils',
+    'ImageDecoder',
+    'MediaDrmProxy',
+    'PanZoomController',
+    'PrefsHelper',
+    'RuntimeTelemetry',
+    'Sample',
+    'SampleBuffer',
+    'ScreenManagerHelper',
+    'SessionAccessibility',
+    'SessionKeyInfo',
+    'SessionTextInput',
+    'SpeechSynthesisService',
+    'StackScroller',
+    'SurfaceAllocator',
+    'SurfaceTextureListener',
+    'TelemetryUtils',
+    'VsyncSource',
+    'WebAuthnTokenManager',
+    'WebMessage',
+    'WebNotification',
+    'WebNotificationDelegate',
+    'WebRequest',
+    'WebRequestError',
+    'WebResponse',
+    'XPCOMEventTarget',
 ]
 
+headers_from_WrapForJNI = sorted(
+    ['Generated{}JNINatives.h'.format(c) for c in classes_with_WrapForJNI] +
+    ['Generated{}JNIWrappers.h'.format(c) for c in classes_with_WrapForJNI])
+
+sources_from_WrapForJNI = sorted(
+    'Generated{}JNIWrappers.cpp'.format(c) for c in classes_with_WrapForJNI)
+
 EXPORTS.mozilla.widget += [
     'AndroidCompositorWidget.h',
     'AndroidUiThread.h',
     'EventDispatcher.h',
     'nsWindow.h',
 ]
 
+EXPORTS += ['!{}'.format(c) for c in headers_from_WrapForJNI]
+
+SOURCES += ['!{}'.format(c) for c in sources_from_WrapForJNI]
+
 SOURCES += [
-    '!GeneratedJNIWrappers.cpp',
     'MediaKeysEventSourceFactory.cpp',
 ]
 
 UNIFIED_SOURCES += [
     'AndroidAlerts.cpp',
     'AndroidBridge.cpp',
     'AndroidCompositorWidget.cpp',
     'AndroidContentController.cpp',
@@ -74,19 +138,21 @@ XPCOM_MANIFESTS += [
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 # The recursive make backend treats the first output specially: it's passed as
 # an open FileAvoidWrite to the invoked script.  That doesn't work well with
 # the Gradle task that generates all of the outputs, so we add a dummy first
 # output.
-GeneratedFile(
-    'generated_jni_wrappers', 'GeneratedJNINatives.h', 'GeneratedJNIWrappers.h',
-    'GeneratedJNIWrappers.cpp', script='/mobile/android/gradle.py',
+
+t = tuple(['generated_jni_wrappers'] + headers_from_WrapForJNI + sources_from_WrapForJNI)
+
+GeneratedFile(*t,
+    script='/mobile/android/gradle.py',
     entry_point='generate_generated_jni_wrappers')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/dom/system/android',