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 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 |