Home | History | Annotate | Download | only in scripts
      1 # Copyright (C) 2013 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 """Generate template values for methods.
     30 
     31 Extends IdlArgument with property |default_cpp_value|.
     32 Extends IdlTypeBase and IdlUnionType with property |union_arguments|.
     33 
     34 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
     35 """
     36 
     37 from idl_definitions import IdlArgument, IdlOperation
     38 from idl_types import IdlTypeBase, IdlUnionType, inherits_interface
     39 from v8_globals import includes
     40 import v8_types
     41 import v8_utilities
     42 from v8_utilities import has_extended_attribute_value
     43 
     44 
     45 # Methods with any of these require custom method registration code in the
     46 # interface's configure*Template() function.
     47 CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES = frozenset([
     48     'DoNotCheckSecurity',
     49     'DoNotCheckSignature',
     50     'NotEnumerable',
     51     'Unforgeable',
     52 ])
     53 
     54 
     55 def use_local_result(method):
     56     extended_attributes = method.extended_attributes
     57     idl_type = method.idl_type
     58     return (has_extended_attribute_value(method, 'CallWith', 'ScriptState') or
     59             'ImplementedInPrivateScript' in extended_attributes or
     60             'RaisesException' in extended_attributes or
     61             idl_type.is_union_type or
     62             idl_type.is_explicit_nullable)
     63 
     64 
     65 def method_context(interface, method):
     66     arguments = method.arguments
     67     extended_attributes = method.extended_attributes
     68     idl_type = method.idl_type
     69     is_static = method.is_static
     70     name = method.name
     71 
     72     idl_type.add_includes_for_type()
     73     this_cpp_value = cpp_value(interface, method, len(arguments))
     74 
     75     def function_template():
     76         if is_static:
     77             return 'functionTemplate'
     78         if 'Unforgeable' in extended_attributes:
     79             return 'instanceTemplate'
     80         return 'prototypeTemplate'
     81 
     82     is_implemented_in_private_script = 'ImplementedInPrivateScript' in extended_attributes
     83     if is_implemented_in_private_script:
     84         includes.add('bindings/core/v8/PrivateScriptRunner.h')
     85         includes.add('core/frame/LocalFrame.h')
     86         includes.add('platform/ScriptForbiddenScope.h')
     87 
     88     # [OnlyExposedToPrivateScript]
     89     is_only_exposed_to_private_script = 'OnlyExposedToPrivateScript' in extended_attributes
     90 
     91     is_call_with_script_arguments = has_extended_attribute_value(method, 'CallWith', 'ScriptArguments')
     92     if is_call_with_script_arguments:
     93         includes.update(['bindings/core/v8/ScriptCallStackFactory.h',
     94                          'core/inspector/ScriptArguments.h'])
     95     is_call_with_script_state = has_extended_attribute_value(method, 'CallWith', 'ScriptState')
     96     if is_call_with_script_state:
     97         includes.add('bindings/core/v8/ScriptState.h')
     98     is_check_security_for_node = 'CheckSecurity' in extended_attributes
     99     if is_check_security_for_node:
    100         includes.add('bindings/core/v8/BindingSecurity.h')
    101     is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes
    102     if is_custom_element_callbacks:
    103         includes.add('core/dom/custom/CustomElementProcessingStack.h')
    104 
    105     is_do_not_check_security = 'DoNotCheckSecurity' in extended_attributes
    106 
    107     is_check_security_for_frame = (
    108         has_extended_attribute_value(interface, 'CheckSecurity', 'Frame') and
    109         not is_do_not_check_security)
    110 
    111     is_check_security_for_window = (
    112         has_extended_attribute_value(interface, 'CheckSecurity', 'Window') and
    113         not is_do_not_check_security)
    114 
    115     is_raises_exception = 'RaisesException' in extended_attributes
    116 
    117     return {
    118         'activity_logging_world_list': v8_utilities.activity_logging_world_list(method),  # [ActivityLogging]
    119         'arguments': [argument_context(interface, method, argument, index)
    120                       for index, argument in enumerate(arguments)],
    121         'argument_declarations_for_private_script':
    122             argument_declarations_for_private_script(interface, method),
    123         'conditional_string': v8_utilities.conditional_string(method),
    124         'cpp_type': (v8_types.cpp_template_type('Nullable', idl_type.cpp_type)
    125                      if idl_type.is_explicit_nullable else idl_type.cpp_type),
    126         'cpp_value': this_cpp_value,
    127         'cpp_type_initializer': idl_type.cpp_type_initializer,
    128         'custom_registration_extended_attributes':
    129             CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES.intersection(
    130                 extended_attributes.iterkeys()),
    131         'deprecate_as': v8_utilities.deprecate_as(method),  # [DeprecateAs]
    132         'exposed_test': v8_utilities.exposed(method, interface),  # [Exposed]
    133         'function_template': function_template(),
    134         'has_custom_registration': is_static or
    135             v8_utilities.has_extended_attribute(
    136                 method, CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES),
    137         'has_exception_state':
    138             is_raises_exception or
    139             is_check_security_for_frame or
    140             is_check_security_for_window or
    141             any(argument for argument in arguments
    142                 if (argument.idl_type.name == 'SerializedScriptValue' or
    143                     argument_conversion_needs_exception_state(method, argument))),
    144         'idl_type': idl_type.base_type,
    145         'is_call_with_execution_context': has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'),
    146         'is_call_with_script_arguments': is_call_with_script_arguments,
    147         'is_call_with_script_state': is_call_with_script_state,
    148         'is_check_security_for_frame': is_check_security_for_frame,
    149         'is_check_security_for_node': is_check_security_for_node,
    150         'is_check_security_for_window': is_check_security_for_window,
    151         'is_custom': 'Custom' in extended_attributes,
    152         'is_custom_element_callbacks': is_custom_element_callbacks,
    153         'is_do_not_check_security': is_do_not_check_security,
    154         'is_do_not_check_signature': 'DoNotCheckSignature' in extended_attributes,
    155         'is_explicit_nullable': idl_type.is_explicit_nullable,
    156         'is_implemented_in_private_script': is_implemented_in_private_script,
    157         'is_partial_interface_member':
    158             'PartialInterfaceImplementedAs' in extended_attributes,
    159         'is_per_world_bindings': 'PerWorldBindings' in extended_attributes,
    160         'is_raises_exception': is_raises_exception,
    161         'is_read_only': 'Unforgeable' in extended_attributes,
    162         'is_static': is_static,
    163         'is_variadic': arguments and arguments[-1].is_variadic,
    164         'measure_as': v8_utilities.measure_as(method),  # [MeasureAs]
    165         'name': name,
    166         'number_of_arguments': len(arguments),
    167         'number_of_required_arguments': len([
    168             argument for argument in arguments
    169             if not (argument.is_optional or argument.is_variadic)]),
    170         'number_of_required_or_variadic_arguments': len([
    171             argument for argument in arguments
    172             if not argument.is_optional]),
    173         'only_exposed_to_private_script': is_only_exposed_to_private_script,
    174         'per_context_enabled_function': v8_utilities.per_context_enabled_function_name(method),  # [PerContextEnabled]
    175         'private_script_v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value(
    176             extended_attributes, 'v8Value', 'cppValue', isolate='scriptState->isolate()', used_in_private_script=True),
    177         'property_attributes': property_attributes(method),
    178         'runtime_enabled_function': v8_utilities.runtime_enabled_function_name(method),  # [RuntimeEnabled]
    179         'should_be_exposed_to_script': not (is_implemented_in_private_script and is_only_exposed_to_private_script),
    180         'signature': 'v8::Local<v8::Signature>()' if is_static or 'DoNotCheckSignature' in extended_attributes else 'defaultSignature',
    181         'union_arguments': idl_type.union_arguments,
    182         'use_local_result': use_local_result(method),
    183         'v8_set_return_value': v8_set_return_value(interface.name, method, this_cpp_value),
    184         'v8_set_return_value_for_main_world': v8_set_return_value(interface.name, method, this_cpp_value, for_main_world=True),
    185         'world_suffixes': ['', 'ForMainWorld'] if 'PerWorldBindings' in extended_attributes else [''],  # [PerWorldBindings],
    186     }
    187 
    188 
    189 def argument_context(interface, method, argument, index):
    190     extended_attributes = argument.extended_attributes
    191     idl_type = argument.idl_type
    192     this_cpp_value = cpp_value(interface, method, index)
    193     is_variadic_wrapper_type = argument.is_variadic and idl_type.is_wrapper_type
    194 
    195     if ('ImplementedInPrivateScript' in extended_attributes and
    196         not idl_type.is_wrapper_type and
    197         not idl_type.is_basic_type):
    198         raise Exception('Private scripts supports only primitive types and DOM wrappers.')
    199 
    200     default_cpp_value = argument.default_cpp_value
    201     return {
    202         'cpp_type': idl_type.cpp_type_args(extended_attributes=extended_attributes,
    203                                            raw_type=True,
    204                                            used_as_variadic_argument=argument.is_variadic),
    205         'cpp_value': this_cpp_value,
    206         # FIXME: check that the default value's type is compatible with the argument's
    207         'default_value': default_cpp_value,
    208         'enum_validation_expression': idl_type.enum_validation_expression,
    209         'handle': '%sHandle' % argument.name,
    210         # FIXME: remove once [Default] removed and just use argument.default_value
    211         'has_default': 'Default' in extended_attributes or default_cpp_value,
    212         'has_type_checking_interface':
    213             (has_extended_attribute_value(interface, 'TypeChecking', 'Interface') or
    214              has_extended_attribute_value(method, 'TypeChecking', 'Interface')) and
    215             idl_type.is_wrapper_type,
    216         'has_type_checking_unrestricted':
    217             (has_extended_attribute_value(interface, 'TypeChecking', 'Unrestricted') or
    218              has_extended_attribute_value(method, 'TypeChecking', 'Unrestricted')) and
    219             idl_type.name in ('Float', 'Double'),
    220         # Dictionary is special-cased, but arrays and sequences shouldn't be
    221         'idl_type': idl_type.base_type,
    222         'idl_type_object': idl_type,
    223         'index': index,
    224         'is_callback_interface': idl_type.is_callback_interface,
    225         # FIXME: Remove generic 'Dictionary' special-casing
    226         'is_dictionary': idl_type.is_dictionary or idl_type.base_type == 'Dictionary',
    227         'is_nullable': idl_type.is_nullable,
    228         'is_optional': argument.is_optional,
    229         'is_variadic_wrapper_type': is_variadic_wrapper_type,
    230         'is_wrapper_type': idl_type.is_wrapper_type,
    231         'name': argument.name,
    232         'private_script_cpp_value_to_v8_value': idl_type.cpp_value_to_v8_value(
    233             argument.name, isolate='scriptState->isolate()',
    234             creation_context='scriptState->context()->Global()'),
    235         'v8_set_return_value': v8_set_return_value(interface.name, method, this_cpp_value),
    236         'v8_set_return_value_for_main_world': v8_set_return_value(interface.name, method, this_cpp_value, for_main_world=True),
    237         'v8_value_to_local_cpp_value': v8_value_to_local_cpp_value(argument, index, return_promise=method.returns_promise),
    238         'vector_type': v8_types.cpp_ptr_type('Vector', 'HeapVector', idl_type.gc_type),
    239     }
    240 
    241 
    242 def argument_declarations_for_private_script(interface, method):
    243     argument_declarations = ['LocalFrame* frame']
    244     argument_declarations.append('%s* holderImpl' % interface.name)
    245     argument_declarations.extend(['%s %s' % (argument.idl_type.cpp_type_args(
    246         used_as_rvalue_type=True), argument.name) for argument in method.arguments])
    247     if method.idl_type.name != 'void':
    248         argument_declarations.append('%s* %s' % (method.idl_type.cpp_type, 'result'))
    249     return argument_declarations
    250 
    251 
    252 ################################################################################
    253 # Value handling
    254 ################################################################################
    255 
    256 def cpp_value(interface, method, number_of_arguments):
    257     def cpp_argument(argument):
    258         idl_type = argument.idl_type
    259         if idl_type.name == 'EventListener':
    260             return argument.name
    261         if idl_type.is_dictionary:
    262             return '*%s' % argument.name
    263         if (idl_type.name in ['NodeFilter', 'NodeFilterOrNull',
    264                               'XPathNSResolver', 'XPathNSResolverOrNull']):
    265             # FIXME: remove this special case
    266             return '%s.release()' % argument.name
    267         return argument.name
    268 
    269     # Truncate omitted optional arguments
    270     arguments = method.arguments[:number_of_arguments]
    271     cpp_arguments = []
    272     if 'ImplementedInPrivateScript' in method.extended_attributes:
    273         cpp_arguments.append('toFrameIfNotDetached(info.GetIsolate()->GetCurrentContext())')
    274         cpp_arguments.append('impl')
    275 
    276     if method.is_constructor:
    277         call_with_values = interface.extended_attributes.get('ConstructorCallWith')
    278     else:
    279         call_with_values = method.extended_attributes.get('CallWith')
    280     cpp_arguments.extend(v8_utilities.call_with_arguments(call_with_values))
    281 
    282     # Members of IDL partial interface definitions are implemented in C++ as
    283     # static member functions, which for instance members (non-static members)
    284     # take *impl as their first argument
    285     if ('PartialInterfaceImplementedAs' in method.extended_attributes and
    286         not 'ImplementedInPrivateScript' in method.extended_attributes and
    287         not method.is_static):
    288         cpp_arguments.append('*impl')
    289     cpp_arguments.extend(cpp_argument(argument) for argument in arguments)
    290 
    291     this_union_arguments = method.idl_type and method.idl_type.union_arguments
    292     if this_union_arguments:
    293         cpp_arguments.extend([member_argument['cpp_value']
    294                               for member_argument in this_union_arguments])
    295 
    296     if 'ImplementedInPrivateScript' in method.extended_attributes:
    297         if method.idl_type.name != 'void':
    298             cpp_arguments.append('&result')
    299     elif ('RaisesException' in method.extended_attributes or
    300         (method.is_constructor and
    301          has_extended_attribute_value(interface, 'RaisesException', 'Constructor'))):
    302         cpp_arguments.append('exceptionState')
    303 
    304     if method.name == 'Constructor':
    305         base_name = 'create'
    306     elif method.name == 'NamedConstructor':
    307         base_name = 'createForJSConstructor'
    308     elif 'ImplementedInPrivateScript' in method.extended_attributes:
    309         base_name = '%sMethod' % method.name
    310     else:
    311         base_name = v8_utilities.cpp_name(method)
    312 
    313     cpp_method_name = v8_utilities.scoped_name(interface, method, base_name)
    314     return '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
    315 
    316 
    317 def v8_set_return_value(interface_name, method, cpp_value, for_main_world=False):
    318     idl_type = method.idl_type
    319     extended_attributes = method.extended_attributes
    320     if not idl_type or idl_type.name == 'void':
    321         # Constructors and void methods don't have a return type
    322         return None
    323 
    324     if ('ImplementedInPrivateScript' in extended_attributes and
    325         not idl_type.is_wrapper_type and
    326         not idl_type.is_basic_type):
    327         raise Exception('Private scripts supports only primitive types and DOM wrappers.')
    328 
    329     release = False
    330     # [CallWith=ScriptState], [RaisesException]
    331     if use_local_result(method):
    332         if idl_type.is_explicit_nullable:
    333             # result is of type Nullable<T>
    334             cpp_value = 'result.get()'
    335         else:
    336             cpp_value = 'result'
    337         release = idl_type.release
    338 
    339     script_wrappable = 'impl' if inherits_interface(interface_name, 'Node') else ''
    340     return idl_type.v8_set_return_value(cpp_value, extended_attributes, script_wrappable=script_wrappable, release=release, for_main_world=for_main_world)
    341 
    342 
    343 def v8_value_to_local_cpp_variadic_value(argument, index, return_promise):
    344     assert argument.is_variadic
    345     idl_type = argument.idl_type
    346 
    347     suffix = ''
    348 
    349     macro = 'TONATIVE_VOID_EXCEPTIONSTATE'
    350     macro_args = [
    351         argument.name,
    352         'toImplArguments<%s>(info, %s, exceptionState)' % (idl_type.cpp_type, index),
    353         'exceptionState',
    354     ]
    355 
    356     if return_promise:
    357         suffix += '_PROMISE'
    358         macro_args.extend(['info', 'ScriptState::current(info.GetIsolate())'])
    359 
    360     suffix += '_INTERNAL'
    361 
    362     return '%s%s(%s)' % (macro, suffix, ', '.join(macro_args))
    363 
    364 
    365 def v8_value_to_local_cpp_value(argument, index, return_promise=False):
    366     extended_attributes = argument.extended_attributes
    367     idl_type = argument.idl_type
    368     name = argument.name
    369     if argument.is_variadic:
    370         return v8_value_to_local_cpp_variadic_value(argument, index, return_promise)
    371     return idl_type.v8_value_to_local_cpp_value(extended_attributes, 'info[%s]' % index,
    372                                                 name, index=index, declare_variable=False, return_promise=return_promise)
    373 
    374 
    375 ################################################################################
    376 # Auxiliary functions
    377 ################################################################################
    378 
    379 # [NotEnumerable]
    380 def property_attributes(method):
    381     extended_attributes = method.extended_attributes
    382     property_attributes_list = []
    383     if 'NotEnumerable' in extended_attributes:
    384         property_attributes_list.append('v8::DontEnum')
    385     if 'Unforgeable' in extended_attributes:
    386         property_attributes_list.append('v8::ReadOnly')
    387     if property_attributes_list:
    388         property_attributes_list.insert(0, 'v8::DontDelete')
    389     return property_attributes_list
    390 
    391 
    392 def union_member_argument_context(idl_type, index):
    393     """Returns a context of union member for argument."""
    394     this_cpp_value = 'result%d' % index
    395     this_cpp_type = idl_type.cpp_type
    396     this_cpp_type_initializer = idl_type.cpp_type_initializer
    397     cpp_return_value = this_cpp_value
    398 
    399     if not idl_type.cpp_type_has_null_value:
    400         this_cpp_type = v8_types.cpp_template_type('Nullable', this_cpp_type)
    401         this_cpp_type_initializer = ''
    402         cpp_return_value = '%s.get()' % this_cpp_value
    403 
    404     if idl_type.is_string_type:
    405         null_check_value = '!%s.isNull()' % this_cpp_value
    406     else:
    407         null_check_value = this_cpp_value
    408 
    409     return {
    410         'cpp_type': this_cpp_type,
    411         'cpp_type_initializer': this_cpp_type_initializer,
    412         'cpp_value': this_cpp_value,
    413         'null_check_value': null_check_value,
    414         'v8_set_return_value': idl_type.v8_set_return_value(
    415             cpp_value=cpp_return_value,
    416             release=idl_type.release),
    417     }
    418 
    419 
    420 def union_arguments(idl_type):
    421     return [union_member_argument_context(member_idl_type, index)
    422             for index, member_idl_type
    423             in enumerate(idl_type.member_types)]
    424 
    425 
    426 def argument_default_cpp_value(argument):
    427     if argument.idl_type.is_dictionary:
    428         # We always create impl objects for IDL dictionaries.
    429         return '%s::create()' % argument.idl_type.base_type
    430     if not argument.default_value:
    431         return None
    432     return argument.idl_type.literal_cpp_value(argument.default_value)
    433 
    434 IdlTypeBase.union_arguments = None
    435 IdlUnionType.union_arguments = property(union_arguments)
    436 IdlArgument.default_cpp_value = property(argument_default_cpp_value)
    437 
    438 
    439 def method_returns_promise(method):
    440     return method.idl_type and method.idl_type.name == 'Promise'
    441 
    442 IdlOperation.returns_promise = property(method_returns_promise)
    443 
    444 
    445 def argument_conversion_needs_exception_state(method, argument):
    446     idl_type = argument.idl_type
    447     return (idl_type.v8_conversion_needs_exception_state or
    448             argument.is_variadic or
    449             (method.returns_promise and (idl_type.is_string_type or
    450                                          idl_type.is_enum)))
    451