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

Side by Side Diff: lib/dom/scripts/systemnative.py

Issue 10513004: Implement v8-like overload resolving. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: . Created 8 years, 6 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/python 1 #!/usr/bin/python
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
3 # for details. All rights reserved. Use of this source code is governed by a 3 # for details. All rights reserved. Use of this source code is governed by a
4 # BSD-style license that can be found in the LICENSE file. 4 # BSD-style license that can be found in the LICENSE file.
5 5
6 """This module provides shared functionality for the systems to generate 6 """This module provides shared functionality for the systems to generate
7 native binding from the IDL database.""" 7 native binding from the IDL database."""
8 8
9 import emitter 9 import emitter
10 import os 10 import os
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 dart_declaration = 'void operator[]=(int index, %s value)' % element_type 736 dart_declaration = 'void operator[]=(int index, %s value)' % element_type
737 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, 737 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration,
738 'Callback', True) 738 'Callback', True)
739 739
740 def _AddOperation(self, info): 740 def _AddOperation(self, info):
741 """ 741 """
742 Arguments: 742 Arguments:
743 info: An OperationInfo object. 743 info: An OperationInfo object.
744 """ 744 """
745 745
746 if 'CheckSecurityForNode' in info.overloads[0].ext_attrs: 746 operation = info.operations[0]
747
748 if 'CheckSecurityForNode' in operation.ext_attrs:
747 # FIXME: exclude from interface as well. 749 # FIXME: exclude from interface as well.
748 return 750 return
749 751
750 html_interface_name = self._HTMLInterfaceName(self._interface.id) 752 html_interface_name = self._HTMLInterfaceName(self._interface.id)
751 html_name = self._html_system.RenameInHtmlLibrary( 753 html_name = self._html_system.RenameInHtmlLibrary(
752 html_interface_name, info.name, implementation_class=True) 754 html_interface_name, info.name, implementation_class=True)
753 755
754 if not html_name and info.name == 'item': 756 if not html_name and info.name == 'item':
755 # FIXME: item should be renamed to operator[], not removed. 757 # FIXME: item should be renamed to operator[], not removed.
756 html_name = 'item' 758 html_name = 'item'
757 759
758 if not html_name: 760 if not html_name:
759 return 761 return
760 762
761 dart_declaration = '%s%s %s(%s)' % ( 763 dart_declaration = '%s%s %s(%s)' % (
762 'static ' if info.IsStatic() else '', 764 'static ' if info.IsStatic() else '',
763 self._DartType(info.type_name), 765 self._DartType(info.type_name),
764 html_name or info.name, 766 html_name,
765 info.ParametersImplementationDeclaration(self._DartType)) 767 info.ParametersImplementationDeclaration(self._DartType))
766 768
767 if 'Custom' in info.overloads[0].ext_attrs: 769 is_custom = 'Custom' in operation.ext_attrs
770 has_optional_arguments = any(IsOptional(argument) for argument in operation. arguments)
771 needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_option al_arguments)
772 if not needs_dispatcher:
773 # Bind directly to native implementation
768 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos) 774 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos)
769 self._GenerateNativeBinding(info.name , argument_count, 775 cpp_callback_name = self._GenerateNativeBinding(
770 dart_declaration, 'Callback', True) 776 info.name, argument_count, dart_declaration, 'Callback', is_custom)
771 return 777 if not is_custom:
778 self._GenerateOperationNativeCallback(operation, operation.arguments, cp p_callback_name)
779 else:
780 self._GenerateDispatcher(info.operations, dart_declaration, [info.name for info in info.param_infos])
781
782 def _GenerateDispatcher(self, operations, dart_declaration, argument_names):
783
784 version = [1]
785 def GenerateChecksAndCall(operation, argument_count, checks):
786 if checks:
787 call = body.Emit(
788 ' if ($CHECKS) {\n'
789 '$!CALL'
790 ' }\n',
791 CHECKS=' && '.join(checks))
792 else:
793 call = body
794 if operation.type.id != 'void':
795 call = call.Emit(' return $!CALL;\n')
796 else:
797 call = call.Emit(' $!CALL;\n'
798 ' return;\n')
799
800 overload_name = '%s_%s' % (operation.id, version[0])
801 version[0] += 1
802 argument_list = ', '.join(argument_names[:argument_count])
803 call.Emit('_%s(%s)' % (overload_name, argument_list))
804
805 dart_declaration = '%s%s _%s(%s)' % (
806 'static ' if operation.is_static else '',
807 self._DartType(operation.type.id), overload_name, argument_list)
808 cpp_callback_name = self._GenerateNativeBinding(
809 overload_name, (0 if operation.is_static else 1) + argument_count,
810 dart_declaration, 'Callback', False)
811 self._GenerateOperationNativeCallback(operation, operation.arguments[:argu ment_count], cpp_callback_name)
772 812
773 body = self._members_emitter.Emit( 813 body = self._members_emitter.Emit(
774 '\n' 814 '\n'
775 ' $DECLARATION {\n' 815 ' $DECLARATION {\n'
776 '$!BODY' 816 '$!BODY'
777 ' }\n', 817 ' }\n',
778 DECLARATION=dart_declaration) 818 DECLARATION=dart_declaration)
779 819
780 if self._interface.id == 'IDBObjectStore' and info.name == 'openCursor': 820 # TODO: Optimize the dispatch to avoid repeated checks.
781 # FIXME: implement v8-like overload resolver and remove this hack. 821 if len(operations) > 1:
782 info.overloads = info.overloads[1:] 822 for operation in operations:
783 823 checks = ['%s === null' % name for name in argument_names]
784 self._native_version = 0 824 for position, argument in enumerate(operation.arguments):
785 overloads = self.CombineOverloads(info.overloads) 825 if IsOptional(argument) and not 'Callback' in argument.ext_attrs:
786 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) 826 GenerateChecksAndCall(operation, position, checks)
787 if fallthrough: 827 checks[position] = '%s is %s' % (argument_names[position], self._DartT ype(argument.type.id))
828 if IsOptional(argument) and 'Callback' in argument.ext_attrs:
829 checks[position] = '(%s or %s === null)' % (checks[position], argume nt_names[position])
830 GenerateChecksAndCall(operation, len(operation.arguments), checks)
788 body.Emit(' throw "Incorrect number or type of arguments";\n'); 831 body.Emit(' throw "Incorrect number or type of arguments";\n');
789 832 else:
790 def CombineOverloads(self, overloads): 833 operation = operations[0]
791 # Combine overloads that can be implemented by the same native method. This 834 for position, argument in list(enumerate(operation.arguments))[::-1]:
792 # undoes the expansion of optional arguments into multiple overloads unless 835 if IsOptional(argument) and not 'Callback' in argument.ext_attrs:
793 # IDL merging has made the overloads necessary. Starting with overload with 836 check = '%s === null' % argument_names[position]
794 # no optional arguments and grow it by adding optional arguments, then the 837 GenerateChecksAndCall(operation, position, [check])
795 # longest overload can serve for all the shorter ones. 838 GenerateChecksAndCall(operation, len(operation.arguments), [])
796 out = []
797 seed_index = 0
798 while seed_index < len(overloads):
799 seed = overloads[seed_index]
800 if len(seed.arguments) > 0 and IsOptional(seed.arguments[-1]):
801 # Must start with no optional arguments.
802 out.append(seed)
803 seed_index += 1
804 continue
805
806 prev = seed
807 probe_index = seed_index + 1
808 while probe_index < len(overloads):
809 probe = overloads[probe_index]
810 # Check that 'probe' extends 'prev' by one optional argument.
811 if len(probe.arguments) != len(prev.arguments) + 1:
812 break
813 if probe.arguments[:-1] != prev.arguments:
814 break
815 if not IsOptional(probe.arguments[-1]):
816 break
817 # See Issue 3177. This test against known implemented types is to
818 # prevent combining a possibly unimplemented type. Combining with an
819 # unimplemented type will cause all set of combined overloads to become
820 # 'unimplemented', even if no argument is passed to the the
821 # unimplemented parameter.
822 if DartType(probe.arguments[-1].type.id) not in [
823 'String', 'int', 'num', 'double', 'bool',
824 'IDBKeyRange']:
825 break
826 probe_index += 1
827 prev = probe
828 out.append(prev)
829 seed_index = probe_index
830
831 return out
832
833 def PrintOverloadsComment(self, emitter, info, indent, note, overloads):
834 emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note)
835 for operation in overloads:
836 params = ', '.join([
837 ('[Optional] ' if IsOptional(arg) else '') + DartType(arg.type.id) + ' '
838 + arg.id for arg in operation.arguments])
839 emitter.Emit('$(INDENT)// $NAME($PARAMS)\n',
840 INDENT=indent,
841 NAME=info.name,
842 PARAMS=params)
843 emitter.Emit('$(INDENT)//\n', INDENT=indent)
844
845 def GenerateDispatch(self, emitter, info, indent, overloads):
846 """Generates a dispatch to one of the overloads.
847
848 Arguments:
849 emitter: an Emitter for the body of a block of code.
850 info: the compound information about the operation and its overloads.
851 indent: an indentation string for generated code.
852 position: the index of the parameter to dispatch on.
853 overloads: a list of the IDLOperations to dispatch.
854
855 Returns True if the dispatch can fall through on failure, False if the code
856 always dispatches.
857 """
858
859 def NullCheck(name):
860 return '%s === null' % name
861
862 def TypeCheck(name, type):
863 return '%s is %s' % (name, type)
864
865 def IsNullable(type):
866 #return type != 'int' and type != 'num'
867 return True
868
869 def PickRequiredCppSingleOperation():
870 # Returns a special case single operation, or None. Check if we dispatch
871 # on RequiredCppParameter arguments. In this case all trailing arguments
872 # must be RequiredCppParameter and there is no need in dispatch.
873 def IsRequiredCppParameter(arg):
874 return 'RequiredCppParameter' in arg.ext_attrs
875 def HasRequiredCppParameters(op):
876 matches = filter(IsRequiredCppParameter, op.arguments)
877 if matches:
878 # Validate all the RequiredCppParameter ones are at the end.
879 rematches = filter(IsRequiredCppParameter,
880 op.arguments[len(op.arguments) - len(matches):])
881 if len(matches) != len(rematches):
882 raise Exception('Invalid RequiredCppParameter - all subsequent '
883 'parameters must also be RequiredCppParameter.')
884 return True
885 return False
886 if any(HasRequiredCppParameters(op) for op in overloads):
887 longest = max(overloads, key=lambda op: len(op.arguments))
888 # Validate all other overloads are prefixes.
889 for op in overloads:
890 for (index, arg) in enumerate(op.arguments):
891 type1 = arg.type.id
892 type2 = longest.arguments[index].type.id
893 if type1 != type2:
894 raise Exception(
895 'Overloads for method %s with RequiredCppParameter have '
896 'inconsistent types %s and %s for parameter #%s' %
897 (info.name, type1, type2, index))
898 return longest
899 return None
900
901 single_operation = PickRequiredCppSingleOperation()
902 if single_operation:
903 self.GenerateSingleOperation(emitter, info, indent, single_operation)
904 return False
905
906 # Print just the interesting sets of overloads.
907 if len(overloads) > 1 or len(info.overloads) > 1:
908 self.PrintOverloadsComment(emitter, info, indent, '', info.overloads)
909 if overloads != info.overloads:
910 self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:',
911 overloads)
912
913 # Match each operation in turn.
914 # TODO: Optimize the dispatch to avoid repeated tests.
915 fallthrough = True
916 for operation in overloads:
917 tests = []
918 for (position, param) in enumerate(info.param_infos):
919 if position < len(operation.arguments):
920 arg = operation.arguments[position]
921 dart_type = self._DartType(arg.type.id)
922 if dart_type == param.dart_type:
923 # The overload type matches the method parameter type exactly. We
924 # will have already tested this type in checked mode, and the target
925 # will expect (i.e. check) this type. This case happens when all
926 # the overloads have the same type in this position, including the
927 # trivial case of one overload.
928 test = None
929 else:
930 test = TypeCheck(param.name, dart_type)
931 if IsNullable(dart_type) or IsOptional(arg):
932 test = '(%s || %s)' % (NullCheck(param.name), test)
933 else:
934 test = NullCheck(param.name)
935 if test:
936 tests.append(test)
937 if tests:
938 cond = ' && '.join(tests)
939 if len(cond) + len(indent) + 7 > 80:
940 cond = (' &&\n' + indent + ' ').join(tests)
941 call = emitter.Emit(
942 '$(INDENT)if ($COND) {\n'
943 '$!CALL'
944 '$(INDENT)}\n',
945 COND=cond,
946 INDENT=indent)
947 self.GenerateSingleOperation(call, info, indent + ' ', operation)
948 else:
949 self.GenerateSingleOperation(emitter, info, indent, operation)
950 fallthrough = False
951 return fallthrough
952 839
953 def AddOperation(self, info): 840 def AddOperation(self, info):
954 self._AddOperation(info) 841 self._AddOperation(info)
955 842
956 def AddStaticOperation(self, info): 843 def AddStaticOperation(self, info):
957 self._AddOperation(info) 844 self._AddOperation(info)
958 845
959 def AddSecondaryOperation(self, interface, info): 846 def AddSecondaryOperation(self, interface, info):
960 self.AddOperation(info) 847 self.AddOperation(info)
961 848
962 def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): 849 def _GenerateOperationNativeCallback(self, operation, arguments, cpp_callback_ name):
963 """Generates a call to a single operation.
964
965 Arguments:
966 dispatch_emitter: an dispatch_emitter for the body of a block of code.
967 info: the compound information about the operation and its overloads.
968 indent: an indentation string for generated code.
969 operation: the IDLOperation to call.
970 """
971
972 self._native_version += 1
973 native_name = info.name
974 if self._native_version > 1:
975 native_name = '%s_%s' % (native_name, self._native_version)
976 argument_list = ', '.join([info.param_infos[i].name
977 for (i, arg) in enumerate(operation.arguments)])
978
979 # Generate dispatcher.
980 if info.type_name != 'void':
981 dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n',
982 INDENT=indent,
983 NATIVENAME=native_name,
984 ARGS=argument_list)
985 else:
986 dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n'
987 '$(INDENT)return;\n',
988 INDENT=indent,
989 NATIVENAME=native_name,
990 ARGS=argument_list)
991 # Generate binding.
992 modifier = ''
993 if operation.is_static:
994 modifier = 'static '
995 dart_declaration = '%s%s _%s(%s)' % (modifier, self._DartType(info.type_name ), native_name,
996 argument_list)
997 is_custom = 'Custom' in operation.ext_attrs
998 cpp_callback_name = self._GenerateNativeBinding(
999 native_name, (0 if operation.is_static else 1) + len(operation.arguments ), dart_declaration, 'Callback',
1000 is_custom)
1001 if is_custom:
1002 return
1003
1004 # Generate callback.
1005 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i d) 850 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i d)
1006 851
1007 parameter_definitions_emitter = emitter.Emitter() 852 parameter_definitions_emitter = emitter.Emitter()
1008 arguments = [] 853 cpp_arguments = []
1009 raises_exceptions = self._GenerateCallWithHandling( 854 raises_exceptions = self._GenerateCallWithHandling(
1010 operation, parameter_definitions_emitter, arguments) 855 operation, parameter_definitions_emitter, cpp_arguments)
1011 raises_exceptions = raises_exceptions or len(operation.arguments) > 0 or ope ration.raises 856 raises_exceptions = raises_exceptions or len(arguments) > 0 or operation.rai ses
1012 857
1013 # Process Dart arguments. 858 # Process Dart cpp_arguments.
1014 start_index = 1 859 start_index = 1
1015 if operation.is_static: 860 if operation.is_static:
1016 start_index = 0 861 start_index = 0
1017 for (i, argument) in enumerate(operation.arguments): 862 for (i, argument) in enumerate(arguments):
1018 if (i == len(operation.arguments) - 1 and 863 if (i == len(arguments) - 1 and
1019 self._interface.id == 'Console' and 864 self._interface.id == 'Console' and
1020 argument.id == 'arg'): 865 argument.id == 'arg'):
1021 # FIXME: we are skipping last argument here because it was added in 866 # FIXME: we are skipping last argument here because it was added in
1022 # supplemental dart.idl. Cleanup dart.idl and remove this check. 867 # supplemental dart.idl. Cleanup dart.idl and remove this check.
1023 break 868 break
1024 argument_expression = self._GenerateToNative( 869 argument_expression = self._GenerateToNative(
1025 parameter_definitions_emitter, argument, start_index + i) 870 parameter_definitions_emitter, argument, start_index + i)
1026 arguments.append(argument_expression) 871 cpp_arguments.append(argument_expression)
1027 872
1028 if operation.id in ['addEventListener', 'removeEventListener']: 873 if operation.id in ['addEventListener', 'removeEventListener']:
1029 # addEventListener's and removeEventListener's last argument is marked 874 # addEventListener's and removeEventListener's last argument is marked
1030 # as optional in idl, but is not optional in webcore implementation. 875 # as optional in idl, but is not optional in webcore implementation.
1031 if len(operation.arguments) == 2: 876 if len(arguments) == 2:
1032 arguments.append('false') 877 cpp_arguments.append('false')
1033 878
1034 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty': 879 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty':
1035 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart 880 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart
1036 # idl, but is not optional in webcore implementation. 881 # idl, but is not optional in webcore implementation.
1037 if len(operation.arguments) == 2: 882 if len(arguments) == 2:
1038 arguments.append('String()') 883 cpp_arguments.append('String()')
1039 884
1040 if 'NeedsUserGestureCheck' in operation.ext_attrs: 885 if 'NeedsUserGestureCheck' in operation.ext_attrs:
1041 arguments.append('DartUtilities::processingUserGesture') 886 cpp_arguments.append('DartUtilities::processingUserGesture')
1042 887
1043 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation) 888 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation)
1044 invocation = self._GenerateWebCoreInvocation(function_expression, arguments, 889 invocation = self._GenerateWebCoreInvocation(function_expression, cpp_argume nts,
1045 operation.type.id, operation.ext_attrs, operation.raises) 890 operation.type.id, operation.ext_attrs, operation.raises)
1046 self._GenerateNativeCallback(cpp_callback_name, 891 self._GenerateNativeCallback(cpp_callback_name,
1047 parameter_definitions=parameter_definitions_emitter.Fragments(), 892 parameter_definitions=parameter_definitions_emitter.Fragments(),
1048 needs_receiver=not operation.is_static, invocation=invocation, 893 needs_receiver=not operation.is_static, invocation=invocation,
1049 raises_exceptions=raises_exceptions) 894 raises_exceptions=raises_exceptions)
1050 895
1051 def _GenerateNativeCallback(self, callback_name, parameter_definitions, 896 def _GenerateNativeCallback(self, callback_name, parameter_definitions,
1052 needs_receiver, invocation, raises_exceptions): 897 needs_receiver, invocation, raises_exceptions):
1053 898
1054 if needs_receiver: 899 if needs_receiver:
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 for parent in interface.parents: 1041 for parent in interface.parents:
1197 parent_name = parent.type.id 1042 parent_name = parent.type.id
1198 if not database.HasInterface(parent.type.id): 1043 if not database.HasInterface(parent.type.id):
1199 continue 1044 continue
1200 parent_interface = database.GetInterface(parent.type.id) 1045 parent_interface = database.GetInterface(parent.type.id)
1201 if callback(parent_interface): 1046 if callback(parent_interface):
1202 return parent_interface 1047 return parent_interface
1203 parent_interface = _FindParent(parent_interface, database, callback) 1048 parent_interface = _FindParent(parent_interface, database, callback)
1204 if parent_interface: 1049 if parent_interface:
1205 return parent_interface 1050 return parent_interface
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698