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