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

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

Powered by Google App Engine
This is Rietveld 408576698