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 796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 807 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
808 } | 808 } |
809 ret += [template.substitute(values)] | 809 ret += [template.substitute(values)] |
810 return '\n'.join(ret) | 810 return '\n'.join(ret) |
811 | 811 |
812 def GetForwardDeclarationsString(self): | 812 def GetForwardDeclarationsString(self): |
813 ret = [] | 813 ret = [] |
814 for native in self.natives: | 814 for native in self.natives: |
815 if native.type != 'method': | 815 if native.type != 'method': |
816 ret += [self.GetForwardDeclaration(native)] | 816 ret += [self.GetForwardDeclaration(native)] |
| 817 if self.options.native_exports and ret: |
| 818 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' |
817 return '\n'.join(ret) | 819 return '\n'.join(ret) |
818 | 820 |
819 def GetConstantFieldsString(self): | 821 def GetConstantFieldsString(self): |
820 if not self.constant_fields: | 822 if not self.constant_fields: |
821 return '' | 823 return '' |
822 ret = ['enum Java_%s_constant_fields {' % self.class_name] | 824 ret = ['enum Java_%s_constant_fields {' % self.class_name] |
823 for c in self.constant_fields: | 825 for c in self.constant_fields: |
824 ret += [' %s = %s,' % (c.name, c.value)] | 826 ret += [' %s = %s,' % (c.name, c.value)] |
825 ret += ['};'] | 827 ret += ['};'] |
826 return '\n'.join(ret) | 828 return '\n'.join(ret) |
827 | 829 |
828 def GetMethodStubsString(self): | 830 def GetMethodStubsString(self): |
829 """Returns the code corresponding to method stubs.""" | 831 """Returns the code corresponding to method stubs.""" |
830 ret = [] | 832 ret = [] |
831 for native in self.natives: | 833 for native in self.natives: |
832 if native.type == 'method': | 834 if native.type == 'method': |
833 ret += [self.GetNativeMethodStubString(native)] | 835 ret += [self.GetNativeMethodStubString(native)] |
834 if self.options.eager_called_by_natives: | 836 if self.options.eager_called_by_natives: |
835 ret += self.GetEagerCalledByNativeMethodStubs() | 837 ret += self.GetEagerCalledByNativeMethodStubs() |
836 else: | 838 else: |
837 ret += self.GetLazyCalledByNativeMethodStubs() | 839 ret += self.GetLazyCalledByNativeMethodStubs() |
| 840 |
| 841 if self.options.native_exports and ret: |
| 842 return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' |
838 return '\n'.join(ret) | 843 return '\n'.join(ret) |
839 | 844 |
840 def GetLazyCalledByNativeMethodStubs(self): | 845 def GetLazyCalledByNativeMethodStubs(self): |
841 return [self.GetLazyCalledByNativeMethodStub(called_by_native) | 846 return [self.GetLazyCalledByNativeMethodStub(called_by_native) |
842 for called_by_native in self.called_by_natives] | 847 for called_by_native in self.called_by_natives] |
843 | 848 |
844 def GetEagerCalledByNativeMethodStubs(self): | 849 def GetEagerCalledByNativeMethodStubs(self): |
845 ret = [] | 850 ret = [] |
846 if self.called_by_natives: | 851 if self.called_by_natives: |
847 ret += ['namespace {'] | 852 ret += ['namespace {'] |
(...skipping 25 matching lines...) Expand all Loading... |
873 kmethods = self.GetKMethodsString(clazz) | 878 kmethods = self.GetKMethodsString(clazz) |
874 if kmethods: | 879 if kmethods: |
875 values = {'JAVA_CLASS': clazz, | 880 values = {'JAVA_CLASS': clazz, |
876 'KMETHODS': kmethods} | 881 'KMETHODS': kmethods} |
877 ret += [template.substitute(values)] | 882 ret += [template.substitute(values)] |
878 if not ret: return '' | 883 if not ret: return '' |
879 return '\n' + '\n'.join(ret) | 884 return '\n' + '\n'.join(ret) |
880 | 885 |
881 def GetJNINativeMethodsString(self): | 886 def GetJNINativeMethodsString(self): |
882 """Returns the implementation of the array of native methods.""" | 887 """Returns the implementation of the array of native methods.""" |
| 888 if self.options.native_exports: |
| 889 return '' |
883 template = Template("""\ | 890 template = Template("""\ |
884 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 891 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
885 ${KMETHODS} | 892 ${KMETHODS} |
886 }; | 893 }; |
887 """) | 894 """) |
888 return self.SubstituteNativeMethods(template) | 895 return self.SubstituteNativeMethods(template) |
889 | 896 |
890 def GetRegisterCalledByNativesImplString(self): | 897 def GetRegisterCalledByNativesImplString(self): |
891 """Returns the code for registering the called by native methods.""" | 898 """Returns the code for registering the called by native methods.""" |
892 if not self.options.eager_called_by_natives: | 899 if not self.options.eager_called_by_natives: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 called_by_natives = self.GetRegisterCalledByNativesImplString() | 934 called_by_natives = self.GetRegisterCalledByNativesImplString() |
928 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 935 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
929 'CLASSES': self.GetFindClasses(), | 936 'CLASSES': self.GetFindClasses(), |
930 'NATIVES': natives, | 937 'NATIVES': natives, |
931 'CALLED_BY_NATIVES': called_by_natives, | 938 'CALLED_BY_NATIVES': called_by_natives, |
932 } | 939 } |
933 return template.substitute(values) | 940 return template.substitute(values) |
934 | 941 |
935 def GetRegisterNativesImplString(self): | 942 def GetRegisterNativesImplString(self): |
936 """Returns the shared implementation for RegisterNatives.""" | 943 """Returns the shared implementation for RegisterNatives.""" |
| 944 if self.options.native_exports: |
| 945 return '' |
| 946 |
937 template = Template("""\ | 947 template = Template("""\ |
938 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 948 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
939 | 949 |
940 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, | 950 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, |
941 kMethods${JAVA_CLASS}, | 951 kMethods${JAVA_CLASS}, |
942 kMethods${JAVA_CLASS}Size) < 0) { | 952 kMethods${JAVA_CLASS}Size) < 0) { |
943 jni_generator::HandleRegistrationError( | 953 jni_generator::HandleRegistrationError( |
944 env, g_${JAVA_CLASS}_clazz, __FILE__); | 954 env, g_${JAVA_CLASS}_clazz, __FILE__); |
945 return false; | 955 return false; |
946 } | 956 } |
947 """) | 957 """) |
948 return self.SubstituteNativeMethods(template) | 958 return self.SubstituteNativeMethods(template) |
949 | 959 |
950 def GetJNIRegisterNativesString(self): | 960 def GetJNIRegisterNativesString(self): |
951 """Returns the implementation for the JNI registration of native methods.""" | 961 """Returns the implementation for the JNI registration of native methods.""" |
952 if not self.init_native: | 962 if not self.init_native: |
953 return '' | 963 return '' |
954 | 964 |
955 template = Template("""\ | 965 template = Template("""\ |
956 extern "C" JNIEXPORT bool JNICALL | 966 extern "C" JNIEXPORT bool JNICALL |
957 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { | 967 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { |
958 return ${NAMESPACE}RegisterNativesImpl(env, clazz); | 968 return ${NAMESPACE}RegisterNativesImpl(env, clazz); |
959 } | 969 } |
960 """) | 970 """) |
961 fully_qualified_class = self.fully_qualified_class.replace('/', '_') | 971 |
| 972 if self.options.native_exports: |
| 973 java_name = JniParams.RemapClassName(self.fully_qualified_class) |
| 974 java_name = java_name.replace('_', '_1').replace('/', '_') |
| 975 else: |
| 976 java_name = self.fully_qualified_class.replace('/', '_') |
| 977 |
962 namespace = '' | 978 namespace = '' |
963 if self.namespace: | 979 if self.namespace: |
964 namespace = self.namespace + '::' | 980 namespace = self.namespace + '::' |
965 values = {'FULLY_QUALIFIED_CLASS': fully_qualified_class, | 981 values = {'FULLY_QUALIFIED_CLASS': java_name, |
966 'INIT_NATIVE_NAME': 'native' + self.init_native.name, | 982 'INIT_NATIVE_NAME': 'native' + self.init_native.name, |
967 'NAMESPACE': namespace, | 983 'NAMESPACE': namespace, |
968 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() | 984 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() |
969 } | 985 } |
970 return template.substitute(values) | 986 return template.substitute(values) |
971 | 987 |
972 def GetOpenNamespaceString(self): | 988 def GetOpenNamespaceString(self): |
973 if self.namespace: | 989 if self.namespace: |
974 all_namespaces = ['namespace %s {' % ns | 990 all_namespaces = ['namespace %s {' % ns |
975 for ns in self.namespace.split('::')] | 991 for ns in self.namespace.split('::')] |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 param.name | 1025 param.name |
1010 for param in native.params]) | 1026 for param in native.params]) |
1011 | 1027 |
1012 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 1028 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
1013 return ',\n '.join([ | 1029 return ',\n '.join([ |
1014 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + | 1030 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + |
1015 param.name | 1031 param.name |
1016 for param in called_by_native.params]) | 1032 for param in called_by_native.params]) |
1017 | 1033 |
1018 def GetForwardDeclaration(self, native): | 1034 def GetForwardDeclaration(self, native): |
1019 template = Template(""" | 1035 template_str = """ |
1020 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 1036 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
1021 """) | 1037 """ |
| 1038 if self.options.native_exports: |
| 1039 template_str += """ |
| 1040 __attribute__((visibility("default"))) |
| 1041 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) { |
| 1042 return ${NAME}(${PARAMS_IN_CALL}); |
| 1043 } |
| 1044 """ |
| 1045 template = Template(template_str) |
| 1046 params_in_call = [] |
| 1047 if not self.options.pure_native_methods: |
| 1048 params_in_call = ['env', 'jcaller'] |
| 1049 params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) |
| 1050 |
| 1051 java_name = JniParams.RemapClassName(self.fully_qualified_class) |
| 1052 java_name = java_name.replace('_', '_1').replace('/', '_') |
| 1053 if native.java_class_name: |
| 1054 java_name += '_00024' + native.java_class_name |
| 1055 |
1022 values = {'RETURN': JavaDataTypeToC(native.return_type), | 1056 values = {'RETURN': JavaDataTypeToC(native.return_type), |
1023 'NAME': native.name, | 1057 'NAME': native.name, |
1024 'PARAMS': self.GetParamsInDeclaration(native)} | 1058 'JAVA_NAME': java_name, |
| 1059 'PARAMS': self.GetParamsInDeclaration(native), |
| 1060 'PARAMS_IN_CALL': params_in_call} |
1025 return template.substitute(values) | 1061 return template.substitute(values) |
1026 | 1062 |
1027 def GetNativeMethodStubString(self, native): | 1063 def GetNativeMethodStubString(self, native): |
1028 """Returns stubs for native methods.""" | 1064 """Returns stubs for native methods.""" |
1029 template = Template("""\ | 1065 if self.options.native_exports: |
1030 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { | 1066 template_str = """\ |
| 1067 __attribute__((visibility("default"))) |
| 1068 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, |
| 1069 ${PARAMS_IN_DECLARATION}) {""" |
| 1070 else: |
| 1071 template_str = """\ |
| 1072 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" |
| 1073 template_str += """ |
1031 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1074 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
1032 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1075 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
1033 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1076 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1034 } | 1077 } |
1035 """) | 1078 """ |
| 1079 |
| 1080 template = Template(template_str) |
1036 params = [] | 1081 params = [] |
1037 if not self.options.pure_native_methods: | 1082 if not self.options.pure_native_methods: |
1038 params = ['env', 'jcaller'] | 1083 params = ['env', 'jcaller'] |
1039 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 1084 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
1040 | 1085 |
1041 return_type = JavaDataTypeToC(native.return_type) | 1086 return_type = JavaDataTypeToC(native.return_type) |
1042 optional_error_return = JavaReturnValueToC(native.return_type) | 1087 optional_error_return = JavaReturnValueToC(native.return_type) |
1043 if optional_error_return: | 1088 if optional_error_return: |
1044 optional_error_return = ', ' + optional_error_return | 1089 optional_error_return = ', ' + optional_error_return |
1045 post_call = '' | 1090 post_call = '' |
1046 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 1091 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
1047 post_call = '.Release()' | 1092 post_call = '.Release()' |
| 1093 |
| 1094 if self.options.native_exports: |
| 1095 java_name = JniParams.RemapClassName(self.fully_qualified_class) |
| 1096 java_name = java_name.replace('_', '_1').replace('/', '_') |
| 1097 if native.java_class_name: |
| 1098 java_name += '_00024' + native.java_class_name |
| 1099 else: |
| 1100 java_name = '' |
| 1101 |
1048 values = { | 1102 values = { |
1049 'RETURN': return_type, | 1103 'RETURN': return_type, |
1050 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1104 'OPTIONAL_ERROR_RETURN': optional_error_return, |
| 1105 'JAVA_NAME': java_name, |
1051 'NAME': native.name, | 1106 'NAME': native.name, |
1052 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1107 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
1053 'PARAM0_NAME': native.params[0].name, | 1108 'PARAM0_NAME': native.params[0].name, |
1054 'P0_TYPE': native.p0_type, | 1109 'P0_TYPE': native.p0_type, |
1055 'PARAMS_IN_CALL': params_in_call, | 1110 'PARAMS_IN_CALL': params_in_call, |
1056 'POST_CALL': post_call | 1111 'POST_CALL': post_call |
1057 } | 1112 } |
1058 return template.substitute(values) | 1113 return template.substitute(values) |
1059 | 1114 |
1060 def GetArgument(self, param): | 1115 def GetArgument(self, param): |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1188 ret[class_name] = jni_class_path | 1243 ret[class_name] = jni_class_path |
1189 return ret | 1244 return ret |
1190 | 1245 |
1191 def GetClassPathDefinitions(self): | 1246 def GetClassPathDefinitions(self): |
1192 """Returns the ClassPath constants.""" | 1247 """Returns the ClassPath constants.""" |
1193 ret = [] | 1248 ret = [] |
1194 template = Template("""\ | 1249 template = Template("""\ |
1195 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1250 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
1196 native_classes = self.GetUniqueClasses(self.natives) | 1251 native_classes = self.GetUniqueClasses(self.natives) |
1197 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1252 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) |
1198 all_classes = native_classes | 1253 if self.options.native_exports: |
1199 all_classes.update(called_by_native_classes) | 1254 all_classes = called_by_native_classes |
| 1255 else: |
| 1256 all_classes = native_classes |
| 1257 all_classes.update(called_by_native_classes) |
| 1258 |
1200 for clazz in all_classes: | 1259 for clazz in all_classes: |
1201 values = { | 1260 values = { |
1202 'JAVA_CLASS': clazz, | 1261 'JAVA_CLASS': clazz, |
1203 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), | 1262 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), |
1204 } | 1263 } |
1205 ret += [template.substitute(values)] | 1264 ret += [template.substitute(values)] |
1206 ret += '' | 1265 ret += '' |
1207 for clazz in called_by_native_classes: | 1266 for clazz in called_by_native_classes: |
1208 template = Template("""\ | 1267 template = Template("""\ |
1209 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1268 // Leaking this jclass as we cannot use LazyInstance from some threads. |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1410 'will limit the initialization to only the ' | 1469 'will limit the initialization to only the ' |
1411 'top-level class.') | 1470 'top-level class.') |
1412 option_parser.add_option('--eager_called_by_natives', | 1471 option_parser.add_option('--eager_called_by_natives', |
1413 action='store_true', dest='eager_called_by_natives', | 1472 action='store_true', dest='eager_called_by_natives', |
1414 help='When true, the called-by-native methods will ' | 1473 help='When true, the called-by-native methods will ' |
1415 'be initialized in a non-atomic way.') | 1474 'be initialized in a non-atomic way.') |
1416 option_parser.add_option('--cpp', default='cpp', | 1475 option_parser.add_option('--cpp', default='cpp', |
1417 help='The path to cpp command.') | 1476 help='The path to cpp command.') |
1418 option_parser.add_option('--javap', default='javap', | 1477 option_parser.add_option('--javap', default='javap', |
1419 help='The path to javap command.') | 1478 help='The path to javap command.') |
| 1479 option_parser.add_option('--native_exports', action='store_true', |
| 1480 help='Native method registration through .so ' |
| 1481 'exports.') |
1420 options, args = option_parser.parse_args(argv) | 1482 options, args = option_parser.parse_args(argv) |
1421 if options.jar_file: | 1483 if options.jar_file: |
1422 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1484 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1423 options.output_dir) | 1485 options.output_dir) |
1424 elif options.input_file: | 1486 elif options.input_file: |
1425 input_file = options.input_file | 1487 input_file = options.input_file |
1426 else: | 1488 else: |
1427 option_parser.print_help() | 1489 option_parser.print_help() |
1428 print '\nError: Must specify --jar_file or --input_file.' | 1490 print '\nError: Must specify --jar_file or --input_file.' |
1429 return 1 | 1491 return 1 |
1430 output_file = None | 1492 output_file = None |
1431 if options.output_dir: | 1493 if options.output_dir: |
1432 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1494 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1433 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1495 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1434 if options.jarjar: | 1496 if options.jarjar: |
1435 with open(options.jarjar) as f: | 1497 with open(options.jarjar) as f: |
1436 JniParams.SetJarJarMappings(f.read()) | 1498 JniParams.SetJarJarMappings(f.read()) |
1437 GenerateJNIHeader(input_file, output_file, options) | 1499 GenerateJNIHeader(input_file, output_file, options) |
1438 | 1500 |
1439 if options.depfile: | 1501 if options.depfile: |
1440 build_utils.WriteDepfile( | 1502 build_utils.WriteDepfile( |
1441 options.depfile, | 1503 options.depfile, |
1442 build_utils.GetPythonDependencies()) | 1504 build_utils.GetPythonDependencies()) |
1443 | 1505 |
1444 | 1506 |
1445 if __name__ == '__main__': | 1507 if __name__ == '__main__': |
1446 sys.exit(main(sys.argv)) | 1508 sys.exit(main(sys.argv)) |
OLD | NEW |