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 // For | 729 // For |
730 // ${FULLY_QUALIFIED_CLASS} | 730 // ${FULLY_QUALIFIED_CLASS} |
731 | 731 |
732 #ifndef ${HEADER_GUARD} | 732 #ifndef ${HEADER_GUARD} |
733 #define ${HEADER_GUARD} | 733 #define ${HEADER_GUARD} |
734 | 734 |
735 #include <jni.h> | 735 #include <jni.h> |
736 | 736 |
737 ${INCLUDES} | 737 ${INCLUDES} |
738 | 738 |
| 739 ${PROFILING_INCLUDES} |
739 #include "base/android/jni_int_wrapper.h" | 740 #include "base/android/jni_int_wrapper.h" |
740 | 741 |
741 // Step 1: forward declarations. | 742 // Step 1: forward declarations. |
742 namespace { | 743 namespace { |
743 $CLASS_PATH_DEFINITIONS | 744 $CLASS_PATH_DEFINITIONS |
744 | 745 |
745 } // namespace | 746 } // namespace |
746 | 747 |
747 $OPEN_NAMESPACE | 748 $OPEN_NAMESPACE |
748 | 749 |
(...skipping 14 matching lines...) Expand all Loading... |
763 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class, | 764 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class, |
764 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(), | 765 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(), |
765 'CONSTANT_FIELDS': self.GetConstantFieldsString(), | 766 'CONSTANT_FIELDS': self.GetConstantFieldsString(), |
766 'METHOD_STUBS': self.GetMethodStubsString(), | 767 'METHOD_STUBS': self.GetMethodStubsString(), |
767 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), | 768 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), |
768 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(), | 769 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(), |
769 'REGISTER_NATIVES': self.GetRegisterNativesString(), | 770 'REGISTER_NATIVES': self.GetRegisterNativesString(), |
770 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), | 771 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), |
771 'HEADER_GUARD': self.header_guard, | 772 'HEADER_GUARD': self.header_guard, |
772 'INCLUDES': self.GetIncludesString(), | 773 'INCLUDES': self.GetIncludesString(), |
| 774 'PROFILING_INCLUDES': self.GetProfilingIncludesString(), |
773 } | 775 } |
774 assert ((values['JNI_NATIVE_METHODS'] == '') == | 776 assert ((values['JNI_NATIVE_METHODS'] == '') == |
775 (values['REGISTER_NATIVES'] == '')) | 777 (values['REGISTER_NATIVES'] == '')) |
776 return WrapOutput(template.substitute(values)) | 778 return WrapOutput(template.substitute(values)) |
777 | 779 |
778 def GetClassPathDefinitionsString(self): | 780 def GetClassPathDefinitionsString(self): |
779 ret = [] | 781 ret = [] |
780 ret += [self.GetClassPathDefinitions()] | 782 ret += [self.GetClassPathDefinitions()] |
781 return '\n'.join(ret) | 783 return '\n'.join(ret) |
782 | 784 |
(...skipping 17 matching lines...) Expand all Loading... |
800 def GetLazyCalledByNativeMethodStubs(self): | 802 def GetLazyCalledByNativeMethodStubs(self): |
801 return [self.GetLazyCalledByNativeMethodStub(called_by_native) | 803 return [self.GetLazyCalledByNativeMethodStub(called_by_native) |
802 for called_by_native in self.called_by_natives] | 804 for called_by_native in self.called_by_natives] |
803 | 805 |
804 def GetIncludesString(self): | 806 def GetIncludesString(self): |
805 if not self.options.includes: | 807 if not self.options.includes: |
806 return '' | 808 return '' |
807 includes = self.options.includes.split(',') | 809 includes = self.options.includes.split(',') |
808 return '\n'.join('#include "%s"' % x for x in includes) | 810 return '\n'.join('#include "%s"' % x for x in includes) |
809 | 811 |
| 812 def GetProfilingIncludesString(self): |
| 813 if not self.options.enable_profiling: |
| 814 return '' |
| 815 return '#include "base/compiler_specific.h"' |
| 816 |
810 def GetKMethodsString(self, clazz): | 817 def GetKMethodsString(self, clazz): |
811 ret = [] | 818 ret = [] |
812 for native in self.natives: | 819 for native in self.natives: |
813 if (native.java_class_name == clazz or | 820 if (native.java_class_name == clazz or |
814 (not native.java_class_name and clazz == self.class_name)): | 821 (not native.java_class_name and clazz == self.class_name)): |
815 ret += [self.GetKMethodArrayEntry(native)] | 822 ret += [self.GetKMethodArrayEntry(native)] |
816 return '\n'.join(ret) | 823 return '\n'.join(ret) |
817 | 824 |
818 def SubstituteNativeMethods(self, template): | 825 def SubstituteNativeMethods(self, template): |
819 """Substitutes JAVA_CLASS and KMETHODS in the provided template.""" | 826 """Substitutes JAVA_CLASS and KMETHODS in the provided template.""" |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 else: | 1001 else: |
995 params_in_call.append(p.name) | 1002 params_in_call.append(p.name) |
996 params_in_call = ', '.join(params_in_call) | 1003 params_in_call = ', '.join(params_in_call) |
997 | 1004 |
998 return_type = return_declaration = JavaDataTypeToC(native.return_type) | 1005 return_type = return_declaration = JavaDataTypeToC(native.return_type) |
999 post_call = '' | 1006 post_call = '' |
1000 if re.match(RE_SCOPED_JNI_TYPES, return_type): | 1007 if re.match(RE_SCOPED_JNI_TYPES, return_type): |
1001 post_call = '.Release()' | 1008 post_call = '.Release()' |
1002 return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type + | 1009 return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type + |
1003 '>') | 1010 '>') |
| 1011 profiling_entered_native = '' |
| 1012 if self.options.enable_profiling: |
| 1013 profiling_entered_native = 'JNI_PROFILING_ENTERED_NATIVE;' |
1004 values = { | 1014 values = { |
1005 'RETURN': return_type, | 1015 'RETURN': return_type, |
1006 'RETURN_DECLARATION': return_declaration, | 1016 'RETURN_DECLARATION': return_declaration, |
1007 'NAME': native.name, | 1017 'NAME': native.name, |
1008 'PARAMS': self.GetParamsInDeclaration(native), | 1018 'PARAMS': self.GetParamsInDeclaration(native), |
1009 'PARAMS_IN_STUB': self.GetParamsInStub(native), | 1019 'PARAMS_IN_STUB': self.GetParamsInStub(native), |
1010 'PARAMS_IN_CALL': params_in_call, | 1020 'PARAMS_IN_CALL': params_in_call, |
1011 'POST_CALL': post_call, | 1021 'POST_CALL': post_call, |
1012 'STUB_NAME': self.GetStubName(native), | 1022 'STUB_NAME': self.GetStubName(native), |
| 1023 'PROFILING_ENTERED_NATIVE': profiling_entered_native, |
1013 } | 1024 } |
1014 | 1025 |
1015 if is_method: | 1026 if is_method: |
1016 optional_error_return = JavaReturnValueToC(native.return_type) | 1027 optional_error_return = JavaReturnValueToC(native.return_type) |
1017 if optional_error_return: | 1028 if optional_error_return: |
1018 optional_error_return = ', ' + optional_error_return | 1029 optional_error_return = ', ' + optional_error_return |
1019 values.update({ | 1030 values.update({ |
1020 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1031 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1021 'PARAM0_NAME': native.params[0].name, | 1032 'PARAM0_NAME': native.params[0].name, |
1022 'P0_TYPE': native.p0_type, | 1033 'P0_TYPE': native.p0_type, |
1023 }) | 1034 }) |
1024 template = Template("""\ | 1035 template = Template("""\ |
1025 extern "C" __attribute__((visibility("default"))) | 1036 extern "C" __attribute__((visibility("default"))) |
1026 ${RETURN} ${STUB_NAME}(JNIEnv* env, | 1037 ${RETURN} ${STUB_NAME}(JNIEnv* env, |
1027 ${PARAMS_IN_STUB}) { | 1038 ${PARAMS_IN_STUB}) { |
| 1039 ${PROFILING_ENTERED_NATIVE} |
1028 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1040 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
1029 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1041 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
1030 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1042 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1031 } | 1043 } |
1032 """) | 1044 """) |
1033 else: | 1045 else: |
1034 template = Template(""" | 1046 template = Template(""" |
1035 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); | 1047 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); |
1036 | 1048 |
1037 extern "C" __attribute__((visibility("default"))) | 1049 extern "C" __attribute__((visibility("default"))) |
1038 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { | 1050 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { |
| 1051 ${PROFILING_ENTERED_NATIVE} |
1039 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1052 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1040 } | 1053 } |
1041 """) | 1054 """) |
1042 | 1055 |
1043 return template.substitute(values) | 1056 return template.substitute(values) |
1044 | 1057 |
1045 def GetArgument(self, param): | 1058 def GetArgument(self, param): |
1046 if param.datatype == 'int': | 1059 if param.datatype == 'int': |
1047 return 'as_jint(' + param.name + ')' | 1060 return 'as_jint(' + param.name + ')' |
1048 elif re.match(RE_SCOPED_JNI_TYPES, JavaDataTypeToC(param.datatype)): | 1061 elif re.match(RE_SCOPED_JNI_TYPES, JavaDataTypeToC(param.datatype)): |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 return_declaration = '' | 1099 return_declaration = '' |
1087 return_clause = '' | 1100 return_clause = '' |
1088 if return_type != 'void': | 1101 if return_type != 'void': |
1089 pre_call = ' ' + pre_call | 1102 pre_call = ' ' + pre_call |
1090 return_declaration = return_type + ' ret =' | 1103 return_declaration = return_type + ' ret =' |
1091 if re.match(RE_SCOPED_JNI_TYPES, return_type): | 1104 if re.match(RE_SCOPED_JNI_TYPES, return_type): |
1092 return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>' | 1105 return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>' |
1093 return_clause = 'return ' + return_type + '(env, ret);' | 1106 return_clause = 'return ' + return_type + '(env, ret);' |
1094 else: | 1107 else: |
1095 return_clause = 'return ret;' | 1108 return_clause = 'return ret;' |
| 1109 profiling_leaving_native = '' |
| 1110 if self.options.enable_profiling: |
| 1111 profiling_leaving_native = 'JNI_PROFILING_LEAVING_NATIVE;' |
1096 return { | 1112 return { |
1097 'JAVA_CLASS': java_class, | 1113 'JAVA_CLASS': java_class, |
1098 'RETURN_TYPE': return_type, | 1114 'RETURN_TYPE': return_type, |
1099 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1115 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1100 'RETURN_DECLARATION': return_declaration, | 1116 'RETURN_DECLARATION': return_declaration, |
1101 'RETURN_CLAUSE': return_clause, | 1117 'RETURN_CLAUSE': return_clause, |
1102 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, | 1118 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, |
1103 'PARAMS_IN_DECLARATION': params_in_declaration, | 1119 'PARAMS_IN_DECLARATION': params_in_declaration, |
1104 'PRE_CALL': pre_call, | 1120 'PRE_CALL': pre_call, |
1105 'POST_CALL': post_call, | 1121 'POST_CALL': post_call, |
1106 'ENV_CALL': called_by_native.env_call, | 1122 'ENV_CALL': called_by_native.env_call, |
1107 'FIRST_PARAM_IN_CALL': first_param_in_call, | 1123 'FIRST_PARAM_IN_CALL': first_param_in_call, |
1108 'PARAMS_IN_CALL': params_in_call, | 1124 'PARAMS_IN_CALL': params_in_call, |
1109 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 1125 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
1110 'CHECK_EXCEPTION': check_exception, | 1126 'CHECK_EXCEPTION': check_exception, |
1111 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native) | 1127 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native), |
| 1128 'PROFILING_LEAVING_NATIVE': profiling_leaving_native, |
1112 } | 1129 } |
1113 | 1130 |
1114 | 1131 |
1115 def GetLazyCalledByNativeMethodStub(self, called_by_native): | 1132 def GetLazyCalledByNativeMethodStub(self, called_by_native): |
1116 """Returns a string.""" | 1133 """Returns a string.""" |
1117 function_signature_template = Template("""\ | 1134 function_signature_template = Template("""\ |
1118 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ | 1135 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ |
1119 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") | 1136 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") |
1120 function_header_template = Template("""\ | 1137 function_header_template = Template("""\ |
1121 ${FUNCTION_SIGNATURE} {""") | 1138 ${FUNCTION_SIGNATURE} {""") |
1122 function_header_with_unused_template = Template("""\ | 1139 function_header_with_unused_template = Template("""\ |
1123 ${FUNCTION_SIGNATURE} __attribute__ ((unused)); | 1140 ${FUNCTION_SIGNATURE} __attribute__ ((unused)); |
1124 ${FUNCTION_SIGNATURE} {""") | 1141 ${FUNCTION_SIGNATURE} {""") |
1125 template = Template(""" | 1142 template = Template(""" |
1126 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; | 1143 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; |
1127 ${FUNCTION_HEADER} | 1144 ${FUNCTION_HEADER} |
1128 CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL}, | 1145 CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL}, |
1129 ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN}); | 1146 ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN}); |
1130 jmethodID method_id = | 1147 jmethodID method_id = |
1131 ${GET_METHOD_ID_IMPL} | 1148 ${GET_METHOD_ID_IMPL} |
| 1149 ${PROFILING_LEAVING_NATIVE} |
1132 ${RETURN_DECLARATION} | 1150 ${RETURN_DECLARATION} |
1133 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, | 1151 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, |
1134 method_id${PARAMS_IN_CALL})${POST_CALL}; | 1152 method_id${PARAMS_IN_CALL})${POST_CALL}; |
1135 ${CHECK_EXCEPTION} | 1153 ${CHECK_EXCEPTION} |
1136 ${RETURN_CLAUSE} | 1154 ${RETURN_CLAUSE} |
1137 }""") | 1155 }""") |
1138 values = self.GetCalledByNativeValues(called_by_native) | 1156 values = self.GetCalledByNativeValues(called_by_native) |
1139 values['FUNCTION_SIGNATURE'] = ( | 1157 values['FUNCTION_SIGNATURE'] = ( |
1140 function_signature_template.substitute(values)) | 1158 function_signature_template.substitute(values)) |
1141 if called_by_native.system_class: | 1159 if called_by_native.system_class: |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1356 help='The type used to represent native pointers in ' | 1374 help='The type used to represent native pointers in ' |
1357 'Java code. For 32-bit, use int; ' | 1375 'Java code. For 32-bit, use int; ' |
1358 'for 64-bit, use long.') | 1376 'for 64-bit, use long.') |
1359 option_parser.add_option('--cpp', default='cpp', | 1377 option_parser.add_option('--cpp', default='cpp', |
1360 help='The path to cpp command.') | 1378 help='The path to cpp command.') |
1361 option_parser.add_option('--javap', default='javap', | 1379 option_parser.add_option('--javap', default='javap', |
1362 help='The path to javap command.') | 1380 help='The path to javap command.') |
1363 option_parser.add_option('--native_exports_optional', action='store_true', | 1381 option_parser.add_option('--native_exports_optional', action='store_true', |
1364 help='Support both explicit and native method' | 1382 help='Support both explicit and native method' |
1365 'registration.') | 1383 'registration.') |
| 1384 option_parser.add_option('--enable_profiling', action='store_true', |
| 1385 help='Add additional profiling instrumentation.') |
1366 options, args = option_parser.parse_args(argv) | 1386 options, args = option_parser.parse_args(argv) |
1367 if options.jar_file: | 1387 if options.jar_file: |
1368 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1388 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1369 options.output_dir) | 1389 options.output_dir) |
1370 elif options.input_file: | 1390 elif options.input_file: |
1371 input_file = options.input_file | 1391 input_file = options.input_file |
1372 else: | 1392 else: |
1373 option_parser.print_help() | 1393 option_parser.print_help() |
1374 print '\nError: Must specify --jar_file or --input_file.' | 1394 print '\nError: Must specify --jar_file or --input_file.' |
1375 return 1 | 1395 return 1 |
1376 output_file = None | 1396 output_file = None |
1377 if options.output_dir: | 1397 if options.output_dir: |
1378 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1398 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1379 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1399 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1380 GenerateJNIHeader(input_file, output_file, options) | 1400 GenerateJNIHeader(input_file, output_file, options) |
1381 | 1401 |
1382 if options.depfile: | 1402 if options.depfile: |
1383 build_utils.WriteDepfile(options.depfile, output_file) | 1403 build_utils.WriteDepfile(options.depfile, output_file) |
1384 | 1404 |
1385 | 1405 |
1386 if __name__ == '__main__': | 1406 if __name__ == '__main__': |
1387 sys.exit(main(sys.argv)) | 1407 sys.exit(main(sys.argv)) |
OLD | NEW |