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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/dom/scripts/generator.py ('k') | lib/html/dartium/html_dartium.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(),
« no previous file with comments | « lib/dom/scripts/generator.py ('k') | lib/html/dartium/html_dartium.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698