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 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 # Regex to match a string like "@CalledByNative public void foo(int bar)". | 517 # Regex to match a string like "@CalledByNative public void foo(int bar)". |
518 RE_CALLED_BY_NATIVE = re.compile( | 518 RE_CALLED_BY_NATIVE = re.compile( |
519 '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?' | 519 '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?' |
520 '\s+(?P<prefix>[\w ]*?)' | 520 '\s+(?P<prefix>[\w ]*?)' |
521 '(:?\s*@\w+)?' # Ignore annotations in return types. | 521 '(:?\s*@\w+)?' # Ignore annotations in return types. |
522 '\s*(?P<return_type>\S+?)' | 522 '\s*(?P<return_type>\S+?)' |
523 '\s+(?P<name>\w+)' | 523 '\s+(?P<name>\w+)' |
524 '\s*\((?P<params>[^\)]*)\)') | 524 '\s*\((?P<params>[^\)]*)\)') |
525 | 525 |
526 | 526 |
| 527 # Removes empty lines that are indented (i.e. start with 2x spaces). |
| 528 def RemoveIndentedEmptyLines(string): |
| 529 return re.sub('^(?: {2})+$\n', '', string, flags=re.MULTILINE) |
| 530 |
| 531 |
527 def ExtractCalledByNatives(contents): | 532 def ExtractCalledByNatives(contents): |
528 """Parses all methods annotated with @CalledByNative. | 533 """Parses all methods annotated with @CalledByNative. |
529 | 534 |
530 Args: | 535 Args: |
531 contents: the contents of the java file. | 536 contents: the contents of the java file. |
532 | 537 |
533 Returns: | 538 Returns: |
534 A list of dict with information about the annotated methods. | 539 A list of dict with information about the annotated methods. |
535 TODO(bulach): return a CalledByNative object. | 540 TODO(bulach): return a CalledByNative object. |
536 | 541 |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 else: | 999 else: |
995 params_in_call.append(p.name) | 1000 params_in_call.append(p.name) |
996 params_in_call = ', '.join(params_in_call) | 1001 params_in_call = ', '.join(params_in_call) |
997 | 1002 |
998 return_type = return_declaration = JavaDataTypeToC(native.return_type) | 1003 return_type = return_declaration = JavaDataTypeToC(native.return_type) |
999 post_call = '' | 1004 post_call = '' |
1000 if re.match(RE_SCOPED_JNI_TYPES, return_type): | 1005 if re.match(RE_SCOPED_JNI_TYPES, return_type): |
1001 post_call = '.Release()' | 1006 post_call = '.Release()' |
1002 return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type + | 1007 return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type + |
1003 '>') | 1008 '>') |
| 1009 profiling_entered_native = '' |
| 1010 if self.options.enable_profiling: |
| 1011 profiling_entered_native = 'JNI_LINK_SAVED_FRAME_POINTER;' |
1004 values = { | 1012 values = { |
1005 'RETURN': return_type, | 1013 'RETURN': return_type, |
1006 'RETURN_DECLARATION': return_declaration, | 1014 'RETURN_DECLARATION': return_declaration, |
1007 'NAME': native.name, | 1015 'NAME': native.name, |
1008 'PARAMS': self.GetParamsInDeclaration(native), | 1016 'PARAMS': self.GetParamsInDeclaration(native), |
1009 'PARAMS_IN_STUB': self.GetParamsInStub(native), | 1017 'PARAMS_IN_STUB': self.GetParamsInStub(native), |
1010 'PARAMS_IN_CALL': params_in_call, | 1018 'PARAMS_IN_CALL': params_in_call, |
1011 'POST_CALL': post_call, | 1019 'POST_CALL': post_call, |
1012 'STUB_NAME': self.GetStubName(native), | 1020 'STUB_NAME': self.GetStubName(native), |
| 1021 'PROFILING_ENTERED_NATIVE': profiling_entered_native, |
1013 } | 1022 } |
1014 | 1023 |
1015 if is_method: | 1024 if is_method: |
1016 optional_error_return = JavaReturnValueToC(native.return_type) | 1025 optional_error_return = JavaReturnValueToC(native.return_type) |
1017 if optional_error_return: | 1026 if optional_error_return: |
1018 optional_error_return = ', ' + optional_error_return | 1027 optional_error_return = ', ' + optional_error_return |
1019 values.update({ | 1028 values.update({ |
1020 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1029 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1021 'PARAM0_NAME': native.params[0].name, | 1030 'PARAM0_NAME': native.params[0].name, |
1022 'P0_TYPE': native.p0_type, | 1031 'P0_TYPE': native.p0_type, |
1023 }) | 1032 }) |
1024 template = Template("""\ | 1033 template = Template("""\ |
1025 extern "C" __attribute__((visibility("default"))) | 1034 extern "C" __attribute__((visibility("default"))) |
1026 ${RETURN} ${STUB_NAME}(JNIEnv* env, | 1035 ${RETURN} ${STUB_NAME}(JNIEnv* env, |
1027 ${PARAMS_IN_STUB}) { | 1036 ${PARAMS_IN_STUB}) { |
| 1037 ${PROFILING_ENTERED_NATIVE} |
1028 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1038 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
1029 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1039 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
1030 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1040 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1031 } | 1041 } |
1032 """) | 1042 """) |
1033 else: | 1043 else: |
1034 template = Template(""" | 1044 template = Template(""" |
1035 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); | 1045 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); |
1036 | 1046 |
1037 extern "C" __attribute__((visibility("default"))) | 1047 extern "C" __attribute__((visibility("default"))) |
1038 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { | 1048 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { |
| 1049 ${PROFILING_ENTERED_NATIVE} |
1039 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1050 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1040 } | 1051 } |
1041 """) | 1052 """) |
1042 | 1053 |
1043 return template.substitute(values) | 1054 return RemoveIndentedEmptyLines(template.substitute(values)) |
1044 | 1055 |
1045 def GetArgument(self, param): | 1056 def GetArgument(self, param): |
1046 if param.datatype == 'int': | 1057 if param.datatype == 'int': |
1047 return 'as_jint(' + param.name + ')' | 1058 return 'as_jint(' + param.name + ')' |
1048 elif re.match(RE_SCOPED_JNI_TYPES, JavaDataTypeToC(param.datatype)): | 1059 elif re.match(RE_SCOPED_JNI_TYPES, JavaDataTypeToC(param.datatype)): |
1049 return param.name + '.obj()' | 1060 return param.name + '.obj()' |
1050 else: | 1061 else: |
1051 return param.name | 1062 return param.name |
1052 | 1063 |
1053 def GetArgumentsInCall(self, params): | 1064 def GetArgumentsInCall(self, params): |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 return_declaration = '' | 1097 return_declaration = '' |
1087 return_clause = '' | 1098 return_clause = '' |
1088 if return_type != 'void': | 1099 if return_type != 'void': |
1089 pre_call = ' ' + pre_call | 1100 pre_call = ' ' + pre_call |
1090 return_declaration = return_type + ' ret =' | 1101 return_declaration = return_type + ' ret =' |
1091 if re.match(RE_SCOPED_JNI_TYPES, return_type): | 1102 if re.match(RE_SCOPED_JNI_TYPES, return_type): |
1092 return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>' | 1103 return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>' |
1093 return_clause = 'return ' + return_type + '(env, ret);' | 1104 return_clause = 'return ' + return_type + '(env, ret);' |
1094 else: | 1105 else: |
1095 return_clause = 'return ret;' | 1106 return_clause = 'return ret;' |
| 1107 profiling_leaving_native = '' |
| 1108 if self.options.enable_profiling: |
| 1109 profiling_leaving_native = 'JNI_SAVE_FRAME_POINTER;' |
1096 return { | 1110 return { |
1097 'JAVA_CLASS': java_class, | 1111 'JAVA_CLASS': java_class, |
1098 'RETURN_TYPE': return_type, | 1112 'RETURN_TYPE': return_type, |
1099 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1113 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1100 'RETURN_DECLARATION': return_declaration, | 1114 'RETURN_DECLARATION': return_declaration, |
1101 'RETURN_CLAUSE': return_clause, | 1115 'RETURN_CLAUSE': return_clause, |
1102 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, | 1116 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, |
1103 'PARAMS_IN_DECLARATION': params_in_declaration, | 1117 'PARAMS_IN_DECLARATION': params_in_declaration, |
1104 'PRE_CALL': pre_call, | 1118 'PRE_CALL': pre_call, |
1105 'POST_CALL': post_call, | 1119 'POST_CALL': post_call, |
1106 'ENV_CALL': called_by_native.env_call, | 1120 'ENV_CALL': called_by_native.env_call, |
1107 'FIRST_PARAM_IN_CALL': first_param_in_call, | 1121 'FIRST_PARAM_IN_CALL': first_param_in_call, |
1108 'PARAMS_IN_CALL': params_in_call, | 1122 'PARAMS_IN_CALL': params_in_call, |
1109 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 1123 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
1110 'CHECK_EXCEPTION': check_exception, | 1124 'CHECK_EXCEPTION': check_exception, |
1111 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native) | 1125 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native), |
| 1126 'PROFILING_LEAVING_NATIVE': profiling_leaving_native, |
1112 } | 1127 } |
1113 | 1128 |
1114 | 1129 |
1115 def GetLazyCalledByNativeMethodStub(self, called_by_native): | 1130 def GetLazyCalledByNativeMethodStub(self, called_by_native): |
1116 """Returns a string.""" | 1131 """Returns a string.""" |
1117 function_signature_template = Template("""\ | 1132 function_signature_template = Template("""\ |
1118 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ | 1133 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ |
1119 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") | 1134 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") |
1120 function_header_template = Template("""\ | 1135 function_header_template = Template("""\ |
1121 ${FUNCTION_SIGNATURE} {""") | 1136 ${FUNCTION_SIGNATURE} {""") |
1122 function_header_with_unused_template = Template("""\ | 1137 function_header_with_unused_template = Template("""\ |
1123 ${FUNCTION_SIGNATURE} __attribute__ ((unused)); | 1138 ${FUNCTION_SIGNATURE} __attribute__ ((unused)); |
1124 ${FUNCTION_SIGNATURE} {""") | 1139 ${FUNCTION_SIGNATURE} {""") |
1125 template = Template(""" | 1140 template = Template(""" |
1126 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; | 1141 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; |
1127 ${FUNCTION_HEADER} | 1142 ${FUNCTION_HEADER} |
1128 CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL}, | 1143 CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL}, |
1129 ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN}); | 1144 ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN}); |
1130 jmethodID method_id = | 1145 jmethodID method_id = |
1131 ${GET_METHOD_ID_IMPL} | 1146 ${GET_METHOD_ID_IMPL} |
| 1147 ${PROFILING_LEAVING_NATIVE} |
1132 ${RETURN_DECLARATION} | 1148 ${RETURN_DECLARATION} |
1133 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, | 1149 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, |
1134 method_id${PARAMS_IN_CALL})${POST_CALL}; | 1150 method_id${PARAMS_IN_CALL})${POST_CALL}; |
1135 ${CHECK_EXCEPTION} | 1151 ${CHECK_EXCEPTION} |
1136 ${RETURN_CLAUSE} | 1152 ${RETURN_CLAUSE} |
1137 }""") | 1153 }""") |
1138 values = self.GetCalledByNativeValues(called_by_native) | 1154 values = self.GetCalledByNativeValues(called_by_native) |
1139 values['FUNCTION_SIGNATURE'] = ( | 1155 values['FUNCTION_SIGNATURE'] = ( |
1140 function_signature_template.substitute(values)) | 1156 function_signature_template.substitute(values)) |
1141 if called_by_native.system_class: | 1157 if called_by_native.system_class: |
1142 values['FUNCTION_HEADER'] = ( | 1158 values['FUNCTION_HEADER'] = ( |
1143 function_header_with_unused_template.substitute(values)) | 1159 function_header_with_unused_template.substitute(values)) |
1144 else: | 1160 else: |
1145 values['FUNCTION_HEADER'] = function_header_template.substitute(values) | 1161 values['FUNCTION_HEADER'] = function_header_template.substitute(values) |
1146 return template.substitute(values) | 1162 return RemoveIndentedEmptyLines(template.substitute(values)) |
1147 | 1163 |
1148 def GetKMethodArrayEntry(self, native): | 1164 def GetKMethodArrayEntry(self, native): |
1149 template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' + | 1165 template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' + |
1150 'reinterpret_cast<void*>(${STUB_NAME}) },') | 1166 'reinterpret_cast<void*>(${STUB_NAME}) },') |
1151 values = {'NAME': native.name, | 1167 values = {'NAME': native.name, |
1152 'JNI_SIGNATURE': JniParams.Signature(native.params, | 1168 'JNI_SIGNATURE': JniParams.Signature(native.params, |
1153 native.return_type, | 1169 native.return_type, |
1154 True), | 1170 True), |
1155 'STUB_NAME': self.GetStubName(native)} | 1171 'STUB_NAME': self.GetStubName(native)} |
1156 return template.substitute(values) | 1172 return template.substitute(values) |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1356 help='The type used to represent native pointers in ' | 1372 help='The type used to represent native pointers in ' |
1357 'Java code. For 32-bit, use int; ' | 1373 'Java code. For 32-bit, use int; ' |
1358 'for 64-bit, use long.') | 1374 'for 64-bit, use long.') |
1359 option_parser.add_option('--cpp', default='cpp', | 1375 option_parser.add_option('--cpp', default='cpp', |
1360 help='The path to cpp command.') | 1376 help='The path to cpp command.') |
1361 option_parser.add_option('--javap', default='javap', | 1377 option_parser.add_option('--javap', default='javap', |
1362 help='The path to javap command.') | 1378 help='The path to javap command.') |
1363 option_parser.add_option('--native_exports_optional', action='store_true', | 1379 option_parser.add_option('--native_exports_optional', action='store_true', |
1364 help='Support both explicit and native method' | 1380 help='Support both explicit and native method' |
1365 'registration.') | 1381 'registration.') |
| 1382 option_parser.add_option('--enable_profiling', action='store_true', |
| 1383 help='Add additional profiling instrumentation.') |
1366 options, args = option_parser.parse_args(argv) | 1384 options, args = option_parser.parse_args(argv) |
1367 if options.jar_file: | 1385 if options.jar_file: |
1368 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1386 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1369 options.output_dir) | 1387 options.output_dir) |
1370 elif options.input_file: | 1388 elif options.input_file: |
1371 input_file = options.input_file | 1389 input_file = options.input_file |
1372 else: | 1390 else: |
1373 option_parser.print_help() | 1391 option_parser.print_help() |
1374 print '\nError: Must specify --jar_file or --input_file.' | 1392 print '\nError: Must specify --jar_file or --input_file.' |
1375 return 1 | 1393 return 1 |
1376 output_file = None | 1394 output_file = None |
1377 if options.output_dir: | 1395 if options.output_dir: |
1378 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1396 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1379 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1397 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1380 GenerateJNIHeader(input_file, output_file, options) | 1398 GenerateJNIHeader(input_file, output_file, options) |
1381 | 1399 |
1382 if options.depfile: | 1400 if options.depfile: |
1383 build_utils.WriteDepfile(options.depfile, output_file) | 1401 build_utils.WriteDepfile(options.depfile, output_file) |
1384 | 1402 |
1385 | 1403 |
1386 if __name__ == '__main__': | 1404 if __name__ == '__main__': |
1387 sys.exit(main(sys.argv)) | 1405 sys.exit(main(sys.argv)) |
OLD | NEW |