OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Extracts native methods from a Java file and generates the JNI bindings. | 6 """Extracts native methods from a Java file and generates the JNI bindings. |
7 If you change this, please run and update the tests.""" | 7 If you change this, please run and update the tests.""" |
8 | 8 |
9 import collections | 9 import collections |
10 import errno | 10 import errno |
(...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
723 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 723 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
724 } | 724 } |
725 ret += [template.substitute(values)] | 725 ret += [template.substitute(values)] |
726 return '\n'.join(ret) | 726 return '\n'.join(ret) |
727 | 727 |
728 def GetForwardDeclarationsString(self): | 728 def GetForwardDeclarationsString(self): |
729 ret = [] | 729 ret = [] |
730 for native in self.natives: | 730 for native in self.natives: |
731 if native.type != 'method': | 731 if native.type != 'method': |
732 ret += [self.GetForwardDeclaration(native)] | 732 ret += [self.GetForwardDeclaration(native)] |
733 if self.options.native_exports and ret != []: | |
734 return '\nextern "C" {\n' + "\n".join(ret) + "\n};" | |
bulach
2014/04/14 13:16:02
nit: use '\n' instead of "\n" in the second string
ostap
2014/04/15 23:30:20
Done.
| |
733 return '\n'.join(ret) | 735 return '\n'.join(ret) |
734 | 736 |
735 def GetConstantFieldsString(self): | 737 def GetConstantFieldsString(self): |
736 if not self.constant_fields: | 738 if not self.constant_fields: |
737 return '' | 739 return '' |
738 ret = ['enum Java_%s_constant_fields {' % self.class_name] | 740 ret = ['enum Java_%s_constant_fields {' % self.class_name] |
739 for c in self.constant_fields: | 741 for c in self.constant_fields: |
740 ret += [' %s = %s,' % (c.name, c.value)] | 742 ret += [' %s = %s,' % (c.name, c.value)] |
741 ret += ['};'] | 743 ret += ['};'] |
742 return '\n'.join(ret) | 744 return '\n'.join(ret) |
743 | 745 |
744 def GetMethodStubsString(self): | 746 def GetMethodStubsString(self): |
745 """Returns the code corresponding to method stubs.""" | 747 """Returns the code corresponding to method stubs.""" |
746 ret = [] | 748 ret = [] |
747 for native in self.natives: | 749 for native in self.natives: |
748 if native.type == 'method': | 750 if native.type == 'method': |
749 ret += [self.GetNativeMethodStubString(native)] | 751 ret += [self.GetNativeMethodStubString(native)] |
750 if self.options.eager_called_by_natives: | 752 if self.options.eager_called_by_natives: |
751 ret += self.GetEagerCalledByNativeMethodStubs() | 753 ret += self.GetEagerCalledByNativeMethodStubs() |
752 else: | 754 else: |
753 ret += self.GetLazyCalledByNativeMethodStubs() | 755 ret += self.GetLazyCalledByNativeMethodStubs() |
756 | |
757 if self.options.native_exports and ret != []: | |
758 return '\nextern "C" {\n' + "\n".join(ret) + "\n};" | |
754 return '\n'.join(ret) | 759 return '\n'.join(ret) |
755 | 760 |
756 def GetLazyCalledByNativeMethodStubs(self): | 761 def GetLazyCalledByNativeMethodStubs(self): |
757 return [self.GetLazyCalledByNativeMethodStub(called_by_native) | 762 return [self.GetLazyCalledByNativeMethodStub(called_by_native) |
758 for called_by_native in self.called_by_natives] | 763 for called_by_native in self.called_by_natives] |
759 | 764 |
760 def GetEagerCalledByNativeMethodStubs(self): | 765 def GetEagerCalledByNativeMethodStubs(self): |
761 ret = [] | 766 ret = [] |
762 if self.called_by_natives: | 767 if self.called_by_natives: |
763 ret += ['namespace {'] | 768 ret += ['namespace {'] |
(...skipping 25 matching lines...) Expand all Loading... | |
789 kmethods = self.GetKMethodsString(clazz) | 794 kmethods = self.GetKMethodsString(clazz) |
790 if kmethods: | 795 if kmethods: |
791 values = {'JAVA_CLASS': clazz, | 796 values = {'JAVA_CLASS': clazz, |
792 'KMETHODS': kmethods} | 797 'KMETHODS': kmethods} |
793 ret += [template.substitute(values)] | 798 ret += [template.substitute(values)] |
794 if not ret: return '' | 799 if not ret: return '' |
795 return '\n' + '\n'.join(ret) | 800 return '\n' + '\n'.join(ret) |
796 | 801 |
797 def GetJNINativeMethodsString(self): | 802 def GetJNINativeMethodsString(self): |
798 """Returns the implementation of the array of native methods.""" | 803 """Returns the implementation of the array of native methods.""" |
804 if self.options.native_exports: | |
805 return '' | |
799 template = Template("""\ | 806 template = Template("""\ |
800 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 807 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
801 ${KMETHODS} | 808 ${KMETHODS} |
802 }; | 809 }; |
803 """) | 810 """) |
804 return self.SubstituteNativeMethods(template) | 811 return self.SubstituteNativeMethods(template) |
805 | 812 |
806 def GetRegisterCalledByNativesImplString(self): | 813 def GetRegisterCalledByNativesImplString(self): |
807 """Returns the code for registering the called by native methods.""" | 814 """Returns the code for registering the called by native methods.""" |
808 if not self.options.eager_called_by_natives: | 815 if not self.options.eager_called_by_natives: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
843 called_by_natives = self.GetRegisterCalledByNativesImplString() | 850 called_by_natives = self.GetRegisterCalledByNativesImplString() |
844 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 851 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
845 'CLASSES': self.GetFindClasses(), | 852 'CLASSES': self.GetFindClasses(), |
846 'NATIVES': natives, | 853 'NATIVES': natives, |
847 'CALLED_BY_NATIVES': called_by_natives, | 854 'CALLED_BY_NATIVES': called_by_natives, |
848 } | 855 } |
849 return template.substitute(values) | 856 return template.substitute(values) |
850 | 857 |
851 def GetRegisterNativesImplString(self): | 858 def GetRegisterNativesImplString(self): |
852 """Returns the shared implementation for RegisterNatives.""" | 859 """Returns the shared implementation for RegisterNatives.""" |
860 if self.options.native_exports: | |
861 return '' | |
862 | |
853 template = Template("""\ | 863 template = Template("""\ |
854 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 864 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
855 | 865 |
856 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, | 866 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, |
857 kMethods${JAVA_CLASS}, | 867 kMethods${JAVA_CLASS}, |
858 kMethods${JAVA_CLASS}Size) < 0) { | 868 kMethods${JAVA_CLASS}Size) < 0) { |
859 jni_generator::HandleRegistrationError( | 869 jni_generator::HandleRegistrationError( |
860 env, g_${JAVA_CLASS}_clazz, __FILE__); | 870 env, g_${JAVA_CLASS}_clazz, __FILE__); |
861 return false; | 871 return false; |
862 } | 872 } |
863 """) | 873 """) |
864 return self.SubstituteNativeMethods(template) | 874 return self.SubstituteNativeMethods(template) |
865 | 875 |
866 def GetJNIRegisterNativesString(self): | 876 def GetJNIRegisterNativesString(self): |
867 """Returns the implementation for the JNI registration of native methods.""" | 877 """Returns the implementation for the JNI registration of native methods.""" |
868 if not self.init_native: | 878 if self.options.native_exports or not self.init_native: |
869 return '' | 879 return '' |
870 | 880 |
871 template = Template("""\ | 881 template = Template("""\ |
872 extern "C" JNIEXPORT bool JNICALL | 882 extern "C" JNIEXPORT bool JNICALL |
873 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { | 883 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { |
874 return ${NAMESPACE}RegisterNativesImpl(env, clazz); | 884 return ${NAMESPACE}RegisterNativesImpl(env, clazz); |
875 } | 885 } |
876 """) | 886 """) |
877 fully_qualified_class = self.fully_qualified_class.replace('/', '_') | 887 fully_qualified_class = self.fully_qualified_class.replace('/', '_') |
878 namespace = '' | 888 namespace = '' |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
924 [JavaDataTypeToC(param.datatype) + ' ' + | 934 [JavaDataTypeToC(param.datatype) + ' ' + |
925 param.name | 935 param.name |
926 for param in native.params]) | 936 for param in native.params]) |
927 | 937 |
928 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 938 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
929 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + | 939 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + |
930 param.name | 940 param.name |
931 for param in called_by_native.params]) | 941 for param in called_by_native.params]) |
932 | 942 |
933 def GetForwardDeclaration(self, native): | 943 def GetForwardDeclaration(self, native): |
934 template = Template(""" | 944 template_str = """ |
935 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 945 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
936 """) | 946 """ |
947 if self.options.native_exports: | |
948 template_str += """ | |
949 __attribute__((alias("${NAME}"), visibility("default"))) ${RETURN} | |
bulach
2014/04/14 13:16:02
nit: move the ${RETURN} to the next line and put i
ostap
2014/04/15 23:30:20
Done.
| |
950 Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}); | |
951 """ | |
952 template = Template(template_str) | |
953 | |
954 java_name = JniParams.RemapClassName(self.fully_qualified_class).replace('_' , '_1').replace('/', '_') | |
bulach
2014/04/14 13:16:02
nit: >80cols, suggest:
java_name = java_name = Jni
ostap
2014/04/15 23:30:20
Done.
| |
955 if native.java_class_name: | |
956 java_name += "_00024" + native.java_class_name | |
bulach
2014/04/14 13:16:02
nit: s/"/'/
ostap
2014/04/15 23:30:20
Done.
| |
957 | |
937 values = {'RETURN': JavaDataTypeToC(native.return_type), | 958 values = {'RETURN': JavaDataTypeToC(native.return_type), |
938 'NAME': native.name, | 959 'NAME': native.name, |
960 'JAVA_NAME': java_name, | |
939 'PARAMS': self.GetParamsInDeclaration(native)} | 961 'PARAMS': self.GetParamsInDeclaration(native)} |
940 return template.substitute(values) | 962 return template.substitute(values) |
941 | 963 |
942 def GetNativeMethodStubString(self, native): | 964 def GetNativeMethodStubString(self, native): |
943 """Returns stubs for native methods.""" | 965 """Returns stubs for native methods.""" |
944 template = Template("""\ | 966 template_str = """\ |
945 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { | 967 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { |
946 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 968 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
947 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 969 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
948 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 970 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
949 } | 971 } |
950 """) | 972 """ |
973 if self.options.native_exports: | |
974 template_str += """ | |
975 __attribute__((alias("${NAME}"), visibility("default"))) | |
976 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, | |
bulach
2014/04/14 13:16:02
nit: unindent this line
ostap
2014/04/15 23:30:20
Done.
| |
977 ${PARAMS_IN_DECLARATION}); | |
978 """ | |
979 template = Template(template_str) | |
951 params = [] | 980 params = [] |
952 if not self.options.pure_native_methods: | 981 if not self.options.pure_native_methods: |
953 params = ['env', 'jcaller'] | 982 params = ['env', 'jcaller'] |
954 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 983 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
955 | 984 |
956 return_type = JavaDataTypeToC(native.return_type) | 985 return_type = JavaDataTypeToC(native.return_type) |
957 optional_error_return = JavaReturnValueToC(native.return_type) | 986 optional_error_return = JavaReturnValueToC(native.return_type) |
958 if optional_error_return: | 987 if optional_error_return: |
959 optional_error_return = ', ' + optional_error_return | 988 optional_error_return = ', ' + optional_error_return |
960 post_call = '' | 989 post_call = '' |
961 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 990 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
962 post_call = '.Release()' | 991 post_call = '.Release()' |
992 | |
993 if self.options.native_exports: | |
994 java_name = JniParams.RemapClassName(self.fully_qualified_class).replace(' _', '_1').replace('/', '_') | |
bulach
2014/04/14 13:16:02
nit: as above, >80 cols
ostap
2014/04/15 23:30:20
Done.
| |
995 if native.java_class_name: | |
996 java_name += "_00024" + native.java_class_name | |
bulach
2014/04/14 13:16:02
nit: s/"/'/ and below in 998
ostap
2014/04/15 23:30:20
Done.
| |
997 else: | |
998 java_name = "" | |
999 | |
963 values = { | 1000 values = { |
964 'RETURN': return_type, | 1001 'RETURN': return_type, |
965 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1002 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1003 'JAVA_NAME': java_name, | |
966 'NAME': native.name, | 1004 'NAME': native.name, |
967 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1005 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
968 'PARAM0_NAME': native.params[0].name, | 1006 'PARAM0_NAME': native.params[0].name, |
969 'P0_TYPE': native.p0_type, | 1007 'P0_TYPE': native.p0_type, |
970 'PARAMS_IN_CALL': params_in_call, | 1008 'PARAMS_IN_CALL': params_in_call, |
971 'POST_CALL': post_call | 1009 'POST_CALL': post_call |
972 } | 1010 } |
973 return template.substitute(values) | 1011 return template.substitute(values) |
974 | 1012 |
975 def GetCalledByNativeValues(self, called_by_native): | 1013 def GetCalledByNativeValues(self, called_by_native): |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1095 ret[class_name] = jni_class_path | 1133 ret[class_name] = jni_class_path |
1096 return ret | 1134 return ret |
1097 | 1135 |
1098 def GetClassPathDefinitions(self): | 1136 def GetClassPathDefinitions(self): |
1099 """Returns the ClassPath constants.""" | 1137 """Returns the ClassPath constants.""" |
1100 ret = [] | 1138 ret = [] |
1101 template = Template("""\ | 1139 template = Template("""\ |
1102 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1140 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
1103 native_classes = self.GetUniqueClasses(self.natives) | 1141 native_classes = self.GetUniqueClasses(self.natives) |
1104 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1142 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) |
1105 all_classes = native_classes | 1143 if self.options.native_exports: |
1106 all_classes.update(called_by_native_classes) | 1144 all_classes = called_by_native_classes |
1145 loop_classes = all_classes | |
1146 else: | |
1147 all_classes = native_classes | |
1148 all_classes.update(called_by_native_classes) | |
1149 loop_classes = called_by_native_classes | |
1150 | |
1107 for clazz in all_classes: | 1151 for clazz in all_classes: |
1108 values = { | 1152 values = { |
1109 'JAVA_CLASS': clazz, | 1153 'JAVA_CLASS': clazz, |
1110 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), | 1154 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), |
1111 } | 1155 } |
1112 ret += [template.substitute(values)] | 1156 ret += [template.substitute(values)] |
1113 ret += '' | 1157 ret += '' |
1114 for clazz in called_by_native_classes: | 1158 for clazz in loop_classes: |
1115 template = Template("""\ | 1159 template = Template("""\ |
1116 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1160 // Leaking this jclass as we cannot use LazyInstance from some threads. |
1117 jclass g_${JAVA_CLASS}_clazz = NULL;""") | 1161 jclass g_${JAVA_CLASS}_clazz = NULL;""") |
1118 values = { | 1162 values = { |
1119 'JAVA_CLASS': clazz, | 1163 'JAVA_CLASS': clazz, |
1120 } | 1164 } |
1121 ret += [template.substitute(values)] | 1165 ret += [template.substitute(values)] |
1122 return '\n'.join(ret) | 1166 return '\n'.join(ret) |
1123 | 1167 |
1124 def GetFindClasses(self): | 1168 def GetFindClasses(self): |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1315 'will limit the initialization to only the ' | 1359 'will limit the initialization to only the ' |
1316 'top-level class.') | 1360 'top-level class.') |
1317 option_parser.add_option('--eager_called_by_natives', | 1361 option_parser.add_option('--eager_called_by_natives', |
1318 action='store_true', dest='eager_called_by_natives', | 1362 action='store_true', dest='eager_called_by_natives', |
1319 help='When true, the called-by-native methods will ' | 1363 help='When true, the called-by-native methods will ' |
1320 'be initialized in a non-atomic way.') | 1364 'be initialized in a non-atomic way.') |
1321 option_parser.add_option('--cpp', default='cpp', | 1365 option_parser.add_option('--cpp', default='cpp', |
1322 help='The path to cpp command.') | 1366 help='The path to cpp command.') |
1323 option_parser.add_option('--javap', default='javap', | 1367 option_parser.add_option('--javap', default='javap', |
1324 help='The path to javap command.') | 1368 help='The path to javap command.') |
1369 option_parser.add_option('--native_exports', | |
1370 action='store_true', dest='native_exports', | |
bulach
2014/04/14 13:16:02
nit: no need for dest
ostap
2014/04/15 23:30:20
Done.
| |
1371 help='Native method registration through .so ' | |
1372 'exports.') | |
1325 options, args = option_parser.parse_args(argv) | 1373 options, args = option_parser.parse_args(argv) |
1326 if options.jar_file: | 1374 if options.jar_file: |
1327 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1375 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1328 options.output_dir) | 1376 options.output_dir) |
1329 elif options.input_file: | 1377 elif options.input_file: |
1330 input_file = options.input_file | 1378 input_file = options.input_file |
1331 else: | 1379 else: |
1332 option_parser.print_help() | 1380 option_parser.print_help() |
1333 print '\nError: Must specify --jar_file or --input_file.' | 1381 print '\nError: Must specify --jar_file or --input_file.' |
1334 return 1 | 1382 return 1 |
1335 output_file = None | 1383 output_file = None |
1336 if options.output_dir: | 1384 if options.output_dir: |
1337 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1385 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1338 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1386 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1339 if options.jarjar: | 1387 if options.jarjar: |
1340 with open(options.jarjar) as f: | 1388 with open(options.jarjar) as f: |
1341 JniParams.SetJarJarMappings(f.read()) | 1389 JniParams.SetJarJarMappings(f.read()) |
1342 GenerateJNIHeader(input_file, output_file, options) | 1390 GenerateJNIHeader(input_file, output_file, options) |
1343 | 1391 |
1344 | 1392 |
1345 if __name__ == '__main__': | 1393 if __name__ == '__main__': |
1346 sys.exit(main(sys.argv)) | 1394 sys.exit(main(sys.argv)) |
OLD | NEW |