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

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 info.overloads[0].ext_attrs
Anton Muhin 2012/06/04 14:27:37 'Custom' in operation.ext_attrs?
podivilov 2012/06/04 16:12:55 Done.
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])
772 781
782 def _GenerateDispatcher(self, operations, dart_declaration, argument_names):
773 body = self._members_emitter.Emit( 783 body = self._members_emitter.Emit(
774 '\n' 784 '\n'
775 ' $DECLARATION {\n' 785 ' $DECLARATION {\n'
776 '$!BODY' 786 '$!BODY'
777 ' }\n', 787 ' }\n',
778 DECLARATION=dart_declaration) 788 DECLARATION=dart_declaration)
779 789
780 if self._interface.id == 'IDBObjectStore' and info.name == 'openCursor': 790 version = [1]
Anton Muhin 2012/06/04 14:27:37 it looks like you actually using version as a scal
podivilov 2012/06/04 16:12:55 Yes, but version = 1 doesn't work since it's not v
781 # FIXME: implement v8-like overload resolver and remove this hack.
782 info.overloads = info.overloads[1:]
783 791
784 self._native_version = 0 792 def GenerateChecksAndCall(operation, argument_count, checks):
Anton Muhin 2012/06/04 14:27:37 nit: maybe move this function to the very top of _
podivilov 2012/06/04 16:12:55 Done.
785 overloads = self.CombineOverloads(info.overloads) 793 if checks:
786 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) 794 call = body.Emit(
787 if fallthrough: 795 ' if ($CHECKS) {\n'
796 '$!CALL'
797 ' }\n',
798 CHECKS=' && '.join(checks))
799 else:
800 call = body
801 if operation.type.id != 'void':
802 call = call.Emit(' return $!CALL;\n')
Anton Muhin 2012/06/04 14:27:37 cosmetic: that will give unnecessary indent if che
803 else:
804 call = call.Emit(' $!CALL;\n'
805 ' return;\n')
806
807 overload_name = '%s_%s' % (operation.id, version[0])
808 version[0] += 1
809 argument_list = ', '.join(argument_names[:argument_count])
810 call.Emit('_%s(%s)' % (overload_name, argument_list))
811
812 dart_declaration = '%s%s _%s(%s)' % (
813 'static ' if operation.is_static else '',
814 self._DartType(operation.type.id), overload_name, argument_list)
815 cpp_callback_name = self._GenerateNativeBinding(
816 overload_name, (0 if operation.is_static else 1) + argument_count,
817 dart_declaration, 'Callback', False)
818 self._GenerateOperationNativeCallback(operation, operation.arguments[:argu ment_count], cpp_callback_name)
819
820 # TODO: Optimize the dispatch to avoid repeated checks.
821 if len(operations) > 1:
822 for operation in operations:
823 checks = ['%s === null' % name for name in argument_names]
Anton Muhin 2012/06/04 14:27:37 checks for all arguments look wrong
podivilov 2012/06/04 16:12:55 Why? We don't have arguments.length in Dart.
824 for (position, argument) in enumerate(operation.arguments):
Anton Muhin 2012/06/04 14:27:37 shouldn't you go here backwards too?
podivilov 2012/06/04 16:12:55 No, here the scheme is different. There are always
825 if IsOptional(argument) and not 'Callback' in argument.ext_attrs:
826 GenerateChecksAndCall(operation, position, checks)
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 in range(len(operation.arguments) - 1, -1, -1):
Anton Muhin 2012/06/04 14:27:37 I'd rather code that for position, argument in li
podivilov 2012/06/04 16:12:55 Done.
792 # undoes the expansion of optional arguments into multiple overloads unless 835 argument = operation.arguments[position]
793 # IDL merging has made the overloads necessary. Starting with overload with 836 if IsOptional(argument) and not 'Callback' in argument.ext_attrs:
Anton Muhin 2012/06/04 14:27:37 it looks like not 'Callback' should belong to IsOp
podivilov 2012/06/04 16:12:55 Not really. IsOptional returns true iff parameter
794 # no optional arguments and grow it by adding optional arguments, then the 837 check = '%s === null' % argument_names[position]
795 # longest overload can serve for all the shorter ones. 838 GenerateChecksAndCall(operation, position, [check])
796 out = [] 839 GenerateChecksAndCall(operation, len(operation.arguments), None)
Anton Muhin 2012/06/04 14:27:37 [] instead of None?
podivilov 2012/06/04 16:12:55 Done.
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 840
953 def AddOperation(self, info): 841 def AddOperation(self, info):
954 self._AddOperation(info) 842 self._AddOperation(info)
955 843
956 def AddStaticOperation(self, info): 844 def AddStaticOperation(self, info):
957 self._AddOperation(info) 845 self._AddOperation(info)
958 846
959 def AddSecondaryOperation(self, interface, info): 847 def AddSecondaryOperation(self, interface, info):
960 self.AddOperation(info) 848 self.AddOperation(info)
961 849
962 def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): 850 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) 851 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i d)
1006 852
1007 parameter_definitions_emitter = emitter.Emitter() 853 parameter_definitions_emitter = emitter.Emitter()
1008 arguments = [] 854 cpp_arguments = []
1009 raises_exceptions = self._GenerateCallWithHandling( 855 raises_exceptions = self._GenerateCallWithHandling(
1010 operation, parameter_definitions_emitter, arguments) 856 operation, parameter_definitions_emitter, cpp_arguments)
1011 raises_exceptions = raises_exceptions or len(operation.arguments) > 0 or ope ration.raises 857 raises_exceptions = raises_exceptions or len(arguments) > 0 or operation.rai ses
1012 858
1013 # Process Dart arguments. 859 # Process Dart cpp_arguments.
1014 start_index = 1 860 start_index = 1
1015 if operation.is_static: 861 if operation.is_static:
1016 start_index = 0 862 start_index = 0
1017 for (i, argument) in enumerate(operation.arguments): 863 for (i, argument) in enumerate(arguments):
1018 if (i == len(operation.arguments) - 1 and 864 if (i == len(arguments) - 1 and
1019 self._interface.id == 'Console' and 865 self._interface.id == 'Console' and
1020 argument.id == 'arg'): 866 argument.id == 'arg'):
1021 # FIXME: we are skipping last argument here because it was added in 867 # FIXME: we are skipping last argument here because it was added in
1022 # supplemental dart.idl. Cleanup dart.idl and remove this check. 868 # supplemental dart.idl. Cleanup dart.idl and remove this check.
1023 break 869 break
1024 argument_expression = self._GenerateToNative( 870 argument_expression = self._GenerateToNative(
1025 parameter_definitions_emitter, argument, start_index + i) 871 parameter_definitions_emitter, argument, start_index + i)
1026 arguments.append(argument_expression) 872 cpp_arguments.append(argument_expression)
1027 873
1028 if operation.id in ['addEventListener', 'removeEventListener']: 874 if operation.id in ['addEventListener', 'removeEventListener']:
1029 # addEventListener's and removeEventListener's last argument is marked 875 # addEventListener's and removeEventListener's last argument is marked
1030 # as optional in idl, but is not optional in webcore implementation. 876 # as optional in idl, but is not optional in webcore implementation.
1031 if len(operation.arguments) == 2: 877 if len(arguments) == 2:
1032 arguments.append('false') 878 cpp_arguments.append('false')
1033 879
1034 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty': 880 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty':
1035 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart 881 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart
1036 # idl, but is not optional in webcore implementation. 882 # idl, but is not optional in webcore implementation.
1037 if len(operation.arguments) == 2: 883 if len(arguments) == 2:
1038 arguments.append('String()') 884 cpp_arguments.append('String()')
1039 885
1040 if 'NeedsUserGestureCheck' in operation.ext_attrs: 886 if 'NeedsUserGestureCheck' in operation.ext_attrs:
1041 arguments.append('DartUtilities::processingUserGesture') 887 cpp_arguments.append('DartUtilities::processingUserGesture')
1042 888
1043 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation) 889 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation)
1044 invocation = self._GenerateWebCoreInvocation(function_expression, arguments, 890 invocation = self._GenerateWebCoreInvocation(function_expression, cpp_argume nts,
1045 operation.type.id, operation.ext_attrs, operation.raises) 891 operation.type.id, operation.ext_attrs, operation.raises)
1046 self._GenerateNativeCallback(cpp_callback_name, 892 self._GenerateNativeCallback(cpp_callback_name,
1047 parameter_definitions=parameter_definitions_emitter.Fragments(), 893 parameter_definitions=parameter_definitions_emitter.Fragments(),
1048 needs_receiver=not operation.is_static, invocation=invocation, 894 needs_receiver=not operation.is_static, invocation=invocation,
1049 raises_exceptions=raises_exceptions) 895 raises_exceptions=raises_exceptions)
1050 896
1051 def _GenerateNativeCallback(self, callback_name, parameter_definitions, 897 def _GenerateNativeCallback(self, callback_name, parameter_definitions,
1052 needs_receiver, invocation, raises_exceptions): 898 needs_receiver, invocation, raises_exceptions):
1053 899
1054 if needs_receiver: 900 if needs_receiver:
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 for parent in interface.parents: 1042 for parent in interface.parents:
1197 parent_name = parent.type.id 1043 parent_name = parent.type.id
1198 if not database.HasInterface(parent.type.id): 1044 if not database.HasInterface(parent.type.id):
1199 continue 1045 continue
1200 parent_interface = database.GetInterface(parent.type.id) 1046 parent_interface = database.GetInterface(parent.type.id)
1201 if callback(parent_interface): 1047 if callback(parent_interface):
1202 return parent_interface 1048 return parent_interface
1203 parent_interface = _FindParent(parent_interface, database, callback) 1049 parent_interface = _FindParent(parent_interface, database, callback)
1204 if parent_interface: 1050 if parent_interface:
1205 return parent_interface 1051 return parent_interface
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698