Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(365)

Side by Side Diff: base/android/jni_generator/jni_generator.py

Issue 2361353002: Link stack frames of JNI stubs to JNI callbacks. (Closed)
Patch Set: git cl format Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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))
OLDNEW
« no previous file with comments | « base/android/jni_generator/golden_sample_for_tests_jni.h ('k') | base/android/jni_generator/jni_generator_tests.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698