Index: lib/dom/scripts/systemnative.py |
diff --git a/lib/dom/scripts/systemnative.py b/lib/dom/scripts/systemnative.py |
index 19b8e3161ba1fa2eb915d84ac094257b7c533497..8a316e8e8930643b09f3cd77af4a1de03f2eb1cb 100644 |
--- a/lib/dom/scripts/systemnative.py |
+++ b/lib/dom/scripts/systemnative.py |
@@ -743,7 +743,9 @@ class NativeImplementationGenerator(object): |
info: An OperationInfo object. |
""" |
- if 'CheckSecurityForNode' in info.overloads[0].ext_attrs: |
+ operation = info.operations[0] |
+ |
+ if 'CheckSecurityForNode' in operation.ext_attrs: |
# FIXME: exclude from interface as well. |
return |
@@ -761,14 +763,23 @@ class NativeImplementationGenerator(object): |
dart_declaration = '%s%s %s(%s)' % ( |
'static ' if info.IsStatic() else '', |
self._DartType(info.type_name), |
- html_name or info.name, |
+ html_name, |
info.ParametersImplementationDeclaration(self._DartType)) |
- if 'Custom' in info.overloads[0].ext_attrs: |
+ is_custom = 'Custom' in operation.ext_attrs |
+ has_optional_arguments = any(IsOptional(argument) for argument in operation.arguments) |
+ needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_optional_arguments) |
+ if not needs_dispatcher: |
+ # Bind directly to native implementation |
argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos) |
- self._GenerateNativeBinding(info.name , argument_count, |
- dart_declaration, 'Callback', True) |
- return |
+ cpp_callback_name = self._GenerateNativeBinding( |
+ info.name, argument_count, dart_declaration, 'Callback', is_custom) |
+ if not is_custom: |
+ self._GenerateOperationNativeCallback(operation, operation.arguments, cpp_callback_name) |
+ else: |
+ self._GenerateDispatcher(info.operations, dart_declaration, [info.name for info in info.param_infos]) |
+ |
+ def _GenerateDispatcher(self, operations, dart_declaration, argument_names): |
body = self._members_emitter.Emit( |
'\n' |
@@ -777,178 +788,60 @@ class NativeImplementationGenerator(object): |
' }\n', |
DECLARATION=dart_declaration) |
- if self._interface.id == 'IDBObjectStore' and info.name == 'openCursor': |
- # FIXME: implement v8-like overload resolver and remove this hack. |
- info.overloads = info.overloads[1:] |
- |
- self._native_version = 0 |
- overloads = self.CombineOverloads(info.overloads) |
- fallthrough = self.GenerateDispatch(body, info, ' ', overloads) |
- if fallthrough: |
- body.Emit(' throw "Incorrect number or type of arguments";\n'); |
- |
- def CombineOverloads(self, overloads): |
- # Combine overloads that can be implemented by the same native method. This |
- # undoes the expansion of optional arguments into multiple overloads unless |
- # IDL merging has made the overloads necessary. Starting with overload with |
- # no optional arguments and grow it by adding optional arguments, then the |
- # longest overload can serve for all the shorter ones. |
- out = [] |
- seed_index = 0 |
- while seed_index < len(overloads): |
- seed = overloads[seed_index] |
- if len(seed.arguments) > 0 and IsOptional(seed.arguments[-1]): |
- # Must start with no optional arguments. |
- out.append(seed) |
- seed_index += 1 |
- continue |
- |
- prev = seed |
- probe_index = seed_index + 1 |
- while probe_index < len(overloads): |
- probe = overloads[probe_index] |
- # Check that 'probe' extends 'prev' by one optional argument. |
- if len(probe.arguments) != len(prev.arguments) + 1: |
- break |
- if probe.arguments[:-1] != prev.arguments: |
- break |
- if not IsOptional(probe.arguments[-1]): |
- break |
- # See Issue 3177. This test against known implemented types is to |
- # prevent combining a possibly unimplemented type. Combining with an |
- # unimplemented type will cause all set of combined overloads to become |
- # 'unimplemented', even if no argument is passed to the the |
- # unimplemented parameter. |
- if DartType(probe.arguments[-1].type.id) not in [ |
- 'String', 'int', 'num', 'double', 'bool', |
- 'IDBKeyRange']: |
- break |
- probe_index += 1 |
- prev = probe |
- out.append(prev) |
- seed_index = probe_index |
- |
- return out |
- |
- def PrintOverloadsComment(self, emitter, info, indent, note, overloads): |
- emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note) |
- for operation in overloads: |
- params = ', '.join([ |
- ('[Optional] ' if IsOptional(arg) else '') + DartType(arg.type.id) + ' ' |
- + arg.id for arg in operation.arguments]) |
- emitter.Emit('$(INDENT)// $NAME($PARAMS)\n', |
- INDENT=indent, |
- NAME=info.name, |
- PARAMS=params) |
- emitter.Emit('$(INDENT)//\n', INDENT=indent) |
- |
- def GenerateDispatch(self, emitter, info, indent, overloads): |
- """Generates a dispatch to one of the overloads. |
- |
- Arguments: |
- emitter: an Emitter for the body of a block of code. |
- info: the compound information about the operation and its overloads. |
- indent: an indentation string for generated code. |
- position: the index of the parameter to dispatch on. |
- overloads: a list of the IDLOperations to dispatch. |
- |
- Returns True if the dispatch can fall through on failure, False if the code |
- always dispatches. |
- """ |
- |
- def NullCheck(name): |
- return '%s === null' % name |
- |
- def TypeCheck(name, type): |
- return '%s is %s' % (name, type) |
- |
- def IsNullable(type): |
- #return type != 'int' and type != 'num' |
- return True |
- |
- def PickRequiredCppSingleOperation(): |
- # Returns a special case single operation, or None. Check if we dispatch |
- # on RequiredCppParameter arguments. In this case all trailing arguments |
- # must be RequiredCppParameter and there is no need in dispatch. |
- def IsRequiredCppParameter(arg): |
- return 'RequiredCppParameter' in arg.ext_attrs |
- def HasRequiredCppParameters(op): |
- matches = filter(IsRequiredCppParameter, op.arguments) |
- if matches: |
- # Validate all the RequiredCppParameter ones are at the end. |
- rematches = filter(IsRequiredCppParameter, |
- op.arguments[len(op.arguments) - len(matches):]) |
- if len(matches) != len(rematches): |
- raise Exception('Invalid RequiredCppParameter - all subsequent ' |
- 'parameters must also be RequiredCppParameter.') |
- return True |
- return False |
- if any(HasRequiredCppParameters(op) for op in overloads): |
- longest = max(overloads, key=lambda op: len(op.arguments)) |
- # Validate all other overloads are prefixes. |
- for op in overloads: |
- for (index, arg) in enumerate(op.arguments): |
- type1 = arg.type.id |
- type2 = longest.arguments[index].type.id |
- if type1 != type2: |
- raise Exception( |
- 'Overloads for method %s with RequiredCppParameter have ' |
- 'inconsistent types %s and %s for parameter #%s' % |
- (info.name, type1, type2, index)) |
- return longest |
- return None |
- |
- single_operation = PickRequiredCppSingleOperation() |
- if single_operation: |
- self.GenerateSingleOperation(emitter, info, indent, single_operation) |
- return False |
- |
- # Print just the interesting sets of overloads. |
- if len(overloads) > 1 or len(info.overloads) > 1: |
- self.PrintOverloadsComment(emitter, info, indent, '', info.overloads) |
- if overloads != info.overloads: |
- self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:', |
- overloads) |
- |
- # Match each operation in turn. |
- # TODO: Optimize the dispatch to avoid repeated tests. |
- fallthrough = True |
- for operation in overloads: |
- tests = [] |
- for (position, param) in enumerate(info.param_infos): |
- if position < len(operation.arguments): |
- arg = operation.arguments[position] |
- dart_type = self._DartType(arg.type.id) |
- if dart_type == param.dart_type: |
- # The overload type matches the method parameter type exactly. We |
- # will have already tested this type in checked mode, and the target |
- # will expect (i.e. check) this type. This case happens when all |
- # the overloads have the same type in this position, including the |
- # trivial case of one overload. |
- test = None |
- else: |
- test = TypeCheck(param.name, dart_type) |
- if IsNullable(dart_type) or IsOptional(arg): |
- test = '(%s || %s)' % (NullCheck(param.name), test) |
+ version = [1] |
+ def GenerateCall(operation, argument_count, checks): |
+ if checks: |
+ if operation.type.id != 'void': |
+ template = ' if ($CHECKS) {\n return $CALL;\n }\n' |
else: |
- test = NullCheck(param.name) |
- if test: |
- tests.append(test) |
- if tests: |
- cond = ' && '.join(tests) |
- if len(cond) + len(indent) + 7 > 80: |
- cond = (' &&\n' + indent + ' ').join(tests) |
- call = emitter.Emit( |
- '$(INDENT)if ($COND) {\n' |
- '$!CALL' |
- '$(INDENT)}\n', |
- COND=cond, |
- INDENT=indent) |
- self.GenerateSingleOperation(call, info, indent + ' ', operation) |
+ template = ' if ($CHECKS) {\n $CALL;\n return;\n }\n' |
else: |
- self.GenerateSingleOperation(emitter, info, indent, operation) |
- fallthrough = False |
- return fallthrough |
+ if operation.type.id != 'void': |
+ template = ' return $CALL;\n' |
+ else: |
+ template = ' $CALL;\n' |
+ |
+ overload_name = '%s_%s' % (operation.id, version[0]) |
+ version[0] += 1 |
+ argument_list = ', '.join(argument_names[:argument_count]) |
+ call = '_%s(%s)' % (overload_name, argument_list) |
+ body.Emit(template, CHECKS=' && '.join(checks), CALL=call) |
+ |
+ dart_declaration = '%s%s _%s(%s)' % ( |
+ 'static ' if operation.is_static else '', |
+ self._DartType(operation.type.id), overload_name, argument_list) |
+ cpp_callback_name = self._GenerateNativeBinding( |
+ overload_name, (0 if operation.is_static else 1) + argument_count, |
+ dart_declaration, 'Callback', False) |
+ self._GenerateOperationNativeCallback(operation, operation.arguments[:argument_count], cpp_callback_name) |
+ |
+ def GenerateChecksAndCall(operation, argument_count): |
+ checks = ['%s === null' % name for name in argument_names] |
+ for i in range(0, argument_count): |
+ argument = operation.arguments[i] |
+ checks[i] = '%s is %s' % (argument_names[i], self._DartType(argument.type.id)) |
+ if IsOptional(argument) and 'Callback' in argument.ext_attrs: |
+ checks[i] = '(%s or %s === null)' % (checks[position], argument_names[i]) |
+ GenerateCall(operation, argument_count, checks) |
+ |
+ def IsOptionalInWebCore(argument): |
+ return IsOptional(argument) and not 'Callback' in argument.ext_attrs |
+ |
+ # TODO: Optimize the dispatch to avoid repeated checks. |
+ if len(operations) > 1: |
+ for operation in operations: |
+ for position, argument in enumerate(operation.arguments): |
+ if IsOptionalInWebCore(argument): |
+ GenerateChecksAndCall(operation, position) |
+ GenerateChecksAndCall(operation, len(operation.arguments)) |
+ body.Emit(' throw "Incorrect number or type of arguments";\n'); |
+ else: |
+ operation = operations[0] |
+ for position, argument in list(enumerate(operation.arguments))[::-1]: |
+ if IsOptionalInWebCore(argument): |
+ check = '%s === null' % argument_names[position] |
+ GenerateCall(operation, position, [check]) |
+ GenerateCall(operation, len(operation.arguments), []) |
def AddOperation(self, info): |
self._AddOperation(info) |
@@ -959,63 +852,21 @@ class NativeImplementationGenerator(object): |
def AddSecondaryOperation(self, interface, info): |
self.AddOperation(info) |
- def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): |
- """Generates a call to a single operation. |
- |
- Arguments: |
- dispatch_emitter: an dispatch_emitter for the body of a block of code. |
- info: the compound information about the operation and its overloads. |
- indent: an indentation string for generated code. |
- operation: the IDLOperation to call. |
- """ |
- |
- self._native_version += 1 |
- native_name = info.name |
- if self._native_version > 1: |
- native_name = '%s_%s' % (native_name, self._native_version) |
- argument_list = ', '.join([info.param_infos[i].name |
- for (i, arg) in enumerate(operation.arguments)]) |
- |
- # Generate dispatcher. |
- if info.type_name != 'void': |
- dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n', |
- INDENT=indent, |
- NATIVENAME=native_name, |
- ARGS=argument_list) |
- else: |
- dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n' |
- '$(INDENT)return;\n', |
- INDENT=indent, |
- NATIVENAME=native_name, |
- ARGS=argument_list) |
- # Generate binding. |
- modifier = '' |
- if operation.is_static: |
- modifier = 'static ' |
- dart_declaration = '%s%s _%s(%s)' % (modifier, self._DartType(info.type_name), native_name, |
- argument_list) |
- is_custom = 'Custom' in operation.ext_attrs |
- cpp_callback_name = self._GenerateNativeBinding( |
- native_name, (0 if operation.is_static else 1) + len(operation.arguments), dart_declaration, 'Callback', |
- is_custom) |
- if is_custom: |
- return |
- |
- # Generate callback. |
+ def _GenerateOperationNativeCallback(self, operation, arguments, cpp_callback_name): |
webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.id) |
parameter_definitions_emitter = emitter.Emitter() |
- arguments = [] |
+ cpp_arguments = [] |
raises_exceptions = self._GenerateCallWithHandling( |
- operation, parameter_definitions_emitter, arguments) |
- raises_exceptions = raises_exceptions or len(operation.arguments) > 0 or operation.raises |
+ operation, parameter_definitions_emitter, cpp_arguments) |
+ raises_exceptions = raises_exceptions or len(arguments) > 0 or operation.raises |
- # Process Dart arguments. |
+ # Process Dart cpp_arguments. |
start_index = 1 |
if operation.is_static: |
start_index = 0 |
- for (i, argument) in enumerate(operation.arguments): |
- if (i == len(operation.arguments) - 1 and |
+ for (i, argument) in enumerate(arguments): |
+ if (i == len(arguments) - 1 and |
self._interface.id == 'Console' and |
argument.id == 'arg'): |
# FIXME: we are skipping last argument here because it was added in |
@@ -1023,25 +874,25 @@ class NativeImplementationGenerator(object): |
break |
argument_expression = self._GenerateToNative( |
parameter_definitions_emitter, argument, start_index + i) |
- arguments.append(argument_expression) |
+ cpp_arguments.append(argument_expression) |
if operation.id in ['addEventListener', 'removeEventListener']: |
# addEventListener's and removeEventListener's last argument is marked |
# as optional in idl, but is not optional in webcore implementation. |
- if len(operation.arguments) == 2: |
- arguments.append('false') |
+ if len(arguments) == 2: |
+ cpp_arguments.append('false') |
if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setProperty': |
# CSSStyleDeclaration.setProperty priority parameter is optional in Dart |
# idl, but is not optional in webcore implementation. |
- if len(operation.arguments) == 2: |
- arguments.append('String()') |
+ if len(arguments) == 2: |
+ cpp_arguments.append('String()') |
if 'NeedsUserGestureCheck' in operation.ext_attrs: |
- arguments.append('DartUtilities::processingUserGesture') |
+ cpp_arguments.append('DartUtilities::processingUserGesture') |
function_expression = self._GenerateWebCoreFunctionExpression(webcore_function_name, operation) |
- invocation = self._GenerateWebCoreInvocation(function_expression, arguments, |
+ invocation = self._GenerateWebCoreInvocation(function_expression, cpp_arguments, |
operation.type.id, operation.ext_attrs, operation.raises) |
self._GenerateNativeCallback(cpp_callback_name, |
parameter_definitions=parameter_definitions_emitter.Fragments(), |