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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 DCHECK_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 DCHECK_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 Loading... |
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 Loading... |
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)) |
OLD | NEW |