| 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(),
|
|
|