| OLD | NEW |
| (Empty) |
| 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 attributes. | |
| 30 | |
| 31 FIXME: Not currently used in build. | |
| 32 This is a rewrite of the Perl IDL compiler in Python, but is not complete. | |
| 33 Once it is complete, we will switch all IDL files over to Python at once. | |
| 34 Until then, please work on the Perl IDL compiler. | |
| 35 For details, see bug http://crbug.com/239771 | |
| 36 """ | |
| 37 | |
| 38 from v8_globals import includes, interfaces | |
| 39 import v8_types | |
| 40 import v8_utilities | |
| 41 from v8_utilities import capitalize, cpp_name, has_extended_attribute, uncapital
ize | |
| 42 | |
| 43 | |
| 44 def generate_attribute(interface, attribute): | |
| 45 idl_type = attribute.idl_type | |
| 46 extended_attributes = attribute.extended_attributes | |
| 47 | |
| 48 v8_types.add_includes_for_type(idl_type) | |
| 49 | |
| 50 # [CheckSecurity] | |
| 51 is_check_security_for_node = 'CheckSecurity' in extended_attributes | |
| 52 if is_check_security_for_node: | |
| 53 includes.add('bindings/v8/BindingSecurity.h') | |
| 54 # [Custom] | |
| 55 has_custom_getter = ('Custom' in extended_attributes and | |
| 56 extended_attributes['Custom'] in [None, 'Getter']) | |
| 57 has_custom_setter = (not attribute.is_read_only and | |
| 58 'Custom' in extended_attributes and | |
| 59 extended_attributes['Custom'] in [None, 'Setter']) | |
| 60 # [CustomElementCallbacks], [Reflect] | |
| 61 is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attribute
s | |
| 62 is_reflect = 'Reflect' in extended_attributes | |
| 63 if is_custom_element_callbacks or is_reflect: | |
| 64 includes.add('core/dom/custom/CustomElementCallbackDispatcher.h') | |
| 65 # [RaisesException], [RaisesException=Setter] | |
| 66 is_setter_raises_exception = ( | |
| 67 'RaisesException' in extended_attributes and | |
| 68 extended_attributes['RaisesException'] in [None, 'Setter']) | |
| 69 # [StrictTypeChecking] | |
| 70 has_strict_type_checking = ( | |
| 71 ('StrictTypeChecking' in extended_attributes or | |
| 72 'StrictTypeChecking' in interface.extended_attributes) and | |
| 73 v8_types.is_wrapper_type(idl_type)) | |
| 74 | |
| 75 if (idl_type == 'EventHandler' and | |
| 76 interface.name in ['Window', 'WorkerGlobalScope'] and | |
| 77 attribute.name == 'onerror'): | |
| 78 includes.add('bindings/v8/V8ErrorHandler.h') | |
| 79 | |
| 80 contents = { | |
| 81 'access_control_list': access_control_list(attribute), | |
| 82 'activity_logging_world_list_for_getter': v8_utilities.activity_logging_
world_list(attribute, 'Getter'), # [ActivityLogging] | |
| 83 'activity_logging_world_list_for_setter': v8_utilities.activity_logging_
world_list(attribute, 'Setter'), # [ActivityLogging] | |
| 84 'cached_attribute_validation_method': extended_attributes.get('CachedAtt
ribute'), | |
| 85 'conditional_string': v8_utilities.conditional_string(attribute), | |
| 86 'constructor_type': v8_types.constructor_type(idl_type) | |
| 87 if is_constructor_attribute(attribute) else None, | |
| 88 'cpp_name': cpp_name(attribute), | |
| 89 'cpp_type': v8_types.cpp_type(idl_type), | |
| 90 'deprecate_as': v8_utilities.deprecate_as(attribute), # [DeprecateAs] | |
| 91 'enum_validation_expression': | |
| 92 v8_utilities.enum_validation_expression(idl_type), | |
| 93 'has_custom_getter': has_custom_getter, | |
| 94 'has_custom_setter': has_custom_setter, | |
| 95 'has_strict_type_checking': has_strict_type_checking, | |
| 96 'idl_type': idl_type, | |
| 97 'is_call_with_execution_context': v8_utilities.has_extended_attribute_va
lue(attribute, 'CallWith', 'ExecutionContext'), | |
| 98 'is_check_security_for_node': is_check_security_for_node, | |
| 99 'is_custom_element_callbacks': is_custom_element_callbacks, | |
| 100 'is_expose_js_accessors': 'ExposeJSAccessors' in extended_attributes, | |
| 101 'is_getter_raises_exception': ( # [RaisesException] | |
| 102 'RaisesException' in extended_attributes and | |
| 103 extended_attributes['RaisesException'] in [None, 'Getter']), | |
| 104 'is_implemented_by': 'ImplementedBy' in extended_attributes, | |
| 105 'is_initialized_by_event_constructor': | |
| 106 'InitializedByEventConstructor' in extended_attributes, | |
| 107 'is_keep_alive_for_gc': is_keep_alive_for_gc(interface, attribute), | |
| 108 'is_nullable': attribute.is_nullable, | |
| 109 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes, | |
| 110 'is_read_only': attribute.is_read_only, | |
| 111 'is_reflect': is_reflect, | |
| 112 'is_replaceable': 'Replaceable' in attribute.extended_attributes, | |
| 113 'is_setter_call_with_execution_context': v8_utilities.has_extended_attri
bute_value(attribute, 'SetterCallWith', 'ExecutionContext'), | |
| 114 'is_setter_raises_exception': is_setter_raises_exception, | |
| 115 'has_setter_exception_state': ( | |
| 116 is_setter_raises_exception or has_strict_type_checking or | |
| 117 v8_types.is_integer_type(idl_type)), | |
| 118 'is_static': attribute.is_static, | |
| 119 'is_url': 'URL' in extended_attributes, | |
| 120 'is_unforgeable': 'Unforgeable' in extended_attributes, | |
| 121 'measure_as': v8_utilities.measure_as(attribute), # [MeasureAs] | |
| 122 'name': attribute.name, | |
| 123 'per_context_enabled_function': v8_utilities.per_context_enabled_functio
n_name(attribute), # [PerContextEnabled] | |
| 124 'property_attributes': property_attributes(attribute), | |
| 125 'put_forwards': 'PutForwards' in extended_attributes, | |
| 126 'reflect_empty': extended_attributes.get('ReflectEmpty'), | |
| 127 'reflect_invalid': extended_attributes.get('ReflectInvalid', ''), | |
| 128 'reflect_missing': extended_attributes.get('ReflectMissing'), | |
| 129 'reflect_only': extended_attributes['ReflectOnly'].split('|') | |
| 130 if 'ReflectOnly' in extended_attributes else None, | |
| 131 'setter_callback': setter_callback_name(interface, attribute), | |
| 132 'v8_type': v8_types.v8_type(idl_type), | |
| 133 'runtime_enabled_function': v8_utilities.runtime_enabled_function_name(a
ttribute), # [RuntimeEnabled] | |
| 134 'world_suffixes': ['', 'ForMainWorld'] | |
| 135 if 'PerWorldBindings' in extended_attributes | |
| 136 else [''], # [PerWorldBindings] | |
| 137 } | |
| 138 | |
| 139 if is_constructor_attribute(attribute): | |
| 140 return contents | |
| 141 if not has_custom_getter: | |
| 142 generate_getter(interface, attribute, contents) | |
| 143 if (not has_custom_setter and | |
| 144 (not attribute.is_read_only or 'PutForwards' in extended_attributes)): | |
| 145 generate_setter(interface, attribute, contents) | |
| 146 | |
| 147 return contents | |
| 148 | |
| 149 | |
| 150 ################################################################################ | |
| 151 # Getter | |
| 152 ################################################################################ | |
| 153 | |
| 154 def generate_getter(interface, attribute, contents): | |
| 155 idl_type = attribute.idl_type | |
| 156 extended_attributes = attribute.extended_attributes | |
| 157 | |
| 158 cpp_value = getter_expression(interface, attribute, contents) | |
| 159 # Normally we can inline the function call into the return statement to | |
| 160 # avoid the overhead of using a Ref<> temporary, but for some cases | |
| 161 # (nullable types, EventHandler, [CachedAttribute], or if there are | |
| 162 # exceptions), we need to use a local variable. | |
| 163 # FIXME: check if compilers are smart enough to inline this, and if so, | |
| 164 # always use a local variable (for readability and CG simplicity). | |
| 165 release = False | |
| 166 if (attribute.is_nullable or | |
| 167 idl_type == 'EventHandler' or | |
| 168 'CachedAttribute' in extended_attributes or | |
| 169 contents['is_getter_raises_exception']): | |
| 170 contents['cpp_value_original'] = cpp_value | |
| 171 cpp_value = 'jsValue' | |
| 172 # EventHandler has special handling | |
| 173 if idl_type != 'EventHandler' and v8_types.is_interface_type(idl_type): | |
| 174 release = True | |
| 175 | |
| 176 if 'ReflectOnly' in extended_attributes: | |
| 177 contents['cpp_value_original'] = cpp_value | |
| 178 # FIXME: rename to jsValue | |
| 179 cpp_value = 'resultValue' | |
| 180 | |
| 181 def v8_set_return_value_statement(for_main_world=False): | |
| 182 if contents['is_keep_alive_for_gc']: | |
| 183 return 'v8SetReturnValue(info, wrapper)' | |
| 184 return v8_types.v8_set_return_value(idl_type, cpp_value, extended_attrib
utes=extended_attributes, script_wrappable='imp', release=release, for_main_worl
d=for_main_world) | |
| 185 | |
| 186 contents.update({ | |
| 187 'cpp_value': cpp_value, | |
| 188 'v8_set_return_value_for_main_world': v8_set_return_value_statement(for_
main_world=True), | |
| 189 'v8_set_return_value': v8_set_return_value_statement(), | |
| 190 }) | |
| 191 | |
| 192 | |
| 193 def getter_expression(interface, attribute, contents): | |
| 194 arguments = [] | |
| 195 this_getter_base_name = getter_base_name(interface, attribute, arguments) | |
| 196 getter_name = v8_utilities.scoped_name(interface, attribute, this_getter_bas
e_name) | |
| 197 | |
| 198 arguments.extend(v8_utilities.call_with_arguments(attribute)) | |
| 199 if ('ImplementedBy' in attribute.extended_attributes and | |
| 200 not attribute.is_static): | |
| 201 arguments.append('*imp') | |
| 202 if attribute.is_nullable: | |
| 203 arguments.append('isNull') | |
| 204 if contents['is_getter_raises_exception']: | |
| 205 arguments.append('exceptionState') | |
| 206 return '%s(%s)' % (getter_name, ', '.join(arguments)) | |
| 207 | |
| 208 | |
| 209 CONTENT_ATTRIBUTE_GETTER_NAMES = { | |
| 210 'boolean': 'fastHasAttribute', | |
| 211 'long': 'getIntegralAttribute', | |
| 212 'unsigned long': 'getUnsignedIntegralAttribute', | |
| 213 } | |
| 214 | |
| 215 | |
| 216 def getter_base_name(interface, attribute, arguments): | |
| 217 extended_attributes = attribute.extended_attributes | |
| 218 if 'Reflect' not in extended_attributes: | |
| 219 return uncapitalize(cpp_name(attribute)) | |
| 220 | |
| 221 content_attribute_name = extended_attributes['Reflect'] or attribute.name.lo
wer() | |
| 222 if content_attribute_name in ['class', 'id', 'name']: | |
| 223 # Special-case for performance optimization. | |
| 224 return 'get%sAttribute' % content_attribute_name.capitalize() | |
| 225 | |
| 226 arguments.append(scoped_content_attribute_name(interface, attribute)) | |
| 227 | |
| 228 idl_type = attribute.idl_type | |
| 229 if idl_type in CONTENT_ATTRIBUTE_GETTER_NAMES: | |
| 230 return CONTENT_ATTRIBUTE_GETTER_NAMES[idl_type] | |
| 231 if 'URL' in attribute.extended_attributes: | |
| 232 return 'getURLAttribute' | |
| 233 return 'fastGetAttribute' | |
| 234 | |
| 235 | |
| 236 def is_keep_alive_for_gc(interface, attribute): | |
| 237 idl_type = attribute.idl_type | |
| 238 extended_attributes = attribute.extended_attributes | |
| 239 return ( | |
| 240 # For readonly attributes, for performance reasons we keep the attribute | |
| 241 # wrapper alive while the owner wrapper is alive, because the attribute | |
| 242 # never changes. | |
| 243 (attribute.is_read_only and | |
| 244 v8_types.is_wrapper_type(idl_type) and | |
| 245 # There are some exceptions, however: | |
| 246 not( | |
| 247 # Node lifetime is managed by object grouping. | |
| 248 v8_types.inherits_interface(interface.name, 'Node') or | |
| 249 v8_types.inherits_interface(idl_type, 'Node') or | |
| 250 # A self-reference is unnecessary. | |
| 251 attribute.name == 'self' or | |
| 252 # FIXME: Remove these hard-coded hacks. | |
| 253 idl_type in ['EventTarget', 'Window'] or | |
| 254 idl_type.startswith(('HTML', 'SVG'))))) | |
| 255 | |
| 256 | |
| 257 ################################################################################ | |
| 258 # Setter | |
| 259 ################################################################################ | |
| 260 | |
| 261 def generate_setter(interface, attribute, contents): | |
| 262 def target_attribute(): | |
| 263 target_interface_name = attribute.idl_type | |
| 264 target_attribute_name = extended_attributes['PutForwards'] | |
| 265 target_interface = interfaces[target_interface_name] | |
| 266 try: | |
| 267 return next(attribute | |
| 268 for attribute in target_interface.attributes | |
| 269 if attribute.name == target_attribute_name) | |
| 270 except StopIteration: | |
| 271 raise Exception('[PutForward] target not found:\n' | |
| 272 'Attribute "%s" is not present in interface "%s"' % | |
| 273 (target_attribute_name, target_interface_name)) | |
| 274 | |
| 275 extended_attributes = attribute.extended_attributes | |
| 276 | |
| 277 if 'PutForwards' in extended_attributes: | |
| 278 # Use target attribute in place of original attribute | |
| 279 attribute = target_attribute() | |
| 280 | |
| 281 contents.update({ | |
| 282 'cpp_setter': setter_expression(interface, attribute, contents), | |
| 283 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value( | |
| 284 attribute.idl_type, extended_attributes, 'jsValue', 'cppValue'), | |
| 285 }) | |
| 286 | |
| 287 | |
| 288 def setter_expression(interface, attribute, contents): | |
| 289 extended_attributes = attribute.extended_attributes | |
| 290 arguments = v8_utilities.call_with_arguments(attribute, extended_attributes.
get('SetterCallWith')) | |
| 291 | |
| 292 this_setter_base_name = setter_base_name(interface, attribute, arguments) | |
| 293 setter_name = v8_utilities.scoped_name(interface, attribute, this_setter_bas
e_name) | |
| 294 | |
| 295 if ('ImplementedBy' in extended_attributes and | |
| 296 not attribute.is_static): | |
| 297 arguments.append('*imp') | |
| 298 idl_type = attribute.idl_type | |
| 299 if idl_type == 'EventHandler': | |
| 300 getter_name = v8_utilities.scoped_name(interface, attribute, cpp_name(at
tribute)) | |
| 301 contents['event_handler_getter_expression'] = '%s(%s)' % ( | |
| 302 getter_name, ', '.join(arguments)) | |
| 303 if (interface.name in ['Window', 'WorkerGlobalScope'] and | |
| 304 attribute.name == 'onerror'): | |
| 305 includes.add('bindings/v8/V8ErrorHandler.h') | |
| 306 arguments.append('V8EventListenerList::findOrCreateWrapper<V8ErrorHa
ndler>(jsValue, true, info.GetIsolate())') | |
| 307 else: | |
| 308 arguments.append('V8EventListenerList::getEventListener(jsValue, tru
e, ListenerFindOrCreate)') | |
| 309 elif v8_types.is_interface_type(idl_type) and not v8_types.array_type(idl_ty
pe): | |
| 310 # FIXME: should be able to eliminate WTF::getPtr in most or all cases | |
| 311 arguments.append('WTF::getPtr(cppValue)') | |
| 312 else: | |
| 313 arguments.append('cppValue') | |
| 314 if contents['is_setter_raises_exception']: | |
| 315 arguments.append('exceptionState') | |
| 316 | |
| 317 return '%s(%s)' % (setter_name, ', '.join(arguments)) | |
| 318 | |
| 319 | |
| 320 CONTENT_ATTRIBUTE_SETTER_NAMES = { | |
| 321 'boolean': 'setBooleanAttribute', | |
| 322 'long': 'setIntegralAttribute', | |
| 323 'unsigned long': 'setUnsignedIntegralAttribute', | |
| 324 } | |
| 325 | |
| 326 | |
| 327 def setter_base_name(interface, attribute, arguments): | |
| 328 if 'Reflect' not in attribute.extended_attributes: | |
| 329 return 'set%s' % capitalize(cpp_name(attribute)) | |
| 330 arguments.append(scoped_content_attribute_name(interface, attribute)) | |
| 331 | |
| 332 idl_type = attribute.idl_type | |
| 333 if idl_type in CONTENT_ATTRIBUTE_SETTER_NAMES: | |
| 334 return CONTENT_ATTRIBUTE_SETTER_NAMES[idl_type] | |
| 335 return 'setAttribute' | |
| 336 | |
| 337 | |
| 338 def scoped_content_attribute_name(interface, attribute): | |
| 339 content_attribute_name = attribute.extended_attributes['Reflect'] or attribu
te.name.lower() | |
| 340 namespace = 'SVGNames' if interface.name.startswith('SVG') else 'HTMLNames' | |
| 341 includes.add('%s.h' % namespace) | |
| 342 return '%s::%sAttr' % (namespace, content_attribute_name) | |
| 343 | |
| 344 | |
| 345 ################################################################################ | |
| 346 # Attribute configuration | |
| 347 ################################################################################ | |
| 348 | |
| 349 # [Replaceable] | |
| 350 def setter_callback_name(interface, attribute): | |
| 351 cpp_class_name = cpp_name(interface) | |
| 352 extended_attributes = attribute.extended_attributes | |
| 353 if (('Replaceable' in extended_attributes and | |
| 354 'PutForwards' not in extended_attributes) or | |
| 355 is_constructor_attribute(attribute)): | |
| 356 # FIXME: rename to ForceSetAttributeOnThisCallback, since also used for
Constructors | |
| 357 return '{0}V8Internal::{0}ReplaceableAttributeSetterCallback'.format(cpp
_class_name) | |
| 358 if attribute.is_read_only and 'PutForwards' not in extended_attributes: | |
| 359 return '0' | |
| 360 return '%sV8Internal::%sAttributeSetterCallback' % (cpp_class_name, attribut
e.name) | |
| 361 | |
| 362 | |
| 363 # [DoNotCheckSecurity], [Unforgeable] | |
| 364 def access_control_list(attribute): | |
| 365 extended_attributes = attribute.extended_attributes | |
| 366 access_control = [] | |
| 367 if 'DoNotCheckSecurity' in extended_attributes: | |
| 368 do_not_check_security = extended_attributes['DoNotCheckSecurity'] | |
| 369 if do_not_check_security == 'Setter': | |
| 370 access_control.append('v8::ALL_CAN_WRITE') | |
| 371 else: | |
| 372 access_control.append('v8::ALL_CAN_READ') | |
| 373 if (not attribute.is_read_only or | |
| 374 'Replaceable' in extended_attributes): | |
| 375 access_control.append('v8::ALL_CAN_WRITE') | |
| 376 if 'Unforgeable' in extended_attributes: | |
| 377 access_control.append('v8::PROHIBITS_OVERWRITING') | |
| 378 return access_control or ['v8::DEFAULT'] | |
| 379 | |
| 380 | |
| 381 # [NotEnumerable], [Unforgeable] | |
| 382 def property_attributes(attribute): | |
| 383 extended_attributes = attribute.extended_attributes | |
| 384 property_attributes_list = [] | |
| 385 if ('NotEnumerable' in extended_attributes or | |
| 386 is_constructor_attribute(attribute)): | |
| 387 property_attributes_list.append('v8::DontEnum') | |
| 388 if 'Unforgeable' in extended_attributes: | |
| 389 property_attributes_list.append('v8::DontDelete') | |
| 390 return property_attributes_list or ['v8::None'] | |
| 391 | |
| 392 | |
| 393 ################################################################################ | |
| 394 # Constructors | |
| 395 ################################################################################ | |
| 396 | |
| 397 def is_constructor_attribute(attribute): | |
| 398 return attribute.idl_type.endswith('Constructor') | |
| OLD | NEW |