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 31FIXME: Not currently used in build. 32This is a rewrite of the Perl IDL compiler in Python, but is not complete. 33Once it is complete, we will switch all IDL files over to Python at once. 34Until then, please work on the Perl IDL compiler. 35For details, see bug http://crbug.com/239771 36""" 37 38from v8_globals import includes 39import v8_types 40import v8_utilities 41from v8_utilities import capitalize, cpp_name, has_extended_attribute, uncapitalize 42 43 44def 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 # [Reflect] 61 is_reflect = 'Reflect' in extended_attributes 62 if is_reflect: 63 includes.add('core/dom/custom/CustomElementCallbackDispatcher.h') 64 65 if (idl_type == 'EventHandler' and 66 interface.name in ['Window', 'WorkerGlobalScope'] and 67 attribute.name == 'onerror'): 68 includes.add('bindings/v8/V8ErrorHandler.h') 69 70 contents = { 71 'access_control_list': access_control_list(attribute), 72 'activity_logging_world_list_for_getter': v8_utilities.activity_logging_world_list(attribute, 'Getter'), # [ActivityLogging] 73 'activity_logging_world_list_for_setter': v8_utilities.activity_logging_world_list(attribute, 'Setter'), # [ActivityLogging] 74 'cached_attribute_validation_method': extended_attributes.get('CachedAttribute'), 75 'conditional_string': v8_utilities.conditional_string(attribute), 76 'constructor_type': v8_types.constructor_type(idl_type) 77 if is_constructor_attribute(attribute) else None, 78 'cpp_name': cpp_name(attribute), 79 'cpp_type': v8_types.cpp_type(idl_type), 80 'deprecate_as': v8_utilities.deprecate_as(attribute), # [DeprecateAs] 81 'enum_validation_expression': 82 v8_utilities.enum_validation_expression(idl_type), 83 'has_custom_getter': has_custom_getter, 84 'has_custom_setter': has_custom_setter, 85 'has_strict_type_checking': ( 86 'StrictTypeChecking' in extended_attributes and 87 v8_types.is_interface_type(idl_type)), 88 'idl_type': idl_type, 89 'is_call_with_execution_context': v8_utilities.has_extended_attribute_value(attribute, 'CallWith', 'ExecutionContext'), 90 'is_check_security_for_node': is_check_security_for_node, 91 'is_expose_js_accessors': 'ExposeJSAccessors' in extended_attributes, 92 'is_getter_raises_exception': ( # [RaisesException] 93 'RaisesException' in extended_attributes and 94 extended_attributes['RaisesException'] in [None, 'Getter']), 95 'is_initialized_by_event_constructor': 96 'InitializedByEventConstructor' in extended_attributes, 97 'is_keep_alive_for_gc': is_keep_alive_for_gc(attribute), 98 'is_nullable': attribute.is_nullable, 99 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes, 100 'is_read_only': attribute.is_read_only, 101 'is_reflect': is_reflect, 102 'is_replaceable': 'Replaceable' in attribute.extended_attributes, 103 'is_setter_raises_exception': ( 104 'RaisesException' in extended_attributes and 105 extended_attributes['RaisesException'] in [None, 'Setter']), 106 'is_static': attribute.is_static, 107 'is_unforgeable': 'Unforgeable' in extended_attributes, 108 'measure_as': v8_utilities.measure_as(attribute), # [MeasureAs] 109 'name': attribute.name, 110 'per_context_enabled_function': v8_utilities.per_context_enabled_function_name(attribute), # [PerContextEnabled] 111 'property_attributes': property_attributes(attribute), 112 'setter_callback': setter_callback_name(interface, attribute), 113 'v8_type': v8_types.v8_type(idl_type), 114 'runtime_enabled_function': v8_utilities.runtime_enabled_function_name(attribute), # [RuntimeEnabled] 115 'world_suffixes': ['', 'ForMainWorld'] 116 if 'PerWorldBindings' in extended_attributes 117 else [''], # [PerWorldBindings] 118 } 119 120 if is_constructor_attribute(attribute): 121 return contents 122 if not has_custom_getter: 123 generate_getter(interface, attribute, contents) 124 if not(attribute.is_read_only or has_custom_setter): 125 contents.update({ 126 'cpp_setter': setter_expression(interface, attribute, contents), 127 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value( 128 idl_type, extended_attributes, 'jsValue', 'cppValue'), 129 }) 130 131 return contents 132 133 134# Getter 135 136def generate_getter(interface, attribute, contents): 137 idl_type = attribute.idl_type 138 extended_attributes = attribute.extended_attributes 139 140 cpp_value = getter_expression(interface, attribute, contents) 141 # Normally we can inline the function call into the return statement to 142 # avoid the overhead of using a Ref<> temporary, but for some cases 143 # (nullable types, EventHandler, [CachedAttribute], or if there are 144 # exceptions), we need to use a local variable. 145 # FIXME: check if compilers are smart enough to inline this, and if so, 146 # always use a local variable (for readability and CG simplicity). 147 if (attribute.is_nullable or 148 idl_type == 'EventHandler' or 149 'CachedAttribute' in extended_attributes or 150 contents['is_getter_raises_exception']): 151 contents['cpp_value_original'] = cpp_value 152 cpp_value = 'jsValue' 153 154 if contents['is_keep_alive_for_gc']: 155 v8_set_return_value_statement = 'v8SetReturnValue(info, wrapper)' 156 includes.add('bindings/v8/V8HiddenPropertyName.h') 157 else: 158 v8_set_return_value_statement = v8_types.v8_set_return_value(idl_type, cpp_value, extended_attributes=extended_attributes, script_wrappable='imp') 159 160 contents.update({ 161 'cpp_value': cpp_value, 162 'v8_set_return_value': v8_set_return_value_statement, 163 }) 164 165 166def getter_expression(interface, attribute, contents): 167 arguments = [] 168 this_getter_base_name = getter_base_name(attribute, arguments) 169 getter_name = v8_utilities.scoped_name(interface, attribute, this_getter_base_name) 170 171 arguments.extend(v8_utilities.call_with_arguments(attribute)) 172 if attribute.is_nullable: 173 arguments.append('isNull') 174 if contents['is_getter_raises_exception']: 175 arguments.append('exceptionState') 176 if attribute.idl_type == 'EventHandler': 177 arguments.append('isolatedWorldForIsolate(info.GetIsolate())') 178 return '%s(%s)' % (getter_name, ', '.join(arguments)) 179 180 181CONTENT_ATTRIBUTE_GETTER_NAMES = { 182 'boolean': 'fastHasAttribute', 183 'long': 'getIntegralAttribute', 184 'unsigned long': 'getUnsignedIntegralAttribute', 185} 186 187 188def getter_base_name(attribute, arguments): 189 extended_attributes = attribute.extended_attributes 190 if 'Reflect' not in extended_attributes: 191 return uncapitalize(cpp_name(attribute)) 192 193 content_attribute_name = extended_attributes['Reflect'] or attribute.name.lower() 194 if content_attribute_name in ['class', 'id', 'name']: 195 # Special-case for performance optimization. 196 return 'get%sAttribute' % content_attribute_name.capitalize() 197 198 arguments.append(scoped_content_attribute_name(attribute)) 199 200 idl_type = attribute.idl_type 201 if idl_type in CONTENT_ATTRIBUTE_GETTER_NAMES: 202 return CONTENT_ATTRIBUTE_GETTER_NAMES[idl_type] 203 if 'URL' in attribute.extended_attributes: 204 return 'getURLAttribute' 205 return 'fastGetAttribute' 206 207 208def is_keep_alive_for_gc(attribute): 209 idl_type = attribute.idl_type 210 extended_attributes = attribute.extended_attributes 211 return ( 212 # For readonly attributes, for performance reasons we keep the attribute 213 # wrapper alive while the owner wrapper is alive, because the attribute 214 # never changes. 215 (attribute.is_read_only and 216 v8_types.is_wrapper_type(idl_type) and 217 # There are some exceptions, however: 218 not( 219 # Node lifetime is managed by object grouping. 220 v8_types.is_dom_node_type(idl_type) or 221 # A self-reference is unnecessary. 222 attribute.name == 'self' or 223 # FIXME: Remove these hard-coded hacks. 224 idl_type in ['EventHandler', 'Promise', 'Window'] or 225 idl_type.startswith('HTML')))) 226 227 228# Setter 229 230def setter_expression(interface, attribute, contents): 231 arguments = v8_utilities.call_with_arguments(attribute, attribute.extended_attributes.get('SetterCallWith')) 232 233 this_setter_base_name = setter_base_name(attribute, arguments) 234 setter_name = v8_utilities.scoped_name(interface, attribute, this_setter_base_name) 235 236 idl_type = attribute.idl_type 237 if idl_type == 'EventHandler': 238 # FIXME: pass the isolate instead of the isolated world 239 isolated_world = 'isolatedWorldForIsolate(info.GetIsolate())' 240 arguments.extend(['V8EventListenerList::getEventListener(jsValue, true, ListenerFindOrCreate)', isolated_world]) 241 contents['event_handler_getter_expression'] = 'imp->%s(%s)' % (cpp_name(attribute), isolated_world) 242 elif v8_types.is_interface_type(idl_type) and not v8_types.array_type(idl_type): 243 # FIXME: should be able to eliminate WTF::getPtr in most or all cases 244 arguments.append('WTF::getPtr(cppValue)') 245 else: 246 arguments.append('cppValue') 247 if contents['is_setter_raises_exception']: 248 arguments.append('exceptionState') 249 250 return '%s(%s)' % (setter_name, ', '.join(arguments)) 251 252 253CONTENT_ATTRIBUTE_SETTER_NAMES = { 254 'boolean': 'setBooleanAttribute', 255 'long': 'setIntegralAttribute', 256 'unsigned long': 'setUnsignedIntegralAttribute', 257} 258 259 260def setter_base_name(attribute, arguments): 261 if 'Reflect' not in attribute.extended_attributes: 262 return 'set%s' % capitalize(cpp_name(attribute)) 263 arguments.append(scoped_content_attribute_name(attribute)) 264 265 idl_type = attribute.idl_type 266 if idl_type in CONTENT_ATTRIBUTE_SETTER_NAMES: 267 return CONTENT_ATTRIBUTE_SETTER_NAMES[idl_type] 268 return 'setAttribute' 269 270 271def scoped_content_attribute_name(attribute): 272 content_attribute_name = attribute.extended_attributes['Reflect'] or attribute.name.lower() 273 namespace = 'HTMLNames' # FIXME: can be SVG too 274 includes.add('%s.h' % namespace) 275 return '%s::%sAttr' % (namespace, content_attribute_name) 276 277 278def scoped_name(interface, attribute, base_name): 279 if attribute.is_static: 280 return '%s::%s' % (interface.name, base_name) 281 return 'imp->%s' % base_name 282 283 284# Attribute configuration 285 286# [Replaceable] 287def setter_callback_name(interface, attribute): 288 cpp_class_name = cpp_name(interface) 289 if ('Replaceable' in attribute.extended_attributes or 290 is_constructor_attribute(attribute)): 291 # FIXME: rename to ForceSetAttributeOnThisCallback, since also used for Constructors 292 return '{0}V8Internal::{0}ReplaceableAttributeSetterCallback'.format(cpp_class_name) 293 # FIXME: support [PutForwards] 294 if attribute.is_read_only: 295 return '0' 296 return '%sV8Internal::%sAttributeSetterCallback' % (cpp_class_name, attribute.name) 297 298 299# [DoNotCheckSecurity], [Unforgeable] 300def access_control_list(attribute): 301 extended_attributes = attribute.extended_attributes 302 access_control = [] 303 if 'DoNotCheckSecurity' in extended_attributes: 304 do_not_check_security = extended_attributes['DoNotCheckSecurity'] 305 if do_not_check_security == 'Setter': 306 access_control.append('v8::ALL_CAN_WRITE') 307 else: 308 access_control.append('v8::ALL_CAN_READ') 309 if not attribute.is_read_only: 310 access_control.append('v8::ALL_CAN_WRITE') 311 if 'Unforgeable' in extended_attributes: 312 access_control.append('v8::PROHIBITS_OVERWRITING') 313 return access_control or ['v8::DEFAULT'] 314 315 316# [NotEnumerable], [Unforgeable] 317def property_attributes(attribute): 318 extended_attributes = attribute.extended_attributes 319 property_attributes_list = [] 320 if ('NotEnumerable' in extended_attributes or 321 is_constructor_attribute(attribute)): 322 property_attributes_list.append('v8::DontEnum') 323 if 'Unforgeable' in extended_attributes: 324 property_attributes_list.append('v8::DontDelete') 325 return property_attributes_list or ['v8::None'] 326 327 328# Constructors 329 330def is_constructor_attribute(attribute): 331 return attribute.idl_type.endswith('Constructor') 332