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

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

Issue 115103002: Android: sync up latest JNI generator changes from downstream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Adds missing files Created 7 years 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 | Annotate | Revision Log
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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 'short': 'jshort', 92 'short': 'jshort',
93 'boolean': 'jboolean', 93 'boolean': 'jboolean',
94 'long': 'jlong', 94 'long': 'jlong',
95 'double': 'jdouble', 95 'double': 'jdouble',
96 'float': 'jfloat', 96 'float': 'jfloat',
97 } 97 }
98 java_type_map = { 98 java_type_map = {
99 'void': 'void', 99 'void': 'void',
100 'String': 'jstring', 100 'String': 'jstring',
101 'java/lang/String': 'jstring', 101 'java/lang/String': 'jstring',
102 'Class': 'jclass',
103 'java/lang/Class': 'jclass', 102 'java/lang/Class': 'jclass',
104 } 103 }
105 104
106 if java_type in java_pod_type_map: 105 if java_type in java_pod_type_map:
107 return java_pod_type_map[java_type] 106 return java_pod_type_map[java_type]
108 elif java_type in java_type_map: 107 elif java_type in java_type_map:
109 return java_type_map[java_type] 108 return java_type_map[java_type]
110 elif java_type.endswith('[]'): 109 elif java_type.endswith('[]'):
111 if java_type[:-2] in java_pod_type_map: 110 if java_type[:-2] in java_pod_type_map:
112 return java_pod_type_map[java_type[:-2]] + 'Array' 111 return java_pod_type_map[java_type[:-2]] + 'Array'
113 return 'jobjectArray' 112 return 'jobjectArray'
113 elif java_type.startswith('Class'):
114 # Not a simple map lookup, because we need to handle generics.
rmcilroy 2013/12/13 14:14:51 nit - comment might be clearer as something like:
bulach 2013/12/13 15:23:58 Done.
115 return 'jclass'
114 else: 116 else:
115 return 'jobject' 117 return 'jobject'
116 118
117 119
120 def JavaReturnValueToC(java_type):
121 """Returns a valid C return value for the given java type."""
122 java_pod_type_map = {
123 'int': '0',
124 'byte': '0',
125 'char': '0',
126 'short': '0',
127 'boolean': 'false',
128 'long': '0',
129 'double': '0',
130 'float': '0',
131 'void': ''
132 }
133 return java_pod_type_map.get(java_type, 'NULL')
134
135
118 class JniParams(object): 136 class JniParams(object):
119 _imports = [] 137 _imports = []
120 _fully_qualified_class = '' 138 _fully_qualified_class = ''
121 _package = '' 139 _package = ''
122 _inner_classes = [] 140 _inner_classes = []
123 _remappings = [] 141 _remappings = []
124 142
125 @staticmethod 143 @staticmethod
126 def SetFullyQualifiedClass(fully_qualified_class): 144 def SetFullyQualifiedClass(fully_qualified_class):
127 JniParams._fully_qualified_class = 'L' + fully_qualified_class 145 JniParams._fully_qualified_class = 'L' + fully_qualified_class
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 return jni_from_javap 541 return jni_from_javap
524 542
525 543
526 class JNIFromJavaSource(object): 544 class JNIFromJavaSource(object):
527 """Uses the given java source file to generate the JNI header file.""" 545 """Uses the given java source file to generate the JNI header file."""
528 546
529 def __init__(self, contents, fully_qualified_class, options): 547 def __init__(self, contents, fully_qualified_class, options):
530 contents = self._RemoveComments(contents) 548 contents = self._RemoveComments(contents)
531 JniParams.SetFullyQualifiedClass(fully_qualified_class) 549 JniParams.SetFullyQualifiedClass(fully_qualified_class)
532 JniParams.ExtractImportsAndInnerClasses(contents) 550 JniParams.ExtractImportsAndInnerClasses(contents)
533 jni_namespace = ExtractJNINamespace(contents) 551 jni_namespace = ExtractJNINamespace(contents) or options.namespace
534 natives = ExtractNatives(contents, options.ptr_type) 552 natives = ExtractNatives(contents, options.ptr_type)
535 called_by_natives = ExtractCalledByNatives(contents) 553 called_by_natives = ExtractCalledByNatives(contents)
536 if len(natives) == 0 and len(called_by_natives) == 0: 554 if len(natives) == 0 and len(called_by_natives) == 0:
537 raise SyntaxError('Unable to find any JNI methods for %s.' % 555 raise SyntaxError('Unable to find any JNI methods for %s.' %
538 fully_qualified_class) 556 fully_qualified_class)
539 inl_header_file_generator = InlHeaderFileGenerator( 557 inl_header_file_generator = InlHeaderFileGenerator(
540 jni_namespace, fully_qualified_class, natives, called_by_natives, 558 jni_namespace, fully_qualified_class, natives, called_by_natives,
541 options) 559 options)
542 self.content = inl_header_file_generator.GetContent() 560 self.content = inl_header_file_generator.GetContent()
543 561
(...skipping 30 matching lines...) Expand all
574 """Generates an inline header file for JNI integration.""" 592 """Generates an inline header file for JNI integration."""
575 593
576 def __init__(self, namespace, fully_qualified_class, natives, 594 def __init__(self, namespace, fully_qualified_class, natives,
577 called_by_natives, options): 595 called_by_natives, options):
578 self.namespace = namespace 596 self.namespace = namespace
579 self.fully_qualified_class = fully_qualified_class 597 self.fully_qualified_class = fully_qualified_class
580 self.class_name = self.fully_qualified_class.split('/')[-1] 598 self.class_name = self.fully_qualified_class.split('/')[-1]
581 self.natives = natives 599 self.natives = natives
582 self.called_by_natives = called_by_natives 600 self.called_by_natives = called_by_natives
583 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' 601 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
584 self.script_name = options.script_name 602 self.options = options
603 self.init_native = self.ExtractInitNative(options)
604
605 def ExtractInitNative(self, options):
606 for native in self.natives:
607 if options.jni_init_native_name == native.name:
608 self.natives.remove(native)
609 return native
610 return None
585 611
586 def GetContent(self): 612 def GetContent(self):
587 """Returns the content of the JNI binding file.""" 613 """Returns the content of the JNI binding file."""
588 template = Template("""\ 614 template = Template("""\
589 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 615 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
590 // Use of this source code is governed by a BSD-style license that can be 616 // Use of this source code is governed by a BSD-style license that can be
591 // found in the LICENSE file. 617 // found in the LICENSE file.
592 618
593 619
594 // This file is autogenerated by 620 // This file is autogenerated by
595 // ${SCRIPT_NAME} 621 // ${SCRIPT_NAME}
596 // For 622 // For
597 // ${FULLY_QUALIFIED_CLASS} 623 // ${FULLY_QUALIFIED_CLASS}
598 624
599 #ifndef ${HEADER_GUARD} 625 #ifndef ${HEADER_GUARD}
600 #define ${HEADER_GUARD} 626 #define ${HEADER_GUARD}
601 627
602 #include <jni.h> 628 #include <jni.h>
603 629
604 #include "base/android/jni_android.h" 630 ${INCLUDES}
605 #include "base/android/scoped_java_ref.h"
606 #include "base/basictypes.h"
607 #include "base/logging.h"
608
609 using base::android::ScopedJavaLocalRef;
610 631
611 // Step 1: forward declarations. 632 // Step 1: forward declarations.
612 namespace { 633 namespace {
613 $CLASS_PATH_DEFINITIONS 634 $CLASS_PATH_DEFINITIONS
635 $METHOD_ID_DEFINITIONS
614 } // namespace 636 } // namespace
615 637
616 $OPEN_NAMESPACE 638 $OPEN_NAMESPACE
617 $FORWARD_DECLARATIONS 639 $FORWARD_DECLARATIONS
618 640
619 // Step 2: method stubs. 641 // Step 2: method stubs.
620 $METHOD_STUBS 642 $METHOD_STUBS
621 643
622 // Step 3: RegisterNatives. 644 // Step 3: RegisterNatives.
623 645 $JNI_NATIVE_METHODS
624 static bool RegisterNativesImpl(JNIEnv* env) { 646 $REGISTER_NATIVES
625 $REGISTER_NATIVES_IMPL
626 return true;
627 }
628 $CLOSE_NAMESPACE 647 $CLOSE_NAMESPACE
648 $JNI_REGISTER_NATIVES
629 #endif // ${HEADER_GUARD} 649 #endif // ${HEADER_GUARD}
630 """) 650 """)
631 values = { 651 values = {
632 'SCRIPT_NAME': self.script_name, 652 'SCRIPT_NAME': self.options.script_name,
633 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class, 653 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
634 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(), 654 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
655 'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
635 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(), 656 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
636 'METHOD_STUBS': self.GetMethodStubsString(), 657 'METHOD_STUBS': self.GetMethodStubsString(),
637 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), 658 'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
638 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString(), 659 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
660 'REGISTER_NATIVES': self.GetRegisterNativesString(),
639 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), 661 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
640 'HEADER_GUARD': self.header_guard, 662 'HEADER_GUARD': self.header_guard,
663 'INCLUDES': self.GetIncludesString(),
664 'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
641 } 665 }
642 return WrapOutput(template.substitute(values)) 666 return WrapOutput(template.substitute(values))
643 667
644 def GetClassPathDefinitionsString(self): 668 def GetClassPathDefinitionsString(self):
645 ret = [] 669 ret = []
646 ret += [self.GetClassPathDefinitions()] 670 ret += [self.GetClassPathDefinitions()]
647 return '\n'.join(ret) 671 return '\n'.join(ret)
648 672
673 def GetMethodIDDefinitionsString(self):
674 """Returns the definition of method ids for the called by native methods."""
675 if not self.options.eager_called_by_natives:
676 return ''
677 template = Template("""\
678 jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
679 ret = []
680 for called_by_native in self.called_by_natives:
681 values = {
682 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
683 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
684 }
685 ret += [template.substitute(values)]
686 return '\n'.join(ret)
687
649 def GetForwardDeclarationsString(self): 688 def GetForwardDeclarationsString(self):
650 ret = [] 689 ret = []
651 for native in self.natives: 690 for native in self.natives:
652 if native.type != 'method': 691 if native.type != 'method':
653 ret += [self.GetForwardDeclaration(native)] 692 ret += [self.GetForwardDeclaration(native)]
654 return '\n'.join(ret) 693 return '\n'.join(ret)
655 694
656 def GetMethodStubsString(self): 695 def GetMethodStubsString(self):
696 """Returns the code corresponding to method stubs."""
657 ret = [] 697 ret = []
658 for native in self.natives: 698 for native in self.natives:
659 if native.type == 'method': 699 if native.type == 'method':
660 ret += [self.GetNativeMethodStub(native)] 700 ret += [self.GetNativeMethodStubString(native)]
661 for called_by_native in self.called_by_natives: 701 if self.options.eager_called_by_natives:
662 ret += [self.GetCalledByNativeMethodStub(called_by_native)] 702 ret += self.GetEagerCalledByNativeMethodStubs()
703 else:
704 ret += self.GetLazyCalledByNativeMethodStubs()
663 return '\n'.join(ret) 705 return '\n'.join(ret)
664 706
707 def GetLazyCalledByNativeMethodStubs(self):
708 return [self.GetLazyCalledByNativeMethodStub(called_by_native)
709 for called_by_native in self.called_by_natives]
710
711 def GetEagerCalledByNativeMethodStubs(self):
712 ret = []
713 if self.called_by_natives:
714 ret += ['namespace {']
715 for called_by_native in self.called_by_natives:
716 ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
717 ret += ['} // namespace']
718 return ret
719
720 def GetIncludesString(self):
721 if not self.options.includes:
722 return ''
723 includes = self.options.includes.split(',')
724 return '\n'.join('#include "%s"' % x for x in includes)
725
665 def GetKMethodsString(self, clazz): 726 def GetKMethodsString(self, clazz):
666 ret = [] 727 ret = []
667 for native in self.natives: 728 for native in self.natives:
668 if (native.java_class_name == clazz or 729 if (native.java_class_name == clazz or
669 (not native.java_class_name and clazz == self.class_name)): 730 (not native.java_class_name and clazz == self.class_name)):
670 ret += [self.GetKMethodArrayEntry(native)] 731 ret += [self.GetKMethodArrayEntry(native)]
671 return '\n'.join(ret) 732 return '\n'.join(ret)
672 733
673 def GetRegisterNativesImplString(self): 734 def SubstituteNativeMethods(self, template):
674 """Returns the implementation for RegisterNatives.""" 735 """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
675 template = Template("""\ 736 ret = []
676 static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
677 ${KMETHODS}
678 };
679 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
680
681 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
682 kMethods${JAVA_CLASS},
683 kMethods${JAVA_CLASS}Size) < 0) {
684 LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
685 return false;
686 }
687 """)
688 ret = [self.GetFindClasses()]
689 all_classes = self.GetUniqueClasses(self.natives) 737 all_classes = self.GetUniqueClasses(self.natives)
690 all_classes[self.class_name] = self.fully_qualified_class 738 all_classes[self.class_name] = self.fully_qualified_class
691 for clazz in all_classes: 739 for clazz in all_classes:
692 kmethods = self.GetKMethodsString(clazz) 740 kmethods = self.GetKMethodsString(clazz)
693 if kmethods: 741 if kmethods:
694 values = {'JAVA_CLASS': clazz, 742 values = {'JAVA_CLASS': clazz,
695 'KMETHODS': kmethods} 743 'KMETHODS': kmethods}
696 ret += [template.substitute(values)] 744 ret += [template.substitute(values)]
697 if not ret: return '' 745 if not ret: return ''
698 return '\n' + '\n'.join(ret) 746 return '\n' + '\n'.join(ret)
699 747
748 def GetJNINativeMethodsString(self):
749 """Returns the implementation of the array of native methods."""
750 template = Template("""\
751 static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
752 ${KMETHODS}
753 };
754 """)
755 return self.SubstituteNativeMethods(template)
756
757 def GetRegisterCalledByNativesImplString(self):
758 """Returns the code for registering the called by native methods."""
759 if not self.options.eager_called_by_natives:
760 return ''
761 template = Template("""\
762 g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
763 if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
764 return false;
765 }
766 """)
767 ret = []
768 for called_by_native in self.called_by_natives:
769 values = {
770 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
771 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
772 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
773 }
774 ret += [template.substitute(values)]
775 return '\n'.join(ret)
776
777 def GetRegisterNativesString(self):
778 """Returns the code for RegisterNatives."""
779 template = Template("""\
780 ${REGISTER_NATIVES_SIGNATURE} {
781 ${CLASSES}
782 ${NATIVES}
783 ${CALLED_BY_NATIVES}
784 return true;
785 }
786 """)
787 signature = 'static bool RegisterNativesImpl(JNIEnv* env'
788 if self.init_native:
789 signature += ', jclass clazz)'
790 else:
791 signature += ')'
792
793 natives = self.GetRegisterNativesImplString()
794 called_by_natives = self.GetRegisterCalledByNativesImplString()
795 values = {'REGISTER_NATIVES_SIGNATURE': signature,
796 'CLASSES': self.GetFindClasses(),
797 'NATIVES': natives,
798 'CALLED_BY_NATIVES': called_by_natives,
799 }
800 return template.substitute(values)
801
802 def GetRegisterNativesImplString(self):
803 """Returns the shared implementation for RegisterNatives."""
804 template = Template("""\
805 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
806
807 if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
808 kMethods${JAVA_CLASS},
809 kMethods${JAVA_CLASS}Size) < 0) {
810 jni_generator::HandleRegistrationError(
811 env, g_${JAVA_CLASS}_clazz, __FILE__);
812 return false;
813 }
814 """)
815 return self.SubstituteNativeMethods(template)
816
817 def GetJNIRegisterNativesString(self):
818 """Returns the implementation for the JNI registration of native methods."""
819 if not self.init_native:
820 return ''
821
822 template = Template("""\
823 extern "C" JNIEXPORT bool JNICALL
824 Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
825 return ${NAMESPACE}RegisterNativesImpl(env, clazz);
826 }
827 """)
828 fully_qualified_class = self.fully_qualified_class.replace('/', '_')
829 namespace = ''
830 if self.namespace:
831 namespace = self.namespace + '::'
832 values = {'FULLY_QUALIFIED_CLASS': fully_qualified_class,
833 'INIT_NATIVE_NAME': self.init_native.name,
834 'NAMESPACE': namespace,
835 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
836 }
837 return template.substitute(values)
838
700 def GetOpenNamespaceString(self): 839 def GetOpenNamespaceString(self):
701 if self.namespace: 840 if self.namespace:
702 all_namespaces = ['namespace %s {' % ns 841 all_namespaces = ['namespace %s {' % ns
703 for ns in self.namespace.split('::')] 842 for ns in self.namespace.split('::')]
704 return '\n'.join(all_namespaces) 843 return '\n'.join(all_namespaces)
705 return '' 844 return ''
706 845
707 def GetCloseNamespaceString(self): 846 def GetCloseNamespaceString(self):
708 if self.namespace: 847 if self.namespace:
709 all_namespaces = ['} // namespace %s' % ns 848 all_namespaces = ['} // namespace %s' % ns
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
744 883
745 def GetForwardDeclaration(self, native): 884 def GetForwardDeclaration(self, native):
746 template = Template(""" 885 template = Template("""
747 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); 886 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
748 """) 887 """)
749 values = {'RETURN': JavaDataTypeToC(native.return_type), 888 values = {'RETURN': JavaDataTypeToC(native.return_type),
750 'NAME': native.name, 889 'NAME': native.name,
751 'PARAMS': self.GetParamsInDeclaration(native)} 890 'PARAMS': self.GetParamsInDeclaration(native)}
752 return template.substitute(values) 891 return template.substitute(values)
753 892
754 def GetNativeMethodStub(self, native): 893 def GetNativeMethodStubString(self, native):
755 """Returns stubs for native methods.""" 894 """Returns stubs for native methods."""
756 template = Template("""\ 895 template = Template("""\
757 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { 896 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
758 DCHECK(${PARAM0_NAME}) << "${NAME}";
759 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); 897 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
760 return native->${NAME}(env, obj${PARAMS_IN_CALL})${POST_CALL}; 898 DCHECK_NATIVE_PTR(native, "${NAME}"${OPTIONAL_ERROR_RETURN});
899 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
761 } 900 }
762 """) 901 """)
763 params_for_call = ', '.join(p.name for p in native.params[1:]) 902 params = []
764 if params_for_call: 903 if not self.options.pure_native_methods:
765 params_for_call = ', ' + params_for_call 904 params = ['env', 'obj']
905 params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
766 906
767 return_type = JavaDataTypeToC(native.return_type) 907 return_type = JavaDataTypeToC(native.return_type)
908 optional_error_return = JavaReturnValueToC(native.return_type)
909 if optional_error_return:
910 optional_error_return = ', ' + optional_error_return
911 post_call = ''
768 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): 912 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
769 scoped_return_type = 'ScopedJavaLocalRef<' + return_type + '>'
770 post_call = '.Release()' 913 post_call = '.Release()'
771 else:
772 scoped_return_type = return_type
773 post_call = ''
774 values = { 914 values = {
775 'RETURN': return_type, 915 'RETURN': return_type,
776 'SCOPED_RETURN': scoped_return_type, 916 'OPTIONAL_ERROR_RETURN': optional_error_return,
777 'NAME': native.name, 917 'NAME': native.name,
778 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), 918 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
779 'PARAM0_NAME': native.params[0].name, 919 'PARAM0_NAME': native.params[0].name,
780 'P0_TYPE': native.p0_type, 920 'P0_TYPE': native.p0_type,
781 'PARAMS_IN_CALL': params_for_call, 921 'PARAMS_IN_CALL': params_in_call,
782 'POST_CALL': post_call 922 'POST_CALL': post_call
783 } 923 }
784 return template.substitute(values) 924 return template.substitute(values)
785 925
786 def GetCalledByNativeMethodStub(self, called_by_native): 926 def GetCalledByNativeValues(self, called_by_native):
787 """Returns a string.""" 927 """Fills in necessary values for the CalledByNative methods."""
788 function_signature_template = Template("""\
789 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
790 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
791 function_header_template = Template("""\
792 ${FUNCTION_SIGNATURE} {""")
793 function_header_with_unused_template = Template("""\
794 ${FUNCTION_SIGNATURE} __attribute__ ((unused));
795 ${FUNCTION_SIGNATURE} {""")
796 template = Template("""
797 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
798 ${FUNCTION_HEADER}
799 /* Must call RegisterNativesImpl() */
800 DCHECK(g_${JAVA_CLASS}_clazz);
801 jmethodID method_id =
802 ${GET_METHOD_ID_IMPL}
803 ${RETURN_DECLARATION}
804 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
805 method_id${PARAMS_IN_CALL})${POST_CALL};
806 ${CHECK_EXCEPTION}
807 ${RETURN_CLAUSE}
808 }""")
809 if called_by_native.static or called_by_native.is_constructor: 928 if called_by_native.static or called_by_native.is_constructor:
810 first_param_in_declaration = '' 929 first_param_in_declaration = ''
811 first_param_in_call = ('g_%s_clazz' % 930 first_param_in_call = ('g_%s_clazz' %
812 (called_by_native.java_class_name or 931 (called_by_native.java_class_name or
813 self.class_name)) 932 self.class_name))
814 else: 933 else:
815 first_param_in_declaration = ', jobject obj' 934 first_param_in_declaration = ', jobject obj'
816 first_param_in_call = 'obj' 935 first_param_in_call = 'obj'
817 params_in_declaration = self.GetCalledByNativeParamsInDeclaration( 936 params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
818 called_by_native) 937 called_by_native)
819 if params_in_declaration: 938 if params_in_declaration:
820 params_in_declaration = ', ' + params_in_declaration 939 params_in_declaration = ', ' + params_in_declaration
821 params_for_call = ', '.join(param.name 940 params_in_call = ', '.join(param.name for param in called_by_native.params)
822 for param in called_by_native.params) 941 if params_in_call:
823 if params_for_call: 942 params_in_call = ', ' + params_in_call
824 params_for_call = ', ' + params_for_call
825 pre_call = '' 943 pre_call = ''
826 post_call = '' 944 post_call = ''
827 if called_by_native.static_cast: 945 if called_by_native.static_cast:
828 pre_call = 'static_cast<%s>(' % called_by_native.static_cast 946 pre_call = 'static_cast<%s>(' % called_by_native.static_cast
829 post_call = ')' 947 post_call = ')'
830 check_exception = '' 948 check_exception = ''
831 if not called_by_native.unchecked: 949 if not called_by_native.unchecked:
832 check_exception = 'base::android::CheckException(env);' 950 check_exception = 'jni_generator::CheckException(env);'
833 return_type = JavaDataTypeToC(called_by_native.return_type) 951 return_type = JavaDataTypeToC(called_by_native.return_type)
952 optional_error_return = JavaReturnValueToC(called_by_native.return_type)
953 if optional_error_return:
954 optional_error_return = ', ' + optional_error_return
834 return_declaration = '' 955 return_declaration = ''
835 return_clause = '' 956 return_clause = ''
836 if return_type != 'void': 957 if return_type != 'void':
837 pre_call = ' ' + pre_call 958 pre_call = ' ' + pre_call
838 return_declaration = return_type + ' ret =' 959 return_declaration = return_type + ' ret ='
839 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): 960 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
840 return_type = 'ScopedJavaLocalRef<' + return_type + '>' 961 return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
841 return_clause = 'return ' + return_type + '(env, ret);' 962 return_clause = 'return ' + return_type + '(env, ret);'
842 else: 963 else:
843 return_clause = 'return ret;' 964 return_clause = 'return ret;'
844 values = { 965 return {
845 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, 966 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
846 'METHOD': called_by_native.name,
847 'RETURN_TYPE': return_type, 967 'RETURN_TYPE': return_type,
968 'OPTIONAL_ERROR_RETURN': optional_error_return,
848 'RETURN_DECLARATION': return_declaration, 969 'RETURN_DECLARATION': return_declaration,
849 'RETURN_CLAUSE': return_clause, 970 'RETURN_CLAUSE': return_clause,
850 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, 971 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
851 'PARAMS_IN_DECLARATION': params_in_declaration, 972 'PARAMS_IN_DECLARATION': params_in_declaration,
852 'STATIC': 'Static' if called_by_native.static else '',
853 'PRE_CALL': pre_call, 973 'PRE_CALL': pre_call,
854 'POST_CALL': post_call, 974 'POST_CALL': post_call,
855 'ENV_CALL': called_by_native.env_call, 975 'ENV_CALL': called_by_native.env_call,
856 'FIRST_PARAM_IN_CALL': first_param_in_call, 976 'FIRST_PARAM_IN_CALL': first_param_in_call,
857 'PARAMS_IN_CALL': params_for_call, 977 'PARAMS_IN_CALL': params_in_call,
858 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, 978 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
859 'CHECK_EXCEPTION': check_exception, 979 'CHECK_EXCEPTION': check_exception,
860 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native) 980 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
861 } 981 }
982
983 def GetEagerCalledByNativeMethodStub(self, called_by_native):
984 """Returns the implementation of the called by native method."""
985 template = Template("""
986 static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
987 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
988 ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
989 g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
990 ${RETURN_CLAUSE}
991 }""")
992 values = self.GetCalledByNativeValues(called_by_native)
993 return template.substitute(values)
994
995 def GetLazyCalledByNativeMethodStub(self, called_by_native):
996 """Returns a string."""
997 function_signature_template = Template("""\
998 static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
999 JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
1000 function_header_template = Template("""\
1001 ${FUNCTION_SIGNATURE} {""")
1002 function_header_with_unused_template = Template("""\
1003 ${FUNCTION_SIGNATURE} __attribute__ ((unused));
1004 ${FUNCTION_SIGNATURE} {""")
1005 template = Template("""
1006 static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
1007 ${FUNCTION_HEADER}
1008 /* Must call RegisterNativesImpl() */
1009 DCHECK_CLAZZ(g_${JAVA_CLASS}_clazz${OPTIONAL_ERROR_RETURN});
1010 jmethodID method_id =
1011 ${GET_METHOD_ID_IMPL}
1012 ${RETURN_DECLARATION}
1013 ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
1014 method_id${PARAMS_IN_CALL})${POST_CALL};
1015 ${CHECK_EXCEPTION}
1016 ${RETURN_CLAUSE}
1017 }""")
1018 values = self.GetCalledByNativeValues(called_by_native)
862 values['FUNCTION_SIGNATURE'] = ( 1019 values['FUNCTION_SIGNATURE'] = (
863 function_signature_template.substitute(values)) 1020 function_signature_template.substitute(values))
864 if called_by_native.system_class: 1021 if called_by_native.system_class:
865 values['FUNCTION_HEADER'] = ( 1022 values['FUNCTION_HEADER'] = (
866 function_header_with_unused_template.substitute(values)) 1023 function_header_with_unused_template.substitute(values))
867 else: 1024 else:
868 values['FUNCTION_HEADER'] = function_header_template.substitute(values) 1025 values['FUNCTION_HEADER'] = function_header_template.substitute(values)
869 return template.substitute(values) 1026 return template.substitute(values)
870 1027
871 def GetKMethodArrayEntry(self, native): 1028 def GetKMethodArrayEntry(self, native):
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 // Leaking this jclass as we cannot use LazyInstance from some threads. 1066 // Leaking this jclass as we cannot use LazyInstance from some threads.
910 jclass g_${JAVA_CLASS}_clazz = NULL;""") 1067 jclass g_${JAVA_CLASS}_clazz = NULL;""")
911 values = { 1068 values = {
912 'JAVA_CLASS': clazz, 1069 'JAVA_CLASS': clazz,
913 } 1070 }
914 ret += [template.substitute(values)] 1071 ret += [template.substitute(values)]
915 return '\n'.join(ret) 1072 return '\n'.join(ret)
916 1073
917 def GetFindClasses(self): 1074 def GetFindClasses(self):
918 """Returns the imlementation of FindClass for all known classes.""" 1075 """Returns the imlementation of FindClass for all known classes."""
919 template = Template("""\ 1076 if self.init_native:
1077 template = Template("""\
1078 g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
1079 else:
1080 template = Template("""\
920 g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( 1081 g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
921 base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""") 1082 base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
922 ret = [] 1083 ret = []
923 for clazz in self.GetUniqueClasses(self.called_by_natives): 1084 for clazz in self.GetUniqueClasses(self.called_by_natives):
924 values = {'JAVA_CLASS': clazz} 1085 values = {'JAVA_CLASS': clazz}
925 ret += [template.substitute(values)] 1086 ret += [template.substitute(values)]
926 return '\n'.join(ret) 1087 return '\n'.join(ret)
927 1088
928 def GetMethodIDImpl(self, called_by_native): 1089 def GetMethodIDImpl(self, called_by_native):
929 """Returns the implementation of GetMethodID.""" 1090 """Returns the implementation of GetMethodID."""
930 template = Template("""\ 1091 if self.options.eager_called_by_natives:
1092 template = Template("""\
1093 env->Get${STATIC_METHOD_PART}MethodID(
1094 g_${JAVA_CLASS}_clazz,
1095 "${JNI_NAME}", ${JNI_SIGNATURE});""")
1096 else:
1097 template = Template("""\
931 base::android::MethodID::LazyGet< 1098 base::android::MethodID::LazyGet<
932 base::android::MethodID::TYPE_${STATIC}>( 1099 base::android::MethodID::TYPE_${STATIC}>(
933 env, g_${JAVA_CLASS}_clazz, 1100 env, g_${JAVA_CLASS}_clazz,
934 "${JNI_NAME}", 1101 "${JNI_NAME}",
935 ${JNI_SIGNATURE}, 1102 ${JNI_SIGNATURE},
936 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); 1103 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
937 """) 1104 """)
938 jni_name = called_by_native.name 1105 jni_name = called_by_native.name
939 jni_return_type = called_by_native.return_type 1106 jni_return_type = called_by_native.return_type
940 if called_by_native.is_constructor: 1107 if called_by_native.is_constructor:
941 jni_name = '<init>' 1108 jni_name = '<init>'
942 jni_return_type = 'void' 1109 jni_return_type = 'void'
943 if called_by_native.signature: 1110 if called_by_native.signature:
944 signature = called_by_native.signature 1111 signature = called_by_native.signature
945 else: 1112 else:
946 signature = JniParams.Signature(called_by_native.params, 1113 signature = JniParams.Signature(called_by_native.params,
947 jni_return_type, 1114 jni_return_type,
948 True) 1115 True)
949 values = { 1116 values = {
950 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, 1117 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
951 'JNI_NAME': jni_name, 1118 'JNI_NAME': jni_name,
952 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, 1119 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
953 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', 1120 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
1121 'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
954 'JNI_SIGNATURE': signature, 1122 'JNI_SIGNATURE': signature,
955 } 1123 }
956 return template.substitute(values) 1124 return template.substitute(values)
957 1125
958 1126
959 def WrapOutput(output): 1127 def WrapOutput(output):
960 ret = [] 1128 ret = []
961 for line in output.splitlines(): 1129 for line in output.splitlines():
962 # Do not wrap lines under 80 characters or preprocessor directives. 1130 # Do not wrap lines under 80 characters or preprocessor directives.
963 if len(line) < 80 or line.lstrip()[:1] == '#': 1131 if len(line) < 80 or line.lstrip()[:1] == '#':
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 See SampleForTests.java for more details. 1217 See SampleForTests.java for more details.
1050 """ 1218 """
1051 option_parser = optparse.OptionParser(usage=usage) 1219 option_parser = optparse.OptionParser(usage=usage)
1052 option_parser.add_option('-j', dest='jar_file', 1220 option_parser.add_option('-j', dest='jar_file',
1053 help='Extract the list of input files from' 1221 help='Extract the list of input files from'
1054 ' a specified jar file.' 1222 ' a specified jar file.'
1055 ' Uses javap to extract the methods from a' 1223 ' Uses javap to extract the methods from a'
1056 ' pre-compiled class. --input should point' 1224 ' pre-compiled class. --input should point'
1057 ' to pre-compiled Java .class files.') 1225 ' to pre-compiled Java .class files.')
1058 option_parser.add_option('-n', dest='namespace', 1226 option_parser.add_option('-n', dest='namespace',
1059 help='Uses as a namespace in the generated header,' 1227 help='Uses as a namespace in the generated header '
1060 ' instead of the javap class name.') 1228 'instead of the javap class name, or when there is '
1229 'no JNINamespace annotation in the java source.')
1061 option_parser.add_option('--input_file', 1230 option_parser.add_option('--input_file',
1062 help='Single input file name. The output file name ' 1231 help='Single input file name. The output file name '
1063 'will be derived from it. Must be used with ' 1232 'will be derived from it. Must be used with '
1064 '--output_dir.') 1233 '--output_dir.')
1065 option_parser.add_option('--output_dir', 1234 option_parser.add_option('--output_dir',
1066 help='The output directory. Must be used with ' 1235 help='The output directory. Must be used with '
1067 '--input') 1236 '--input')
1068 option_parser.add_option('--optimize_generation', type="int", 1237 option_parser.add_option('--optimize_generation', type="int",
1069 default=0, help='Whether we should optimize JNI ' 1238 default=0, help='Whether we should optimize JNI '
1070 'generation by not regenerating files if they have ' 1239 'generation by not regenerating files if they have '
1071 'not changed.') 1240 'not changed.')
1072 option_parser.add_option('--jarjar', 1241 option_parser.add_option('--jarjar',
1073 help='Path to optional jarjar rules file.') 1242 help='Path to optional jarjar rules file.')
1074 option_parser.add_option('--script_name', default=GetScriptName(), 1243 option_parser.add_option('--script_name', default=GetScriptName(),
1075 help='The name of this script in the generated ' 1244 help='The name of this script in the generated '
1076 'header.') 1245 'header.')
1246 option_parser.add_option('--includes',
1247 help='The comma-separated list of header files to '
1248 'include in the generated header.')
1249 option_parser.add_option('--pure_native_methods',
1250 action='store_true', dest='pure_native_methods',
1251 help='When true, the native methods will be called '
1252 'without any JNI-specific arguments.')
1077 option_parser.add_option('--ptr_type', default='int', 1253 option_parser.add_option('--ptr_type', default='int',
1078 type='choice', choices=['int', 'long'], 1254 type='choice', choices=['int', 'long'],
1079 help='The type used to represent native pointers in ' 1255 help='The type used to represent native pointers in '
1080 'Java code. For 32-bit, use int; ' 1256 'Java code. For 32-bit, use int; '
1081 'for 64-bit, use long.') 1257 'for 64-bit, use long.')
1258 option_parser.add_option('--jni_init_native_name', default='',
1259 help='The name of the JNI registration method that '
1260 'is used to initialize all native methods. If a '
1261 'method with this name is not present in the Java '
1262 'source file, setting this option is a no-op. When '
1263 'a method with this name is found however, the '
1264 'naming convention Java_<packageName>_<className> '
1265 'will limit the initialization to only the '
1266 'top-level class.')
1267 option_parser.add_option('--eager_called_by_natives',
1268 action='store_true', dest='eager_called_by_natives',
1269 help='When true, the called-by-native methods will '
1270 'be initialized in a non-atomic way.')
1082 options, args = option_parser.parse_args(argv) 1271 options, args = option_parser.parse_args(argv)
1083 if options.jar_file: 1272 if options.jar_file:
1084 input_file = ExtractJarInputFile(options.jar_file, options.input_file, 1273 input_file = ExtractJarInputFile(options.jar_file, options.input_file,
1085 options.output_dir) 1274 options.output_dir)
1086 elif options.input_file: 1275 elif options.input_file:
1087 input_file = options.input_file 1276 input_file = options.input_file
1088 else: 1277 else:
1089 option_parser.print_help() 1278 option_parser.print_help()
1090 print '\nError: Must specify --jar_file or --input_file.' 1279 print '\nError: Must specify --jar_file or --input_file.'
1091 return 1 1280 return 1
1092 output_file = None 1281 output_file = None
1093 if options.output_dir: 1282 if options.output_dir:
1094 root_name = os.path.splitext(os.path.basename(input_file))[0] 1283 root_name = os.path.splitext(os.path.basename(input_file))[0]
1095 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' 1284 output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
1096 if options.jarjar: 1285 if options.jarjar:
1097 with open(options.jarjar) as f: 1286 with open(options.jarjar) as f:
1098 JniParams.SetJarJarMappings(f.read()) 1287 JniParams.SetJarJarMappings(f.read())
1099 GenerateJNIHeader(input_file, output_file, options) 1288 GenerateJNIHeader(input_file, output_file, options)
1100 1289
1101 1290
1102 if __name__ == '__main__': 1291 if __name__ == '__main__':
1103 sys.exit(main(sys.argv)) 1292 sys.exit(main(sys.argv))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698