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 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
729 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 729 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
730 } | 730 } |
731 ret += [template.substitute(values)] | 731 ret += [template.substitute(values)] |
732 return '\n'.join(ret) | 732 return '\n'.join(ret) |
733 | 733 |
734 def GetForwardDeclarationsString(self): | 734 def GetForwardDeclarationsString(self): |
735 ret = [] | 735 ret = [] |
736 for native in self.natives: | 736 for native in self.natives: |
737 if native.type != 'method': | 737 if native.type != 'method': |
738 ret += [self.GetForwardDeclaration(native)] | 738 ret += [self.GetForwardDeclaration(native)] |
739 if self.options.native_exports and ret: | |
740 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' | |
739 return '\n'.join(ret) | 741 return '\n'.join(ret) |
740 | 742 |
741 def GetConstantFieldsString(self): | 743 def GetConstantFieldsString(self): |
742 if not self.constant_fields: | 744 if not self.constant_fields: |
743 return '' | 745 return '' |
744 ret = ['enum Java_%s_constant_fields {' % self.class_name] | 746 ret = ['enum Java_%s_constant_fields {' % self.class_name] |
745 for c in self.constant_fields: | 747 for c in self.constant_fields: |
746 ret += [' %s = %s,' % (c.name, c.value)] | 748 ret += [' %s = %s,' % (c.name, c.value)] |
747 ret += ['};'] | 749 ret += ['};'] |
748 return '\n'.join(ret) | 750 return '\n'.join(ret) |
749 | 751 |
750 def GetMethodStubsString(self): | 752 def GetMethodStubsString(self): |
751 """Returns the code corresponding to method stubs.""" | 753 """Returns the code corresponding to method stubs.""" |
752 ret = [] | 754 ret = [] |
753 for native in self.natives: | 755 for native in self.natives: |
754 if native.type == 'method': | 756 if native.type == 'method': |
755 ret += [self.GetNativeMethodStubString(native)] | 757 ret += [self.GetNativeMethodStubString(native)] |
756 if self.options.eager_called_by_natives: | 758 if self.options.eager_called_by_natives: |
757 ret += self.GetEagerCalledByNativeMethodStubs() | 759 ret += self.GetEagerCalledByNativeMethodStubs() |
758 else: | 760 else: |
759 ret += self.GetLazyCalledByNativeMethodStubs() | 761 ret += self.GetLazyCalledByNativeMethodStubs() |
762 | |
763 if self.options.native_exports and ret: | |
764 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' | |
760 return '\n'.join(ret) | 765 return '\n'.join(ret) |
761 | 766 |
762 def GetLazyCalledByNativeMethodStubs(self): | 767 def GetLazyCalledByNativeMethodStubs(self): |
763 return [self.GetLazyCalledByNativeMethodStub(called_by_native) | 768 return [self.GetLazyCalledByNativeMethodStub(called_by_native) |
764 for called_by_native in self.called_by_natives] | 769 for called_by_native in self.called_by_natives] |
765 | 770 |
766 def GetEagerCalledByNativeMethodStubs(self): | 771 def GetEagerCalledByNativeMethodStubs(self): |
767 ret = [] | 772 ret = [] |
768 if self.called_by_natives: | 773 if self.called_by_natives: |
769 ret += ['namespace {'] | 774 ret += ['namespace {'] |
(...skipping 25 matching lines...) Expand all Loading... | |
795 kmethods = self.GetKMethodsString(clazz) | 800 kmethods = self.GetKMethodsString(clazz) |
796 if kmethods: | 801 if kmethods: |
797 values = {'JAVA_CLASS': clazz, | 802 values = {'JAVA_CLASS': clazz, |
798 'KMETHODS': kmethods} | 803 'KMETHODS': kmethods} |
799 ret += [template.substitute(values)] | 804 ret += [template.substitute(values)] |
800 if not ret: return '' | 805 if not ret: return '' |
801 return '\n' + '\n'.join(ret) | 806 return '\n' + '\n'.join(ret) |
802 | 807 |
803 def GetJNINativeMethodsString(self): | 808 def GetJNINativeMethodsString(self): |
804 """Returns the implementation of the array of native methods.""" | 809 """Returns the implementation of the array of native methods.""" |
810 if self.options.native_exports: | |
811 return '' | |
805 template = Template("""\ | 812 template = Template("""\ |
806 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 813 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
807 ${KMETHODS} | 814 ${KMETHODS} |
808 }; | 815 }; |
809 """) | 816 """) |
810 return self.SubstituteNativeMethods(template) | 817 return self.SubstituteNativeMethods(template) |
811 | 818 |
812 def GetRegisterCalledByNativesImplString(self): | 819 def GetRegisterCalledByNativesImplString(self): |
813 """Returns the code for registering the called by native methods.""" | 820 """Returns the code for registering the called by native methods.""" |
814 if not self.options.eager_called_by_natives: | 821 if not self.options.eager_called_by_natives: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
849 called_by_natives = self.GetRegisterCalledByNativesImplString() | 856 called_by_natives = self.GetRegisterCalledByNativesImplString() |
850 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 857 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
851 'CLASSES': self.GetFindClasses(), | 858 'CLASSES': self.GetFindClasses(), |
852 'NATIVES': natives, | 859 'NATIVES': natives, |
853 'CALLED_BY_NATIVES': called_by_natives, | 860 'CALLED_BY_NATIVES': called_by_natives, |
854 } | 861 } |
855 return template.substitute(values) | 862 return template.substitute(values) |
856 | 863 |
857 def GetRegisterNativesImplString(self): | 864 def GetRegisterNativesImplString(self): |
858 """Returns the shared implementation for RegisterNatives.""" | 865 """Returns the shared implementation for RegisterNatives.""" |
866 if self.options.native_exports: | |
867 return '' | |
868 | |
859 template = Template("""\ | 869 template = Template("""\ |
860 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 870 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
861 | 871 |
862 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, | 872 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, |
863 kMethods${JAVA_CLASS}, | 873 kMethods${JAVA_CLASS}, |
864 kMethods${JAVA_CLASS}Size) < 0) { | 874 kMethods${JAVA_CLASS}Size) < 0) { |
865 jni_generator::HandleRegistrationError( | 875 jni_generator::HandleRegistrationError( |
866 env, g_${JAVA_CLASS}_clazz, __FILE__); | 876 env, g_${JAVA_CLASS}_clazz, __FILE__); |
867 return false; | 877 return false; |
868 } | 878 } |
869 """) | 879 """) |
870 return self.SubstituteNativeMethods(template) | 880 return self.SubstituteNativeMethods(template) |
871 | 881 |
872 def GetJNIRegisterNativesString(self): | 882 def GetJNIRegisterNativesString(self): |
873 """Returns the implementation for the JNI registration of native methods.""" | 883 """Returns the implementation for the JNI registration of native methods.""" |
874 if not self.init_native: | 884 if not self.init_native: |
875 return '' | 885 return '' |
876 | 886 |
877 template = Template("""\ | 887 template = Template("""\ |
878 extern "C" JNIEXPORT bool JNICALL | 888 extern "C" JNIEXPORT bool JNICALL |
879 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { | 889 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { |
880 return ${NAMESPACE}RegisterNativesImpl(env, clazz); | 890 return ${NAMESPACE}RegisterNativesImpl(env, clazz); |
881 } | 891 } |
882 """) | 892 """) |
883 fully_qualified_class = self.fully_qualified_class.replace('/', '_') | 893 |
894 if self.options.native_exports: | |
895 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
896 java_name = java_name.replace('_', '_1').replace('/', '_') | |
897 else: | |
898 java_name = self.fully_qualified_class.replace('/', '_') | |
899 | |
884 namespace = '' | 900 namespace = '' |
885 if self.namespace: | 901 if self.namespace: |
886 namespace = self.namespace + '::' | 902 namespace = self.namespace + '::' |
887 values = {'FULLY_QUALIFIED_CLASS': fully_qualified_class, | 903 values = {'FULLY_QUALIFIED_CLASS': java_name, |
888 'INIT_NATIVE_NAME': 'native' + self.init_native.name, | 904 'INIT_NATIVE_NAME': 'native' + self.init_native.name, |
889 'NAMESPACE': namespace, | 905 'NAMESPACE': namespace, |
890 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() | 906 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() |
891 } | 907 } |
892 return template.substitute(values) | 908 return template.substitute(values) |
893 | 909 |
894 def GetOpenNamespaceString(self): | 910 def GetOpenNamespaceString(self): |
895 if self.namespace: | 911 if self.namespace: |
896 all_namespaces = ['namespace %s {' % ns | 912 all_namespaces = ['namespace %s {' % ns |
897 for ns in self.namespace.split('::')] | 913 for ns in self.namespace.split('::')] |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
930 [JavaDataTypeToC(param.datatype) + ' ' + | 946 [JavaDataTypeToC(param.datatype) + ' ' + |
931 param.name | 947 param.name |
932 for param in native.params]) | 948 for param in native.params]) |
933 | 949 |
934 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 950 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
935 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + | 951 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + |
936 param.name | 952 param.name |
937 for param in called_by_native.params]) | 953 for param in called_by_native.params]) |
938 | 954 |
939 def GetForwardDeclaration(self, native): | 955 def GetForwardDeclaration(self, native): |
940 template = Template(""" | 956 template_str = """ |
941 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 957 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
942 """) | 958 """ |
959 if self.options.native_exports: | |
960 template_str += """ | |
961 __attribute__((visibility("default"))) | |
962 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) { | |
963 return ${NAME}(${PARAMS_IN_CALL}); | |
964 } | |
965 """ | |
966 template = Template(template_str) | |
967 params_in_call = [] | |
968 if not self.options.pure_native_methods: | |
969 params_in_call = ['env', 'jcaller'] | |
970 params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) | |
971 | |
972 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
973 java_name = java_name.replace('_', '_1').replace('/', '_') | |
974 if native.java_class_name: | |
975 java_name += '_00024' + native.java_class_name | |
Yaron
2014/04/22 02:43:08
Why is this logic not needed in GetJNIRegisterNati
ostap
2014/04/24 03:58:43
SoOn 2014/04/22 02:43:08, Yaron wrote:
ostap
2014/04/24 14:10:00
Actually, RegisterNatives will never be in inner c
| |
976 | |
943 values = {'RETURN': JavaDataTypeToC(native.return_type), | 977 values = {'RETURN': JavaDataTypeToC(native.return_type), |
944 'NAME': native.name, | 978 'NAME': native.name, |
945 'PARAMS': self.GetParamsInDeclaration(native)} | 979 'JAVA_NAME': java_name, |
980 'PARAMS': self.GetParamsInDeclaration(native), | |
981 'PARAMS_IN_CALL': params_in_call} | |
946 return template.substitute(values) | 982 return template.substitute(values) |
947 | 983 |
948 def GetNativeMethodStubString(self, native): | 984 def GetNativeMethodStubString(self, native): |
949 """Returns stubs for native methods.""" | 985 """Returns stubs for native methods.""" |
950 template = Template("""\ | 986 if self.options.native_exports: |
951 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { | 987 template_str = """\ |
988 __attribute__((visibility("default"))) | |
989 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, | |
990 ${PARAMS_IN_DECLARATION}) {""" | |
991 else: | |
992 template_str = """\ | |
993 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" | |
994 template_str += """ | |
952 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 995 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
953 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 996 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
954 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 997 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
955 } | 998 } |
956 """) | 999 """ |
1000 | |
1001 template = Template(template_str) | |
957 params = [] | 1002 params = [] |
958 if not self.options.pure_native_methods: | 1003 if not self.options.pure_native_methods: |
959 params = ['env', 'jcaller'] | 1004 params = ['env', 'jcaller'] |
960 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 1005 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
961 | 1006 |
962 return_type = JavaDataTypeToC(native.return_type) | 1007 return_type = JavaDataTypeToC(native.return_type) |
963 optional_error_return = JavaReturnValueToC(native.return_type) | 1008 optional_error_return = JavaReturnValueToC(native.return_type) |
964 if optional_error_return: | 1009 if optional_error_return: |
965 optional_error_return = ', ' + optional_error_return | 1010 optional_error_return = ', ' + optional_error_return |
966 post_call = '' | 1011 post_call = '' |
967 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 1012 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
968 post_call = '.Release()' | 1013 post_call = '.Release()' |
1014 | |
1015 if self.options.native_exports: | |
1016 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
1017 java_name = java_name.replace('_', '_1').replace('/', '_') | |
1018 if native.java_class_name: | |
1019 java_name += '_00024' + native.java_class_name | |
1020 else: | |
1021 java_name = '' | |
1022 | |
969 values = { | 1023 values = { |
970 'RETURN': return_type, | 1024 'RETURN': return_type, |
971 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1025 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1026 'JAVA_NAME': java_name, | |
972 'NAME': native.name, | 1027 'NAME': native.name, |
973 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1028 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
974 'PARAM0_NAME': native.params[0].name, | 1029 'PARAM0_NAME': native.params[0].name, |
975 'P0_TYPE': native.p0_type, | 1030 'P0_TYPE': native.p0_type, |
976 'PARAMS_IN_CALL': params_in_call, | 1031 'PARAMS_IN_CALL': params_in_call, |
977 'POST_CALL': post_call | 1032 'POST_CALL': post_call |
978 } | 1033 } |
979 return template.substitute(values) | 1034 return template.substitute(values) |
980 | 1035 |
981 def GetCalledByNativeValues(self, called_by_native): | 1036 def GetCalledByNativeValues(self, called_by_native): |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1101 ret[class_name] = jni_class_path | 1156 ret[class_name] = jni_class_path |
1102 return ret | 1157 return ret |
1103 | 1158 |
1104 def GetClassPathDefinitions(self): | 1159 def GetClassPathDefinitions(self): |
1105 """Returns the ClassPath constants.""" | 1160 """Returns the ClassPath constants.""" |
1106 ret = [] | 1161 ret = [] |
1107 template = Template("""\ | 1162 template = Template("""\ |
1108 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1163 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
1109 native_classes = self.GetUniqueClasses(self.natives) | 1164 native_classes = self.GetUniqueClasses(self.natives) |
1110 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1165 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) |
1111 all_classes = native_classes | 1166 if self.options.native_exports: |
1112 all_classes.update(called_by_native_classes) | 1167 all_classes = called_by_native_classes |
1168 else: | |
1169 all_classes = native_classes | |
1170 all_classes.update(called_by_native_classes) | |
1171 | |
1113 for clazz in all_classes: | 1172 for clazz in all_classes: |
1114 values = { | 1173 values = { |
1115 'JAVA_CLASS': clazz, | 1174 'JAVA_CLASS': clazz, |
1116 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), | 1175 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), |
1117 } | 1176 } |
1118 ret += [template.substitute(values)] | 1177 ret += [template.substitute(values)] |
1119 ret += '' | 1178 ret += '' |
1120 for clazz in called_by_native_classes: | 1179 for clazz in called_by_native_classes: |
1121 template = Template("""\ | 1180 template = Template("""\ |
1122 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1181 // Leaking this jclass as we cannot use LazyInstance from some threads. |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1321 'will limit the initialization to only the ' | 1380 'will limit the initialization to only the ' |
1322 'top-level class.') | 1381 'top-level class.') |
1323 option_parser.add_option('--eager_called_by_natives', | 1382 option_parser.add_option('--eager_called_by_natives', |
1324 action='store_true', dest='eager_called_by_natives', | 1383 action='store_true', dest='eager_called_by_natives', |
1325 help='When true, the called-by-native methods will ' | 1384 help='When true, the called-by-native methods will ' |
1326 'be initialized in a non-atomic way.') | 1385 'be initialized in a non-atomic way.') |
1327 option_parser.add_option('--cpp', default='cpp', | 1386 option_parser.add_option('--cpp', default='cpp', |
1328 help='The path to cpp command.') | 1387 help='The path to cpp command.') |
1329 option_parser.add_option('--javap', default='javap', | 1388 option_parser.add_option('--javap', default='javap', |
1330 help='The path to javap command.') | 1389 help='The path to javap command.') |
1390 option_parser.add_option('--native_exports', action='store_true', | |
1391 help='Native method registration through .so ' | |
1392 'exports.') | |
1331 options, args = option_parser.parse_args(argv) | 1393 options, args = option_parser.parse_args(argv) |
1332 if options.jar_file: | 1394 if options.jar_file: |
1333 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1395 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1334 options.output_dir) | 1396 options.output_dir) |
1335 elif options.input_file: | 1397 elif options.input_file: |
1336 input_file = options.input_file | 1398 input_file = options.input_file |
1337 else: | 1399 else: |
1338 option_parser.print_help() | 1400 option_parser.print_help() |
1339 print '\nError: Must specify --jar_file or --input_file.' | 1401 print '\nError: Must specify --jar_file or --input_file.' |
1340 return 1 | 1402 return 1 |
1341 output_file = None | 1403 output_file = None |
1342 if options.output_dir: | 1404 if options.output_dir: |
1343 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1405 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1344 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1406 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1345 if options.jarjar: | 1407 if options.jarjar: |
1346 with open(options.jarjar) as f: | 1408 with open(options.jarjar) as f: |
1347 JniParams.SetJarJarMappings(f.read()) | 1409 JniParams.SetJarJarMappings(f.read()) |
1348 GenerateJNIHeader(input_file, output_file, options) | 1410 GenerateJNIHeader(input_file, output_file, options) |
1349 | 1411 |
1350 | 1412 |
1351 if __name__ == '__main__': | 1413 if __name__ == '__main__': |
1352 sys.exit(main(sys.argv)) | 1414 sys.exit(main(sys.argv)) |
OLD | NEW |