| 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 | 69 |
| 70 def __init__(self, **kwargs): | 70 def __init__(self, **kwargs): |
| 71 self.system_class = kwargs['system_class'] | 71 self.system_class = kwargs['system_class'] |
| 72 self.unchecked = kwargs['unchecked'] | 72 self.unchecked = kwargs['unchecked'] |
| 73 self.static = kwargs['static'] | 73 self.static = kwargs['static'] |
| 74 self.java_class_name = kwargs['java_class_name'] | 74 self.java_class_name = kwargs['java_class_name'] |
| 75 self.return_type = kwargs['return_type'] | 75 self.return_type = kwargs['return_type'] |
| 76 self.name = kwargs['name'] | 76 self.name = kwargs['name'] |
| 77 self.params = kwargs['params'] | 77 self.params = kwargs['params'] |
| 78 self.method_id_var_name = kwargs.get('method_id_var_name', None) | 78 self.method_id_var_name = kwargs.get('method_id_var_name', None) |
| 79 self.signature = kwargs.get('signature') |
| 79 self.is_constructor = kwargs.get('is_constructor', False) | 80 self.is_constructor = kwargs.get('is_constructor', False) |
| 80 self.env_call = GetEnvCall(self.is_constructor, self.static, | 81 self.env_call = GetEnvCall(self.is_constructor, self.static, |
| 81 self.return_type) | 82 self.return_type) |
| 82 self.static_cast = GetStaticCastForReturnType(self.return_type) | 83 self.static_cast = GetStaticCastForReturnType(self.return_type) |
| 83 | 84 |
| 84 | 85 |
| 85 def JavaDataTypeToC(java_type): | 86 def JavaDataTypeToC(java_type): |
| 86 """Returns a C datatype for the given java type.""" | 87 """Returns a C datatype for the given java type.""" |
| 87 java_pod_type_map = { | 88 java_pod_type_map = { |
| 88 'int': 'jint', | 89 'int': 'jint', |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 JniParams._imports += ['L' + match.group('class').replace('.', '/')] | 135 JniParams._imports += ['L' + match.group('class').replace('.', '/')] |
| 135 | 136 |
| 136 re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W') | 137 re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W') |
| 137 for match in re.finditer(re_inner, contents): | 138 for match in re.finditer(re_inner, contents): |
| 138 inner = match.group('name') | 139 inner = match.group('name') |
| 139 if not JniParams._fully_qualified_class.endswith(inner): | 140 if not JniParams._fully_qualified_class.endswith(inner): |
| 140 JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + | 141 JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + |
| 141 inner] | 142 inner] |
| 142 | 143 |
| 143 @staticmethod | 144 @staticmethod |
| 145 def ParseJavaPSignature(signature_line): |
| 146 prefix = 'Signature: ' |
| 147 return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):] |
| 148 |
| 149 @staticmethod |
| 144 def JavaToJni(param): | 150 def JavaToJni(param): |
| 145 """Converts a java param into a JNI signature type.""" | 151 """Converts a java param into a JNI signature type.""" |
| 146 pod_param_map = { | 152 pod_param_map = { |
| 147 'int': 'I', | 153 'int': 'I', |
| 148 'boolean': 'Z', | 154 'boolean': 'Z', |
| 149 'char': 'C', | 155 'char': 'C', |
| 150 'short': 'S', | 156 'short': 'S', |
| 151 'long': 'J', | 157 'long': 'J', |
| 152 'double': 'D', | 158 'double': 'D', |
| 153 'float': 'F', | 159 'float': 'F', |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 # Java 7's javap includes type parameters in output, like HashSet<T>. Strip | 465 # Java 7's javap includes type parameters in output, like HashSet<T>. Strip |
| 460 # away the <...> and use the raw class name that Java 6 would've given us. | 466 # away the <...> and use the raw class name that Java 6 would've given us. |
| 461 self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0] | 467 self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0] |
| 462 JniParams.SetFullyQualifiedClass(self.fully_qualified_class) | 468 JniParams.SetFullyQualifiedClass(self.fully_qualified_class) |
| 463 self.java_class_name = self.fully_qualified_class.split('/')[-1] | 469 self.java_class_name = self.fully_qualified_class.split('/')[-1] |
| 464 if not self.namespace: | 470 if not self.namespace: |
| 465 self.namespace = 'JNI_' + self.java_class_name | 471 self.namespace = 'JNI_' + self.java_class_name |
| 466 re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)' | 472 re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)' |
| 467 '\((?P<params>.*?)\)') | 473 '\((?P<params>.*?)\)') |
| 468 self.called_by_natives = [] | 474 self.called_by_natives = [] |
| 469 for content in contents[2:]: | 475 for lineno, content in enumerate(contents[2:], 2): |
| 470 match = re.match(re_method, content) | 476 match = re.match(re_method, content) |
| 471 if not match: | 477 if not match: |
| 472 continue | 478 continue |
| 473 self.called_by_natives += [CalledByNative( | 479 self.called_by_natives += [CalledByNative( |
| 474 system_class=True, | 480 system_class=True, |
| 475 unchecked=False, | 481 unchecked=False, |
| 476 static='static' in match.group('prefix'), | 482 static='static' in match.group('prefix'), |
| 477 java_class_name='', | 483 java_class_name='', |
| 478 return_type=match.group('return_type').replace('.', '/'), | 484 return_type=match.group('return_type').replace('.', '/'), |
| 479 name=match.group('name'), | 485 name=match.group('name'), |
| 480 params=JniParams.Parse(match.group('params').replace('.', '/')))] | 486 params=JniParams.Parse(match.group('params').replace('.', '/')), |
| 481 re_constructor = re.compile('.*? public ' + | 487 signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))] |
| 488 re_constructor = re.compile('(.*?)public ' + |
| 482 self.fully_qualified_class.replace('/', '.') + | 489 self.fully_qualified_class.replace('/', '.') + |
| 483 '\((?P<params>.*?)\)') | 490 '\((?P<params>.*?)\)') |
| 484 for content in contents[2:]: | 491 for lineno, content in enumerate(contents[2:], 2): |
| 485 match = re.match(re_constructor, content) | 492 match = re.match(re_constructor, content) |
| 486 if not match: | 493 if not match: |
| 487 continue | 494 continue |
| 488 self.called_by_natives += [CalledByNative( | 495 self.called_by_natives += [CalledByNative( |
| 489 system_class=True, | 496 system_class=True, |
| 490 unchecked=False, | 497 unchecked=False, |
| 491 static=False, | 498 static=False, |
| 492 java_class_name='', | 499 java_class_name='', |
| 493 return_type=self.fully_qualified_class, | 500 return_type=self.fully_qualified_class, |
| 494 name='Constructor', | 501 name='Constructor', |
| 495 params=JniParams.Parse(match.group('params').replace('.', '/')), | 502 params=JniParams.Parse(match.group('params').replace('.', '/')), |
| 503 signature=JniParams.ParseJavaPSignature(contents[lineno + 1]), |
| 496 is_constructor=True)] | 504 is_constructor=True)] |
| 497 self.called_by_natives = MangleCalledByNatives(self.called_by_natives) | 505 self.called_by_natives = MangleCalledByNatives(self.called_by_natives) |
| 498 self.inl_header_file_generator = InlHeaderFileGenerator( | 506 self.inl_header_file_generator = InlHeaderFileGenerator( |
| 499 self.namespace, self.fully_qualified_class, [], | 507 self.namespace, self.fully_qualified_class, [], |
| 500 self.called_by_natives, options) | 508 self.called_by_natives, options) |
| 501 | 509 |
| 502 def GetContent(self): | 510 def GetContent(self): |
| 503 return self.inl_header_file_generator.GetContent() | 511 return self.inl_header_file_generator.GetContent() |
| 504 | 512 |
| 505 @staticmethod | 513 @staticmethod |
| 506 def CreateFromClass(class_file, options): | 514 def CreateFromClass(class_file, options): |
| 507 class_name = os.path.splitext(os.path.basename(class_file))[0] | 515 class_name = os.path.splitext(os.path.basename(class_file))[0] |
| 508 p = subprocess.Popen(args=['javap', class_name], | 516 p = subprocess.Popen(args=['javap', '-s', class_name], |
| 509 cwd=os.path.dirname(class_file), | 517 cwd=os.path.dirname(class_file), |
| 510 stdout=subprocess.PIPE, | 518 stdout=subprocess.PIPE, |
| 511 stderr=subprocess.PIPE) | 519 stderr=subprocess.PIPE) |
| 512 stdout, _ = p.communicate() | 520 stdout, _ = p.communicate() |
| 513 jni_from_javap = JNIFromJavaP(stdout.split('\n'), options) | 521 jni_from_javap = JNIFromJavaP(stdout.split('\n'), options) |
| 514 return jni_from_javap | 522 return jni_from_javap |
| 515 | 523 |
| 516 | 524 |
| 517 class JNIFromJavaSource(object): | 525 class JNIFromJavaSource(object): |
| 518 """Uses the given java source file to generate the JNI header file.""" | 526 """Uses the given java source file to generate the JNI header file.""" |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 env, g_${JAVA_CLASS}_clazz, | 932 env, g_${JAVA_CLASS}_clazz, |
| 925 "${JNI_NAME}", | 933 "${JNI_NAME}", |
| 926 ${JNI_SIGNATURE}, | 934 ${JNI_SIGNATURE}, |
| 927 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); | 935 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); |
| 928 """) | 936 """) |
| 929 jni_name = called_by_native.name | 937 jni_name = called_by_native.name |
| 930 jni_return_type = called_by_native.return_type | 938 jni_return_type = called_by_native.return_type |
| 931 if called_by_native.is_constructor: | 939 if called_by_native.is_constructor: |
| 932 jni_name = '<init>' | 940 jni_name = '<init>' |
| 933 jni_return_type = 'void' | 941 jni_return_type = 'void' |
| 942 if called_by_native.signature: |
| 943 signature = called_by_native.signature |
| 944 else: |
| 945 signature = JniParams.Signature(called_by_native.params, |
| 946 jni_return_type, |
| 947 True) |
| 934 values = { | 948 values = { |
| 935 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, | 949 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, |
| 936 'JNI_NAME': jni_name, | 950 'JNI_NAME': jni_name, |
| 937 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 951 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
| 938 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', | 952 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', |
| 939 'JNI_SIGNATURE': JniParams.Signature(called_by_native.params, | 953 'JNI_SIGNATURE': signature, |
| 940 jni_return_type, | |
| 941 True) | |
| 942 } | 954 } |
| 943 return template.substitute(values) | 955 return template.substitute(values) |
| 944 | 956 |
| 945 | 957 |
| 946 def WrapOutput(output): | 958 def WrapOutput(output): |
| 947 ret = [] | 959 ret = [] |
| 948 for line in output.splitlines(): | 960 for line in output.splitlines(): |
| 949 # Do not wrap lines under 80 characters or preprocessor directives. | 961 # Do not wrap lines under 80 characters or preprocessor directives. |
| 950 if len(line) < 80 or line.lstrip()[:1] == '#': | 962 if len(line) < 80 or line.lstrip()[:1] == '#': |
| 951 stripped = line.rstrip() | 963 stripped = line.rstrip() |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1088 root_name = os.path.splitext(os.path.basename(input_file))[0] |
| 1077 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1089 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
| 1078 if options.jarjar: | 1090 if options.jarjar: |
| 1079 with open(options.jarjar) as f: | 1091 with open(options.jarjar) as f: |
| 1080 JniParams.SetJarJarMappings(f.read()) | 1092 JniParams.SetJarJarMappings(f.read()) |
| 1081 GenerateJNIHeader(input_file, output_file, options) | 1093 GenerateJNIHeader(input_file, output_file, options) |
| 1082 | 1094 |
| 1083 | 1095 |
| 1084 if __name__ == '__main__': | 1096 if __name__ == '__main__': |
| 1085 sys.exit(main(sys.argv)) | 1097 sys.exit(main(sys.argv)) |
| OLD | NEW |