David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 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 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 29 | # pylint: disable=relative-import |
| 30 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 31 | """Generate template values for attributes. |
| 32 | |
| 33 | Extends IdlType with property |constructor_type_name|. |
| 34 | |
| 35 | Design doc: http://www.chromium.org/developers/design-documents/idl-compiler |
| 36 | """ |
| 37 | |
| 38 | import idl_types |
| 39 | from idl_types import inherits_interface |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 40 | from v8_globals import includes |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 41 | import v8_types |
| 42 | import v8_utilities |
| 43 | from v8_utilities import (cpp_name_or_partial, capitalize, cpp_name, has_extended_attribute, |
| 44 | has_extended_attribute_value, scoped_name, strip_suffix, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 45 | uncapitalize, extended_attribute_value_as_list, is_unforgeable, |
| 46 | is_legacy_interface_type_checking) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 47 | |
| 48 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 49 | def attribute_context(interface, attribute, interfaces): |
| 50 | """Creates a Jinja template context for an attribute of an interface. |
| 51 | |
| 52 | Args: |
| 53 | interface: An interface which |attribute| belongs to |
| 54 | attribute: An attribute to create the context for |
| 55 | interfaces: A dict which maps an interface name to the definition |
| 56 | which can be referred if needed |
| 57 | |
| 58 | Returns: |
| 59 | A Jinja template context for |attribute| |
| 60 | """ |
| 61 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 62 | idl_type = attribute.idl_type |
| 63 | base_idl_type = idl_type.base_type |
| 64 | extended_attributes = attribute.extended_attributes |
| 65 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 66 | idl_type.add_includes_for_type(extended_attributes) |
| 67 | if idl_type.enum_values: |
| 68 | includes.add('core/inspector/ConsoleMessage.h') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 69 | |
| 70 | # [CheckSecurity] |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 71 | is_cross_origin = 'CrossOrigin' in extended_attributes |
| 72 | is_check_security_for_receiver = ( |
| 73 | has_extended_attribute_value(interface, 'CheckSecurity', 'Receiver') and |
| 74 | is_cross_origin) |
| 75 | is_check_security_for_return_value = ( |
| 76 | has_extended_attribute_value(attribute, 'CheckSecurity', 'ReturnValue')) |
| 77 | if is_check_security_for_receiver or is_check_security_for_return_value: |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 78 | includes.add('bindings/core/v8/BindingSecurity.h') |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 79 | # [CrossOrigin] |
| 80 | if has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'): |
| 81 | includes.add('bindings/core/v8/V8CrossOriginSetterInfo.h') |
| 82 | # [Constructor] |
| 83 | # TODO(yukishiino): Constructors are much like methods although constructors |
| 84 | # are not methods. Constructors must be data-type properties, and we can |
| 85 | # support them as a kind of methods. |
| 86 | constructor_type = idl_type.constructor_type_name if is_constructor_attribute(attribute) else None |
| 87 | # [CEReactions] |
| 88 | is_ce_reactions = 'CEReactions' in extended_attributes |
| 89 | if is_ce_reactions: |
| 90 | includes.add('core/dom/custom/CEReactionsScope.h') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 91 | # [CustomElementCallbacks], [Reflect] |
| 92 | is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes |
| 93 | is_reflect = 'Reflect' in extended_attributes |
| 94 | if is_custom_element_callbacks or is_reflect: |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 95 | includes.add('core/dom/custom/V0CustomElementProcessingStack.h') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 96 | # [PerWorldBindings] |
| 97 | if 'PerWorldBindings' in extended_attributes: |
| 98 | assert idl_type.is_wrapper_type or 'LogActivity' in extended_attributes, '[PerWorldBindings] should only be used with wrapper types: %s.%s' % (interface.name, attribute.name) |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 99 | # [SaveSameObject] |
| 100 | is_save_same_object = ( |
| 101 | 'SameObject' in attribute.extended_attributes and |
| 102 | 'SaveSameObject' in attribute.extended_attributes) |
| 103 | if is_save_same_object: |
| 104 | includes.add('bindings/core/v8/V8PrivateProperty.h') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 105 | |
| 106 | if (base_idl_type == 'EventHandler' and |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 107 | interface.name in ['Window', 'WorkerGlobalScope'] and |
| 108 | attribute.name == 'onerror'): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 109 | includes.add('bindings/core/v8/V8ErrorHandler.h') |
| 110 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 111 | cached_attribute_validation_method = extended_attributes.get('CachedAttribute') |
| 112 | keep_alive_for_gc = is_keep_alive_for_gc(interface, attribute) |
| 113 | if cached_attribute_validation_method or keep_alive_for_gc: |
| 114 | includes.add('bindings/core/v8/V8HiddenValue.h') |
| 115 | |
| 116 | # [CachedAccessor] |
| 117 | is_cached_accessor = 'CachedAccessor' in extended_attributes |
| 118 | if is_cached_accessor: |
| 119 | includes.add('bindings/core/v8/V8PrivateProperty.h') |
| 120 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 121 | context = { |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 122 | 'activity_logging_world_list_for_getter': v8_utilities.activity_logging_world_list(attribute, 'Getter'), # [ActivityLogging] |
| 123 | 'activity_logging_world_list_for_setter': v8_utilities.activity_logging_world_list(attribute, 'Setter'), # [ActivityLogging] |
| 124 | 'activity_logging_world_check': v8_utilities.activity_logging_world_check(attribute), # [ActivityLogging] |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 125 | 'cached_attribute_validation_method': cached_attribute_validation_method, |
| 126 | 'constructor_type': constructor_type, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 127 | 'cpp_name': cpp_name(attribute), |
| 128 | 'cpp_type': idl_type.cpp_type, |
| 129 | 'cpp_type_initializer': idl_type.cpp_type_initializer, |
| 130 | 'deprecate_as': v8_utilities.deprecate_as(attribute), # [DeprecateAs] |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 131 | 'enum_type': idl_type.enum_type, |
| 132 | 'enum_values': idl_type.enum_values, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 133 | 'exposed_test': v8_utilities.exposed(attribute, interface), # [Exposed] |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 134 | 'has_cross_origin_getter': |
| 135 | has_extended_attribute_value(attribute, 'CrossOrigin', None) or |
| 136 | has_extended_attribute_value(attribute, 'CrossOrigin', 'Getter'), |
| 137 | 'has_cross_origin_setter': has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 138 | 'has_custom_getter': has_custom_getter(attribute), |
| 139 | 'has_custom_setter': has_custom_setter(attribute), |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 140 | 'has_setter': has_setter(interface, attribute), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 141 | 'idl_type': str(idl_type), # need trailing [] on array for Dictionary::ConversionContext::setConversionType |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 142 | 'is_cached_accessor': is_cached_accessor, |
| 143 | 'is_call_with_execution_context': has_extended_attribute_value(attribute, 'CallWith', 'ExecutionContext'), |
| 144 | 'is_call_with_script_state': has_extended_attribute_value(attribute, 'CallWith', 'ScriptState'), |
| 145 | 'is_ce_reactions': is_ce_reactions, |
| 146 | 'is_check_security_for_receiver': is_check_security_for_receiver, |
| 147 | 'is_check_security_for_return_value': is_check_security_for_return_value, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 148 | 'is_custom_element_callbacks': is_custom_element_callbacks, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 149 | # TODO(yukishiino): Make all DOM attributes accessor-type properties. |
| 150 | 'is_data_type_property': is_data_type_property(interface, attribute), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 151 | 'is_getter_raises_exception': # [RaisesException] |
| 152 | 'RaisesException' in extended_attributes and |
| 153 | extended_attributes['RaisesException'] in (None, 'Getter'), |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 154 | 'is_keep_alive_for_gc': keep_alive_for_gc, |
| 155 | 'is_lenient_this': 'LenientThis' in extended_attributes, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 156 | 'is_nullable': idl_type.is_nullable, |
| 157 | 'is_explicit_nullable': idl_type.is_explicit_nullable, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 158 | 'is_named_constructor': is_named_constructor_attribute(attribute), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 159 | 'is_partial_interface_member': |
| 160 | 'PartialInterfaceImplementedAs' in extended_attributes, |
| 161 | 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 162 | 'is_put_forwards': 'PutForwards' in extended_attributes, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 163 | 'is_read_only': attribute.is_read_only, |
| 164 | 'is_reflect': is_reflect, |
| 165 | 'is_replaceable': 'Replaceable' in attribute.extended_attributes, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 166 | 'is_save_same_object': is_save_same_object, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 167 | 'is_static': attribute.is_static, |
| 168 | 'is_url': 'URL' in extended_attributes, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 169 | 'is_unforgeable': is_unforgeable(interface, attribute), |
| 170 | 'on_instance': v8_utilities.on_instance(interface, attribute), |
| 171 | 'on_interface': v8_utilities.on_interface(interface, attribute), |
| 172 | 'on_prototype': v8_utilities.on_prototype(interface, attribute), |
| 173 | 'origin_trial_enabled_function': v8_utilities.origin_trial_enabled_function_name(attribute), # [OriginTrialEnabled] |
| 174 | 'origin_trial_feature_name': v8_utilities.origin_trial_feature_name(attribute), # [OriginTrialEnabled] |
| 175 | 'use_output_parameter_for_result': idl_type.use_output_parameter_for_result, |
| 176 | 'measure_as': v8_utilities.measure_as(attribute, interface), # [MeasureAs] |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 177 | 'name': attribute.name, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 178 | 'property_attributes': property_attributes(interface, attribute), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 179 | 'reflect_empty': extended_attributes.get('ReflectEmpty'), |
| 180 | 'reflect_invalid': extended_attributes.get('ReflectInvalid', ''), |
| 181 | 'reflect_missing': extended_attributes.get('ReflectMissing'), |
| 182 | 'reflect_only': extended_attribute_value_as_list(attribute, 'ReflectOnly'), |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 183 | 'runtime_enabled_feature_name': v8_utilities.runtime_enabled_feature_name(attribute), # [RuntimeEnabled] |
| 184 | 'secure_context_test': v8_utilities.secure_context(attribute, interface), # [SecureContext] |
| 185 | 'cached_accessor_name': '%s%sCachedAccessor' % (interface.name, attribute.name.capitalize()), |
| 186 | 'world_suffixes': ( |
| 187 | ['', 'ForMainWorld'] |
| 188 | if 'PerWorldBindings' in extended_attributes |
| 189 | else ['']), # [PerWorldBindings] |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | if is_constructor_attribute(attribute): |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 193 | update_constructor_attribute_context(interface, attribute, context) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 194 | if not has_custom_getter(attribute): |
| 195 | getter_context(interface, attribute, context) |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 196 | if not has_custom_setter(attribute) and has_setter(interface, attribute): |
| 197 | setter_context(interface, attribute, interfaces, context) |
| 198 | |
| 199 | # [CrossOrigin] is incompatible with a number of other attributes, so check |
| 200 | # for them here. |
| 201 | if is_cross_origin: |
| 202 | if context['has_cross_origin_setter'] and context['has_custom_setter']: |
| 203 | raise Exception('[CrossOrigin] and [Custom] are incompatible on the same setter: %s.%s', interface.name, attribute.name) |
| 204 | if context['is_per_world_bindings']: |
| 205 | raise Exception('[CrossOrigin] and [PerWorldBindings] are incompatible: %s.%s', interface.name, attribute.name) |
| 206 | if context['constructor_type']: |
| 207 | raise Exception('[CrossOrigin] cannot be used for constructors: %s.%s', interface.name, attribute.name) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 208 | |
| 209 | return context |
| 210 | |
| 211 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 212 | def filter_accessors(attributes): |
| 213 | return [attribute for attribute in attributes if |
| 214 | not (attribute['exposed_test'] or |
| 215 | attribute['secure_context_test'] or |
| 216 | attribute['origin_trial_enabled_function'] or |
| 217 | attribute['runtime_enabled_feature_name']) and |
| 218 | not attribute['is_data_type_property']] |
| 219 | |
| 220 | |
| 221 | def is_data_attribute(attribute): |
| 222 | return (not (attribute['exposed_test'] or |
| 223 | attribute['secure_context_test'] or |
| 224 | attribute['origin_trial_enabled_function'] or |
| 225 | attribute['runtime_enabled_feature_name']) and |
| 226 | attribute['is_data_type_property']) |
| 227 | |
| 228 | |
| 229 | def is_lazy_data_attribute(attribute): |
| 230 | return ((attribute['constructor_type'] and not attribute['needs_constructor_getter_callback']) or |
| 231 | (attribute['idl_type'] == 'Window' and attribute['name'] == 'frames') or |
| 232 | (attribute['idl_type'] == 'Window' and attribute['name'] == 'self') or |
| 233 | (attribute['idl_type'] == 'Window' and attribute['name'] == 'window')) |
| 234 | |
| 235 | |
| 236 | def filter_data_attributes(attributes): |
| 237 | return [attribute for attribute in attributes if is_data_attribute(attribute) and not is_lazy_data_attribute(attribute)] |
| 238 | |
| 239 | |
| 240 | def filter_lazy_data_attributes(attributes): |
| 241 | return [attribute for attribute in attributes if is_data_attribute(attribute) and is_lazy_data_attribute(attribute)] |
| 242 | |
| 243 | |
| 244 | def filter_origin_trial_enabled(attributes): |
| 245 | return [attribute for attribute in attributes if |
| 246 | attribute['origin_trial_feature_name'] and |
| 247 | not attribute['exposed_test']] |
| 248 | |
| 249 | |
| 250 | def filter_runtime_enabled(attributes): |
| 251 | return [attribute for attribute in attributes if |
| 252 | not (attribute['exposed_test'] or |
| 253 | attribute['secure_context_test']) and |
| 254 | attribute['runtime_enabled_feature_name']] |
| 255 | |
| 256 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 257 | ################################################################################ |
| 258 | # Getter |
| 259 | ################################################################################ |
| 260 | |
| 261 | def getter_context(interface, attribute, context): |
| 262 | idl_type = attribute.idl_type |
| 263 | base_idl_type = idl_type.base_type |
| 264 | extended_attributes = attribute.extended_attributes |
| 265 | |
| 266 | cpp_value = getter_expression(interface, attribute, context) |
| 267 | # Normally we can inline the function call into the return statement to |
| 268 | # avoid the overhead of using a Ref<> temporary, but for some cases |
| 269 | # (nullable types, EventHandler, [CachedAttribute], or if there are |
| 270 | # exceptions), we need to use a local variable. |
| 271 | # FIXME: check if compilers are smart enough to inline this, and if so, |
| 272 | # always use a local variable (for readability and CG simplicity). |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 273 | if (idl_type.is_explicit_nullable or |
| 274 | base_idl_type == 'EventHandler' or |
| 275 | 'CachedAttribute' in extended_attributes or |
| 276 | 'ReflectOnly' in extended_attributes or |
| 277 | context['is_keep_alive_for_gc'] or |
| 278 | context['is_getter_raises_exception']): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 279 | context['cpp_value_original'] = cpp_value |
| 280 | cpp_value = 'cppValue' |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 281 | |
| 282 | def v8_set_return_value_statement(for_main_world=False): |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 283 | if context['is_keep_alive_for_gc'] or 'CachedAttribute' in extended_attributes: |
| 284 | return 'v8SetReturnValue(info, v8Value)' |
| 285 | return idl_type.v8_set_return_value( |
| 286 | cpp_value, extended_attributes=extended_attributes, script_wrappable='impl', |
| 287 | for_main_world=for_main_world, is_static=attribute.is_static) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 288 | |
| 289 | context.update({ |
| 290 | 'cpp_value': cpp_value, |
| 291 | 'cpp_value_to_v8_value': idl_type.cpp_value_to_v8_value( |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 292 | cpp_value=cpp_value, creation_context='holder', |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 293 | extended_attributes=extended_attributes), |
| 294 | 'v8_set_return_value_for_main_world': v8_set_return_value_statement(for_main_world=True), |
| 295 | 'v8_set_return_value': v8_set_return_value_statement(), |
| 296 | }) |
| 297 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 298 | def getter_expression(interface, attribute, context): |
| 299 | arguments = [] |
| 300 | this_getter_base_name = getter_base_name(interface, attribute, arguments) |
| 301 | getter_name = scoped_name(interface, attribute, this_getter_base_name) |
| 302 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 303 | arguments.extend(v8_utilities.call_with_arguments( |
| 304 | attribute.extended_attributes.get('CallWith'))) |
| 305 | # Members of IDL partial interface definitions are implemented in C++ as |
| 306 | # static member functions, which for instance members (non-static members) |
| 307 | # take *impl as their first argument |
| 308 | if ('PartialInterfaceImplementedAs' in attribute.extended_attributes and |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 309 | not attribute.is_static): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 310 | arguments.append('*impl') |
| 311 | if attribute.idl_type.is_explicit_nullable: |
| 312 | arguments.append('isNull') |
| 313 | if context['is_getter_raises_exception']: |
| 314 | arguments.append('exceptionState') |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 315 | if attribute.idl_type.use_output_parameter_for_result: |
| 316 | arguments.append('result') |
| 317 | |
| 318 | expression = '%s(%s)' % (getter_name, ', '.join(arguments)) |
| 319 | # Needed to handle getter expressions returning Type& as the |
| 320 | # use site for |expression| expects Type*. |
| 321 | if attribute.idl_type.is_interface_type and len(arguments) == 0: |
| 322 | return 'WTF::getPtr(%s)' % expression |
| 323 | return expression |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 324 | |
| 325 | |
| 326 | CONTENT_ATTRIBUTE_GETTER_NAMES = { |
| 327 | 'boolean': 'fastHasAttribute', |
| 328 | 'long': 'getIntegralAttribute', |
| 329 | 'unsigned long': 'getUnsignedIntegralAttribute', |
| 330 | } |
| 331 | |
| 332 | |
| 333 | def getter_base_name(interface, attribute, arguments): |
| 334 | extended_attributes = attribute.extended_attributes |
| 335 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 336 | if 'Reflect' not in extended_attributes: |
| 337 | return uncapitalize(cpp_name(attribute)) |
| 338 | |
| 339 | content_attribute_name = extended_attributes['Reflect'] or attribute.name.lower() |
| 340 | if content_attribute_name in ['class', 'id', 'name']: |
| 341 | # Special-case for performance optimization. |
| 342 | return 'get%sAttribute' % content_attribute_name.capitalize() |
| 343 | |
| 344 | arguments.append(scoped_content_attribute_name(interface, attribute)) |
| 345 | |
| 346 | base_idl_type = attribute.idl_type.base_type |
| 347 | if base_idl_type in CONTENT_ATTRIBUTE_GETTER_NAMES: |
| 348 | return CONTENT_ATTRIBUTE_GETTER_NAMES[base_idl_type] |
| 349 | if 'URL' in attribute.extended_attributes: |
| 350 | return 'getURLAttribute' |
| 351 | return 'fastGetAttribute' |
| 352 | |
| 353 | |
| 354 | def is_keep_alive_for_gc(interface, attribute): |
| 355 | idl_type = attribute.idl_type |
| 356 | base_idl_type = idl_type.base_type |
| 357 | extended_attributes = attribute.extended_attributes |
| 358 | return ( |
| 359 | # For readonly attributes, for performance reasons we keep the attribute |
| 360 | # wrapper alive while the owner wrapper is alive, because the attribute |
| 361 | # never changes. |
| 362 | (attribute.is_read_only and |
| 363 | idl_type.is_wrapper_type and |
| 364 | # There are some exceptions, however: |
| 365 | not( |
| 366 | # Node lifetime is managed by object grouping. |
| 367 | inherits_interface(interface.name, 'Node') or |
| 368 | inherits_interface(base_idl_type, 'Node') or |
| 369 | # A self-reference is unnecessary. |
| 370 | attribute.name == 'self' or |
| 371 | # FIXME: Remove these hard-coded hacks. |
| 372 | base_idl_type in ['EventTarget', 'Window'] or |
| 373 | base_idl_type.startswith(('HTML', 'SVG'))))) |
| 374 | |
| 375 | |
| 376 | ################################################################################ |
| 377 | # Setter |
| 378 | ################################################################################ |
| 379 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 380 | def setter_context(interface, attribute, interfaces, context): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 381 | if 'PutForwards' in attribute.extended_attributes: |
| 382 | # Use target interface and attribute in place of original interface and |
| 383 | # attribute from this point onwards. |
| 384 | target_interface_name = attribute.idl_type.base_type |
| 385 | target_attribute_name = attribute.extended_attributes['PutForwards'] |
| 386 | interface = interfaces[target_interface_name] |
| 387 | try: |
| 388 | attribute = next(candidate |
| 389 | for candidate in interface.attributes |
| 390 | if candidate.name == target_attribute_name) |
| 391 | except StopIteration: |
| 392 | raise Exception('[PutForward] target not found:\n' |
| 393 | 'Attribute "%s" is not present in interface "%s"' % |
| 394 | (target_attribute_name, target_interface_name)) |
| 395 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 396 | if ('Replaceable' in attribute.extended_attributes): |
| 397 | context['cpp_setter'] = 'v8CallBoolean(info.Holder()->CreateDataProperty(info.GetIsolate()->GetCurrentContext(), propertyName, v8Value))' |
| 398 | return |
| 399 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 400 | extended_attributes = attribute.extended_attributes |
| 401 | idl_type = attribute.idl_type |
| 402 | |
| 403 | # [RaisesException], [RaisesException=Setter] |
| 404 | is_setter_raises_exception = ( |
| 405 | 'RaisesException' in extended_attributes and |
| 406 | extended_attributes['RaisesException'] in [None, 'Setter']) |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 407 | # [LegacyInterfaceTypeChecking] |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 408 | has_type_checking_interface = ( |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 409 | not is_legacy_interface_type_checking(interface, attribute) and |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 410 | idl_type.is_wrapper_type) |
| 411 | |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 412 | context.update({ |
| 413 | 'has_setter_exception_state': |
| 414 | is_setter_raises_exception or has_type_checking_interface or |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 415 | idl_type.v8_conversion_needs_exception_state, |
| 416 | 'has_type_checking_interface': has_type_checking_interface, |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 417 | 'is_setter_call_with_execution_context': has_extended_attribute_value( |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 418 | attribute, 'SetterCallWith', 'ExecutionContext'), |
| 419 | 'is_setter_raises_exception': is_setter_raises_exception, |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 420 | 'v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value( |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 421 | extended_attributes, 'v8Value', 'cppValue'), |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 422 | }) |
| 423 | |
| 424 | # setter_expression() depends on context values we set above. |
| 425 | context['cpp_setter'] = setter_expression(interface, attribute, context) |
| 426 | |
| 427 | |
| 428 | def setter_expression(interface, attribute, context): |
| 429 | extended_attributes = attribute.extended_attributes |
| 430 | arguments = v8_utilities.call_with_arguments( |
| 431 | extended_attributes.get('SetterCallWith') or |
| 432 | extended_attributes.get('CallWith')) |
| 433 | |
| 434 | this_setter_base_name = setter_base_name(interface, attribute, arguments) |
| 435 | setter_name = scoped_name(interface, attribute, this_setter_base_name) |
| 436 | |
| 437 | # Members of IDL partial interface definitions are implemented in C++ as |
| 438 | # static member functions, which for instance members (non-static members) |
| 439 | # take *impl as their first argument |
| 440 | if ('PartialInterfaceImplementedAs' in extended_attributes and |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 441 | not attribute.is_static): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 442 | arguments.append('*impl') |
| 443 | idl_type = attribute.idl_type |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 444 | if idl_type.base_type == 'EventHandler': |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 445 | getter_name = scoped_name(interface, attribute, cpp_name(attribute)) |
| 446 | context['event_handler_getter_expression'] = '%s(%s)' % ( |
| 447 | getter_name, ', '.join(arguments)) |
| 448 | if (interface.name in ['Window', 'WorkerGlobalScope'] and |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 449 | attribute.name == 'onerror'): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 450 | includes.add('bindings/core/v8/V8ErrorHandler.h') |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 451 | arguments.append( |
| 452 | 'V8EventListenerHelper::ensureEventListener<V8ErrorHandler>(' + |
| 453 | 'v8Value, true, ScriptState::forReceiverObject(info))') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 454 | else: |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 455 | arguments.append( |
| 456 | 'V8EventListenerHelper::getEventListener(' + |
| 457 | 'ScriptState::forReceiverObject(info), v8Value, true, ' + |
| 458 | 'ListenerFindOrCreate)') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 459 | else: |
| 460 | arguments.append('cppValue') |
| 461 | if context['is_setter_raises_exception']: |
| 462 | arguments.append('exceptionState') |
| 463 | |
| 464 | return '%s(%s)' % (setter_name, ', '.join(arguments)) |
| 465 | |
| 466 | |
| 467 | CONTENT_ATTRIBUTE_SETTER_NAMES = { |
| 468 | 'boolean': 'setBooleanAttribute', |
| 469 | 'long': 'setIntegralAttribute', |
| 470 | 'unsigned long': 'setUnsignedIntegralAttribute', |
| 471 | } |
| 472 | |
| 473 | |
| 474 | def setter_base_name(interface, attribute, arguments): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 475 | if 'Reflect' not in attribute.extended_attributes: |
| 476 | return 'set%s' % capitalize(cpp_name(attribute)) |
| 477 | arguments.append(scoped_content_attribute_name(interface, attribute)) |
| 478 | |
| 479 | base_idl_type = attribute.idl_type.base_type |
| 480 | if base_idl_type in CONTENT_ATTRIBUTE_SETTER_NAMES: |
| 481 | return CONTENT_ATTRIBUTE_SETTER_NAMES[base_idl_type] |
| 482 | return 'setAttribute' |
| 483 | |
| 484 | |
| 485 | def scoped_content_attribute_name(interface, attribute): |
| 486 | content_attribute_name = attribute.extended_attributes['Reflect'] or attribute.name.lower() |
| 487 | if interface.name.startswith('SVG'): |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 488 | namespace = 'SVGNames' |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 489 | else: |
| 490 | namespace = 'HTMLNames' |
| 491 | includes.add('core/%s.h' % namespace) |
| 492 | return '%s::%sAttr' % (namespace, content_attribute_name) |
| 493 | |
| 494 | |
| 495 | ################################################################################ |
| 496 | # Attribute configuration |
| 497 | ################################################################################ |
| 498 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 499 | # Property descriptor's {writable: boolean} |
| 500 | def is_writable(attribute): |
| 501 | return (not attribute.is_read_only or |
| 502 | 'PutForwards' in attribute.extended_attributes or |
| 503 | 'Replaceable' in attribute.extended_attributes) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 504 | |
| 505 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 506 | def is_data_type_property(interface, attribute): |
| 507 | if 'CachedAccessor' in attribute.extended_attributes: |
| 508 | return False |
| 509 | return (is_constructor_attribute(attribute) or |
| 510 | 'CrossOrigin' in attribute.extended_attributes) |
| 511 | |
| 512 | |
| 513 | # [PutForwards], [Replaceable] |
| 514 | def has_setter(interface, attribute): |
| 515 | if (is_data_type_property(interface, attribute) and |
| 516 | (is_constructor_attribute(attribute) or |
| 517 | 'Replaceable' in attribute.extended_attributes)): |
| 518 | return False |
| 519 | |
| 520 | return is_writable(attribute) |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 521 | |
| 522 | |
| 523 | # [NotEnumerable], [Unforgeable] |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 524 | def property_attributes(interface, attribute): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 525 | extended_attributes = attribute.extended_attributes |
| 526 | property_attributes_list = [] |
| 527 | if ('NotEnumerable' in extended_attributes or |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 528 | is_constructor_attribute(attribute)): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 529 | property_attributes_list.append('v8::DontEnum') |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 530 | if is_unforgeable(interface, attribute): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 531 | property_attributes_list.append('v8::DontDelete') |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 532 | if not is_writable(attribute): |
| 533 | property_attributes_list.append('v8::ReadOnly') |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 534 | return property_attributes_list or ['v8::None'] |
| 535 | |
| 536 | |
| 537 | # [Custom], [Custom=Getter] |
| 538 | def has_custom_getter(attribute): |
| 539 | extended_attributes = attribute.extended_attributes |
| 540 | return ('Custom' in extended_attributes and |
| 541 | extended_attributes['Custom'] in [None, 'Getter']) |
| 542 | |
| 543 | |
| 544 | # [Custom], [Custom=Setter] |
| 545 | def has_custom_setter(attribute): |
| 546 | extended_attributes = attribute.extended_attributes |
| 547 | return (not attribute.is_read_only and |
| 548 | 'Custom' in extended_attributes and |
| 549 | extended_attributes['Custom'] in [None, 'Setter']) |
| 550 | |
| 551 | |
| 552 | ################################################################################ |
| 553 | # Constructors |
| 554 | ################################################################################ |
| 555 | |
| 556 | idl_types.IdlType.constructor_type_name = property( |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 557 | lambda self: strip_suffix(self.base_type, 'Constructor')) |
| 558 | |
| 559 | |
| 560 | def is_constructor_attribute(attribute): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 561 | return attribute.idl_type.name.endswith('Constructor') |
| 562 | |
| 563 | |
David Ghandehari | c44f003 | 2017-03-22 18:53:21 -0700 | [diff] [blame] | 564 | def is_named_constructor_attribute(attribute): |
| 565 | return attribute.idl_type.name.endswith('ConstructorConstructor') |
| 566 | |
| 567 | |
| 568 | def update_constructor_attribute_context(interface, attribute, context): |
David Ghandehari | 9e5b587 | 2016-07-28 09:50:04 -0700 | [diff] [blame] | 569 | context['needs_constructor_getter_callback'] = context['measure_as'] or context['deprecate_as'] |