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 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 786 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
787 } | 787 } |
788 ret += [template.substitute(values)] | 788 ret += [template.substitute(values)] |
789 return '\n'.join(ret) | 789 return '\n'.join(ret) |
790 | 790 |
791 def GetForwardDeclarationsString(self): | 791 def GetForwardDeclarationsString(self): |
792 ret = [] | 792 ret = [] |
793 for native in self.natives: | 793 for native in self.natives: |
794 if native.type != 'method': | 794 if native.type != 'method': |
795 ret += [self.GetForwardDeclaration(native)] | 795 ret += [self.GetForwardDeclaration(native)] |
796 if self.options.native_exports and ret: | |
797 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' | |
798 return '\n'.join(ret) | 796 return '\n'.join(ret) |
799 | 797 |
800 def GetConstantFieldsString(self): | 798 def GetConstantFieldsString(self): |
801 if not self.constant_fields: | 799 if not self.constant_fields: |
802 return '' | 800 return '' |
803 ret = ['enum Java_%s_constant_fields {' % self.class_name] | 801 ret = ['enum Java_%s_constant_fields {' % self.class_name] |
804 for c in self.constant_fields: | 802 for c in self.constant_fields: |
805 ret += [' %s = %s,' % (c.name, c.value)] | 803 ret += [' %s = %s,' % (c.name, c.value)] |
806 ret += ['};'] | 804 ret += ['};'] |
807 return '\n'.join(ret) | 805 return '\n'.join(ret) |
808 | 806 |
809 def GetMethodStubsString(self): | 807 def GetMethodStubsString(self): |
810 """Returns the code corresponding to method stubs.""" | 808 """Returns the code corresponding to method stubs.""" |
811 ret = [] | 809 ret = [] |
812 for native in self.natives: | 810 for native in self.natives: |
813 if native.type == 'method': | 811 if native.type == 'method': |
814 ret += [self.GetNativeMethodStubString(native)] | 812 ret += [self.GetNativeMethodStubString(native)] |
815 if self.options.eager_called_by_natives: | 813 if self.options.eager_called_by_natives: |
816 ret += self.GetEagerCalledByNativeMethodStubs() | 814 ret += self.GetEagerCalledByNativeMethodStubs() |
817 else: | 815 else: |
818 ret += self.GetLazyCalledByNativeMethodStubs() | 816 ret += self.GetLazyCalledByNativeMethodStubs() |
819 | |
820 if self.options.native_exports and ret: | |
821 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' | |
822 return '\n'.join(ret) | 817 return '\n'.join(ret) |
823 | 818 |
824 def GetLazyCalledByNativeMethodStubs(self): | 819 def GetLazyCalledByNativeMethodStubs(self): |
825 return [self.GetLazyCalledByNativeMethodStub(called_by_native) | 820 return [self.GetLazyCalledByNativeMethodStub(called_by_native) |
826 for called_by_native in self.called_by_natives] | 821 for called_by_native in self.called_by_natives] |
827 | 822 |
828 def GetEagerCalledByNativeMethodStubs(self): | 823 def GetEagerCalledByNativeMethodStubs(self): |
829 ret = [] | 824 ret = [] |
830 if self.called_by_natives: | 825 if self.called_by_natives: |
831 ret += ['namespace {'] | 826 ret += ['namespace {'] |
(...skipping 25 matching lines...) Expand all Loading... |
857 kmethods = self.GetKMethodsString(clazz) | 852 kmethods = self.GetKMethodsString(clazz) |
858 if kmethods: | 853 if kmethods: |
859 values = {'JAVA_CLASS': clazz, | 854 values = {'JAVA_CLASS': clazz, |
860 'KMETHODS': kmethods} | 855 'KMETHODS': kmethods} |
861 ret += [template.substitute(values)] | 856 ret += [template.substitute(values)] |
862 if not ret: return '' | 857 if not ret: return '' |
863 return '\n' + '\n'.join(ret) | 858 return '\n' + '\n'.join(ret) |
864 | 859 |
865 def GetJNINativeMethodsString(self): | 860 def GetJNINativeMethodsString(self): |
866 """Returns the implementation of the array of native methods.""" | 861 """Returns the implementation of the array of native methods.""" |
867 if self.options.native_exports: | |
868 return '' | |
869 template = Template("""\ | 862 template = Template("""\ |
870 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 863 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
871 ${KMETHODS} | 864 ${KMETHODS} |
872 }; | 865 }; |
873 """) | 866 """) |
874 return self.SubstituteNativeMethods(template) | 867 return self.SubstituteNativeMethods(template) |
875 | 868 |
876 def GetRegisterCalledByNativesImplString(self): | 869 def GetRegisterCalledByNativesImplString(self): |
877 """Returns the code for registering the called by native methods.""" | 870 """Returns the code for registering the called by native methods.""" |
878 if not self.options.eager_called_by_natives: | 871 if not self.options.eager_called_by_natives: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 called_by_natives = self.GetRegisterCalledByNativesImplString() | 906 called_by_natives = self.GetRegisterCalledByNativesImplString() |
914 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 907 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
915 'CLASSES': self.GetFindClasses(), | 908 'CLASSES': self.GetFindClasses(), |
916 'NATIVES': natives, | 909 'NATIVES': natives, |
917 'CALLED_BY_NATIVES': called_by_natives, | 910 'CALLED_BY_NATIVES': called_by_natives, |
918 } | 911 } |
919 return template.substitute(values) | 912 return template.substitute(values) |
920 | 913 |
921 def GetRegisterNativesImplString(self): | 914 def GetRegisterNativesImplString(self): |
922 """Returns the shared implementation for RegisterNatives.""" | 915 """Returns the shared implementation for RegisterNatives.""" |
923 if self.options.native_exports: | |
924 return '' | |
925 | |
926 template = Template("""\ | 916 template = Template("""\ |
927 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 917 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
928 | 918 |
929 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, | 919 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, |
930 kMethods${JAVA_CLASS}, | 920 kMethods${JAVA_CLASS}, |
931 kMethods${JAVA_CLASS}Size) < 0) { | 921 kMethods${JAVA_CLASS}Size) < 0) { |
932 jni_generator::HandleRegistrationError( | 922 jni_generator::HandleRegistrationError( |
933 env, g_${JAVA_CLASS}_clazz, __FILE__); | 923 env, g_${JAVA_CLASS}_clazz, __FILE__); |
934 return false; | 924 return false; |
935 } | 925 } |
936 """) | 926 """) |
937 return self.SubstituteNativeMethods(template) | 927 return self.SubstituteNativeMethods(template) |
938 | 928 |
939 def GetJNIRegisterNativesString(self): | 929 def GetJNIRegisterNativesString(self): |
940 """Returns the implementation for the JNI registration of native methods.""" | 930 """Returns the implementation for the JNI registration of native methods.""" |
941 if not self.init_native: | 931 if not self.init_native: |
942 return '' | 932 return '' |
943 | 933 |
944 template = Template("""\ | 934 template = Template("""\ |
945 extern "C" JNIEXPORT bool JNICALL | 935 extern "C" JNIEXPORT bool JNICALL |
946 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { | 936 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { |
947 return ${NAMESPACE}RegisterNativesImpl(env, clazz); | 937 return ${NAMESPACE}RegisterNativesImpl(env, clazz); |
948 } | 938 } |
949 """) | 939 """) |
950 | 940 fully_qualified_class = self.fully_qualified_class.replace('/', '_') |
951 if self.options.native_exports: | |
952 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
953 java_name = java_name.replace('_', '_1').replace('/', '_') | |
954 else: | |
955 java_name = self.fully_qualified_class.replace('/', '_') | |
956 | |
957 namespace = '' | 941 namespace = '' |
958 if self.namespace: | 942 if self.namespace: |
959 namespace = self.namespace + '::' | 943 namespace = self.namespace + '::' |
960 values = {'FULLY_QUALIFIED_CLASS': java_name, | 944 values = {'FULLY_QUALIFIED_CLASS': fully_qualified_class, |
961 'INIT_NATIVE_NAME': 'native' + self.init_native.name, | 945 'INIT_NATIVE_NAME': 'native' + self.init_native.name, |
962 'NAMESPACE': namespace, | 946 'NAMESPACE': namespace, |
963 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() | 947 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() |
964 } | 948 } |
965 return template.substitute(values) | 949 return template.substitute(values) |
966 | 950 |
967 def GetOpenNamespaceString(self): | 951 def GetOpenNamespaceString(self): |
968 if self.namespace: | 952 if self.namespace: |
969 all_namespaces = ['namespace %s {' % ns | 953 all_namespaces = ['namespace %s {' % ns |
970 for ns in self.namespace.split('::')] | 954 for ns in self.namespace.split('::')] |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1004 param.name | 988 param.name |
1005 for param in native.params]) | 989 for param in native.params]) |
1006 | 990 |
1007 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 991 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
1008 return ',\n '.join([ | 992 return ',\n '.join([ |
1009 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + | 993 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + |
1010 param.name | 994 param.name |
1011 for param in called_by_native.params]) | 995 for param in called_by_native.params]) |
1012 | 996 |
1013 def GetForwardDeclaration(self, native): | 997 def GetForwardDeclaration(self, native): |
1014 template_str = """ | 998 template = Template(""" |
1015 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 999 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
1016 """ | 1000 """) |
1017 if self.options.native_exports: | |
1018 template_str += """ | |
1019 __attribute__((visibility("default"))) | |
1020 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) { | |
1021 return ${NAME}(${PARAMS_IN_CALL}); | |
1022 } | |
1023 """ | |
1024 template = Template(template_str) | |
1025 params_in_call = [] | |
1026 if not self.options.pure_native_methods: | |
1027 params_in_call = ['env', 'jcaller'] | |
1028 params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) | |
1029 | |
1030 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
1031 java_name = java_name.replace('_', '_1').replace('/', '_') | |
1032 if native.java_class_name: | |
1033 java_name += '_00024' + native.java_class_name | |
1034 | |
1035 values = {'RETURN': JavaDataTypeToC(native.return_type), | 1001 values = {'RETURN': JavaDataTypeToC(native.return_type), |
1036 'NAME': native.name, | 1002 'NAME': native.name, |
1037 'JAVA_NAME': java_name, | 1003 'PARAMS': self.GetParamsInDeclaration(native)} |
1038 'PARAMS': self.GetParamsInDeclaration(native), | |
1039 'PARAMS_IN_CALL': params_in_call} | |
1040 return template.substitute(values) | 1004 return template.substitute(values) |
1041 | 1005 |
1042 def GetNativeMethodStubString(self, native): | 1006 def GetNativeMethodStubString(self, native): |
1043 """Returns stubs for native methods.""" | 1007 """Returns stubs for native methods.""" |
1044 if self.options.native_exports: | 1008 template = Template("""\ |
1045 template_str = """\ | 1009 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { |
1046 __attribute__((visibility("default"))) | |
1047 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, | |
1048 ${PARAMS_IN_DECLARATION}) {""" | |
1049 else: | |
1050 template_str = """\ | |
1051 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" | |
1052 template_str += """ | |
1053 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1010 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
1054 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1011 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
1055 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1012 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1056 } | 1013 } |
1057 """ | 1014 """) |
1058 | |
1059 template = Template(template_str) | |
1060 params = [] | 1015 params = [] |
1061 if not self.options.pure_native_methods: | 1016 if not self.options.pure_native_methods: |
1062 params = ['env', 'jcaller'] | 1017 params = ['env', 'jcaller'] |
1063 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 1018 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
1064 | 1019 |
1065 return_type = JavaDataTypeToC(native.return_type) | 1020 return_type = JavaDataTypeToC(native.return_type) |
1066 optional_error_return = JavaReturnValueToC(native.return_type) | 1021 optional_error_return = JavaReturnValueToC(native.return_type) |
1067 if optional_error_return: | 1022 if optional_error_return: |
1068 optional_error_return = ', ' + optional_error_return | 1023 optional_error_return = ', ' + optional_error_return |
1069 post_call = '' | 1024 post_call = '' |
1070 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 1025 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
1071 post_call = '.Release()' | 1026 post_call = '.Release()' |
1072 | |
1073 if self.options.native_exports: | |
1074 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
1075 java_name = java_name.replace('_', '_1').replace('/', '_') | |
1076 if native.java_class_name: | |
1077 java_name += '_00024' + native.java_class_name | |
1078 else: | |
1079 java_name = '' | |
1080 | |
1081 values = { | 1027 values = { |
1082 'RETURN': return_type, | 1028 'RETURN': return_type, |
1083 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1029 'OPTIONAL_ERROR_RETURN': optional_error_return, |
1084 'JAVA_NAME': java_name, | |
1085 'NAME': native.name, | 1030 'NAME': native.name, |
1086 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1031 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
1087 'PARAM0_NAME': native.params[0].name, | 1032 'PARAM0_NAME': native.params[0].name, |
1088 'P0_TYPE': native.p0_type, | 1033 'P0_TYPE': native.p0_type, |
1089 'PARAMS_IN_CALL': params_in_call, | 1034 'PARAMS_IN_CALL': params_in_call, |
1090 'POST_CALL': post_call | 1035 'POST_CALL': post_call |
1091 } | 1036 } |
1092 return template.substitute(values) | 1037 return template.substitute(values) |
1093 | 1038 |
1094 def GetArgument(self, param): | 1039 def GetArgument(self, param): |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 ret[class_name] = jni_class_path | 1167 ret[class_name] = jni_class_path |
1223 return ret | 1168 return ret |
1224 | 1169 |
1225 def GetClassPathDefinitions(self): | 1170 def GetClassPathDefinitions(self): |
1226 """Returns the ClassPath constants.""" | 1171 """Returns the ClassPath constants.""" |
1227 ret = [] | 1172 ret = [] |
1228 template = Template("""\ | 1173 template = Template("""\ |
1229 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1174 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
1230 native_classes = self.GetUniqueClasses(self.natives) | 1175 native_classes = self.GetUniqueClasses(self.natives) |
1231 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1176 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) |
1232 if self.options.native_exports: | 1177 all_classes = native_classes |
1233 all_classes = called_by_native_classes | 1178 all_classes.update(called_by_native_classes) |
1234 else: | |
1235 all_classes = native_classes | |
1236 all_classes.update(called_by_native_classes) | |
1237 | |
1238 for clazz in all_classes: | 1179 for clazz in all_classes: |
1239 values = { | 1180 values = { |
1240 'JAVA_CLASS': clazz, | 1181 'JAVA_CLASS': clazz, |
1241 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), | 1182 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), |
1242 } | 1183 } |
1243 ret += [template.substitute(values)] | 1184 ret += [template.substitute(values)] |
1244 ret += '' | 1185 ret += '' |
1245 for clazz in called_by_native_classes: | 1186 for clazz in called_by_native_classes: |
1246 template = Template("""\ | 1187 template = Template("""\ |
1247 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1188 // Leaking this jclass as we cannot use LazyInstance from some threads. |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1446 'will limit the initialization to only the ' | 1387 'will limit the initialization to only the ' |
1447 'top-level class.') | 1388 'top-level class.') |
1448 option_parser.add_option('--eager_called_by_natives', | 1389 option_parser.add_option('--eager_called_by_natives', |
1449 action='store_true', dest='eager_called_by_natives', | 1390 action='store_true', dest='eager_called_by_natives', |
1450 help='When true, the called-by-native methods will ' | 1391 help='When true, the called-by-native methods will ' |
1451 'be initialized in a non-atomic way.') | 1392 'be initialized in a non-atomic way.') |
1452 option_parser.add_option('--cpp', default='cpp', | 1393 option_parser.add_option('--cpp', default='cpp', |
1453 help='The path to cpp command.') | 1394 help='The path to cpp command.') |
1454 option_parser.add_option('--javap', default='javap', | 1395 option_parser.add_option('--javap', default='javap', |
1455 help='The path to javap command.') | 1396 help='The path to javap command.') |
1456 option_parser.add_option('--native_exports', action='store_true', | |
1457 help='Native method registration through .so ' | |
1458 'exports.') | |
1459 options, args = option_parser.parse_args(argv) | 1397 options, args = option_parser.parse_args(argv) |
1460 if options.jar_file: | 1398 if options.jar_file: |
1461 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1399 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1462 options.output_dir) | 1400 options.output_dir) |
1463 elif options.input_file: | 1401 elif options.input_file: |
1464 input_file = options.input_file | 1402 input_file = options.input_file |
1465 else: | 1403 else: |
1466 option_parser.print_help() | 1404 option_parser.print_help() |
1467 print '\nError: Must specify --jar_file or --input_file.' | 1405 print '\nError: Must specify --jar_file or --input_file.' |
1468 return 1 | 1406 return 1 |
1469 output_file = None | 1407 output_file = None |
1470 if options.output_dir: | 1408 if options.output_dir: |
1471 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1409 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1472 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1410 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1473 if options.jarjar: | 1411 if options.jarjar: |
1474 with open(options.jarjar) as f: | 1412 with open(options.jarjar) as f: |
1475 JniParams.SetJarJarMappings(f.read()) | 1413 JniParams.SetJarJarMappings(f.read()) |
1476 GenerateJNIHeader(input_file, output_file, options) | 1414 GenerateJNIHeader(input_file, output_file, options) |
1477 | 1415 |
1478 | 1416 |
1479 if __name__ == '__main__': | 1417 if __name__ == '__main__': |
1480 sys.exit(main(sys.argv)) | 1418 sys.exit(main(sys.argv)) |
OLD | NEW |