Chromium Code Reviews| 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 != []: | |
|
bulach
2014/04/16 11:22:35
nit: no need for "!= []", this should be equivalen
ostap
2014/04/16 20:36:04
Done.
| |
| 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 != []: | |
|
bulach
2014/04/16 11:22:35
nit: as above, remove "!= []"
ostap
2014/04/16 20:36:04
Done.
| |
| 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 self.options.native_exports or 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 fully_qualified_class = self.fully_qualified_class.replace('/', '_') |
| 884 namespace = '' | 894 namespace = '' |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 930 [JavaDataTypeToC(param.datatype) + ' ' + | 940 [JavaDataTypeToC(param.datatype) + ' ' + |
| 931 param.name | 941 param.name |
| 932 for param in native.params]) | 942 for param in native.params]) |
| 933 | 943 |
| 934 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 944 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
| 935 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + | 945 return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + |
| 936 param.name | 946 param.name |
| 937 for param in called_by_native.params]) | 947 for param in called_by_native.params]) |
| 938 | 948 |
| 939 def GetForwardDeclaration(self, native): | 949 def GetForwardDeclaration(self, native): |
| 940 template = Template(""" | 950 template_str = """ |
| 941 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 951 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
| 942 """) | 952 """ |
| 953 if self.options.native_exports: | |
| 954 template_str += """ | |
| 955 __attribute__((visibility("default"))) | |
| 956 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) { | |
| 957 return ${NAME}(${PARAMS_IN_CALL}); | |
| 958 } | |
| 959 """ | |
| 960 template = Template(template_str) | |
| 961 params = [] | |
|
bulach
2014/04/16 11:22:35
nit: params_in_call ?
since there's a PARAMS in th
ostap
2014/04/16 20:36:04
Done.
| |
| 962 if not self.options.pure_native_methods: | |
| 963 params = ['env', 'jcaller'] | |
| 964 params_in_call = ', '.join(params + [p.name for p in native.params]) | |
| 965 | |
| 966 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
| 967 java_name = java_name.replace('_', '_1').replace('/', '_') | |
| 968 if native.java_class_name: | |
| 969 java_name += "_00024" + native.java_class_name | |
|
bulach
2014/04/16 11:22:35
nit: s/"/'/
ostap
2014/04/16 20:36:04
Done.
| |
| 970 | |
| 943 values = {'RETURN': JavaDataTypeToC(native.return_type), | 971 values = {'RETURN': JavaDataTypeToC(native.return_type), |
| 944 'NAME': native.name, | 972 'NAME': native.name, |
| 945 'PARAMS': self.GetParamsInDeclaration(native)} | 973 'JAVA_NAME': java_name, |
| 974 'PARAMS': self.GetParamsInDeclaration(native), | |
| 975 'PARAMS_IN_CALL': params_in_call} | |
| 946 return template.substitute(values) | 976 return template.substitute(values) |
| 947 | 977 |
| 948 def GetNativeMethodStubString(self, native): | 978 def GetNativeMethodStubString(self, native): |
| 949 """Returns stubs for native methods.""" | 979 """Returns stubs for native methods.""" |
| 950 template = Template("""\ | 980 if self.options.native_exports: |
| 951 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { | 981 template_str = """\ |
| 982 __attribute__((visibility("default"))) | |
| 983 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, | |
| 984 ${PARAMS_IN_DECLARATION}) {""" | |
| 985 else: | |
| 986 template_str = """\ | |
| 987 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" | |
| 988 template_str += """ | |
| 952 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 989 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
| 953 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 990 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
| 954 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 991 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
| 955 } | 992 } |
| 956 """) | 993 """ |
| 994 | |
| 995 template = Template(template_str) | |
| 957 params = [] | 996 params = [] |
| 958 if not self.options.pure_native_methods: | 997 if not self.options.pure_native_methods: |
| 959 params = ['env', 'jcaller'] | 998 params = ['env', 'jcaller'] |
| 960 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 999 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
| 961 | 1000 |
| 962 return_type = JavaDataTypeToC(native.return_type) | 1001 return_type = JavaDataTypeToC(native.return_type) |
| 963 optional_error_return = JavaReturnValueToC(native.return_type) | 1002 optional_error_return = JavaReturnValueToC(native.return_type) |
| 964 if optional_error_return: | 1003 if optional_error_return: |
| 965 optional_error_return = ', ' + optional_error_return | 1004 optional_error_return = ', ' + optional_error_return |
| 966 post_call = '' | 1005 post_call = '' |
| 967 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 1006 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
| 968 post_call = '.Release()' | 1007 post_call = '.Release()' |
| 1008 | |
| 1009 if self.options.native_exports: | |
| 1010 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
| 1011 java_name = java_name.replace('_', '_1').replace('/', '_') | |
| 1012 if native.java_class_name: | |
| 1013 java_name += '_00024' + native.java_class_name | |
| 1014 else: | |
| 1015 java_name = '' | |
| 1016 | |
| 969 values = { | 1017 values = { |
| 970 'RETURN': return_type, | 1018 'RETURN': return_type, |
| 971 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1019 'OPTIONAL_ERROR_RETURN': optional_error_return, |
| 1020 'JAVA_NAME': java_name, | |
| 972 'NAME': native.name, | 1021 'NAME': native.name, |
| 973 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1022 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
| 974 'PARAM0_NAME': native.params[0].name, | 1023 'PARAM0_NAME': native.params[0].name, |
| 975 'P0_TYPE': native.p0_type, | 1024 'P0_TYPE': native.p0_type, |
| 976 'PARAMS_IN_CALL': params_in_call, | 1025 'PARAMS_IN_CALL': params_in_call, |
| 977 'POST_CALL': post_call | 1026 'POST_CALL': post_call |
| 978 } | 1027 } |
| 979 return template.substitute(values) | 1028 return template.substitute(values) |
| 980 | 1029 |
| 981 def GetCalledByNativeValues(self, called_by_native): | 1030 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 | 1150 ret[class_name] = jni_class_path |
| 1102 return ret | 1151 return ret |
| 1103 | 1152 |
| 1104 def GetClassPathDefinitions(self): | 1153 def GetClassPathDefinitions(self): |
| 1105 """Returns the ClassPath constants.""" | 1154 """Returns the ClassPath constants.""" |
| 1106 ret = [] | 1155 ret = [] |
| 1107 template = Template("""\ | 1156 template = Template("""\ |
| 1108 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1157 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
| 1109 native_classes = self.GetUniqueClasses(self.natives) | 1158 native_classes = self.GetUniqueClasses(self.natives) |
| 1110 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1159 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) |
| 1111 all_classes = native_classes | 1160 if self.options.native_exports: |
| 1112 all_classes.update(called_by_native_classes) | 1161 all_classes = called_by_native_classes |
| 1162 else: | |
| 1163 all_classes = native_classes | |
| 1164 all_classes.update(called_by_native_classes) | |
| 1165 | |
| 1113 for clazz in all_classes: | 1166 for clazz in all_classes: |
| 1114 values = { | 1167 values = { |
| 1115 'JAVA_CLASS': clazz, | 1168 'JAVA_CLASS': clazz, |
| 1116 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), | 1169 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), |
| 1117 } | 1170 } |
| 1118 ret += [template.substitute(values)] | 1171 ret += [template.substitute(values)] |
| 1119 ret += '' | 1172 ret += '' |
| 1120 for clazz in called_by_native_classes: | 1173 for clazz in called_by_native_classes: |
| 1121 template = Template("""\ | 1174 template = Template("""\ |
| 1122 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1175 // 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 ' | 1374 'will limit the initialization to only the ' |
| 1322 'top-level class.') | 1375 'top-level class.') |
| 1323 option_parser.add_option('--eager_called_by_natives', | 1376 option_parser.add_option('--eager_called_by_natives', |
| 1324 action='store_true', dest='eager_called_by_natives', | 1377 action='store_true', dest='eager_called_by_natives', |
| 1325 help='When true, the called-by-native methods will ' | 1378 help='When true, the called-by-native methods will ' |
| 1326 'be initialized in a non-atomic way.') | 1379 'be initialized in a non-atomic way.') |
| 1327 option_parser.add_option('--cpp', default='cpp', | 1380 option_parser.add_option('--cpp', default='cpp', |
| 1328 help='The path to cpp command.') | 1381 help='The path to cpp command.') |
| 1329 option_parser.add_option('--javap', default='javap', | 1382 option_parser.add_option('--javap', default='javap', |
| 1330 help='The path to javap command.') | 1383 help='The path to javap command.') |
| 1384 option_parser.add_option('--native_exports', action='store_true', | |
| 1385 help='Native method registration through .so ' | |
| 1386 'exports.') | |
| 1331 options, args = option_parser.parse_args(argv) | 1387 options, args = option_parser.parse_args(argv) |
| 1332 if options.jar_file: | 1388 if options.jar_file: |
| 1333 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1389 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
| 1334 options.output_dir) | 1390 options.output_dir) |
| 1335 elif options.input_file: | 1391 elif options.input_file: |
| 1336 input_file = options.input_file | 1392 input_file = options.input_file |
| 1337 else: | 1393 else: |
| 1338 option_parser.print_help() | 1394 option_parser.print_help() |
| 1339 print '\nError: Must specify --jar_file or --input_file.' | 1395 print '\nError: Must specify --jar_file or --input_file.' |
| 1340 return 1 | 1396 return 1 |
| 1341 output_file = None | 1397 output_file = None |
| 1342 if options.output_dir: | 1398 if options.output_dir: |
| 1343 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1399 root_name = os.path.splitext(os.path.basename(input_file))[0] |
| 1344 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1400 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
| 1345 if options.jarjar: | 1401 if options.jarjar: |
| 1346 with open(options.jarjar) as f: | 1402 with open(options.jarjar) as f: |
| 1347 JniParams.SetJarJarMappings(f.read()) | 1403 JniParams.SetJarJarMappings(f.read()) |
| 1348 GenerateJNIHeader(input_file, output_file, options) | 1404 GenerateJNIHeader(input_file, output_file, options) |
| 1349 | 1405 |
| 1350 | 1406 |
| 1351 if __name__ == '__main__': | 1407 if __name__ == '__main__': |
| 1352 sys.exit(main(sys.argv)) | 1408 sys.exit(main(sys.argv)) |
| OLD | NEW |