1 # Copyright (C) 2013 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
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
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.
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.
29 """Generate template values for attributes.
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
38 from v8_globals import includes, interfaces
41 from v8_utilities import capitalize, cpp_name, has_extended_attribute, uncapitalize
44 def generate_attribute(interface, attribute):
45 idl_type = attribute.idl_type
46 extended_attributes = attribute.extended_attributes
48 v8_types.add_includes_for_type(idl_type)
51 is_check_security_for_node = 'CheckSecurity' in extended_attributes
52 if is_check_security_for_node:
53 includes.add('bindings/v8/BindingSecurity.h')
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_attributes
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))
75 if (idl_type == 'EventHandler' and
76 interface.name in ['Window', 'WorkerGlobalScope'] and
77 attribute.name == 'onerror'):
78 includes.add('bindings/v8/V8ErrorHandler.h')
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('CachedAttribute'),
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,
97 'is_call_with_execution_context': v8_utilities.has_extended_attribute_value(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_initialized_by_event_constructor':
105 'InitializedByEventConstructor' in extended_attributes,
106 'is_keep_alive_for_gc': is_keep_alive_for_gc(interface, attribute),
107 'is_nullable': attribute.is_nullable,
108 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes,
109 'is_read_only': attribute.is_read_only,
110 'is_reflect': is_reflect,
111 'is_replaceable': 'Replaceable' in attribute.extended_attributes,
112 'is_setter_call_with_execution_context': v8_utilities.has_extended_attribute_value(attribute, 'SetterCallWith', 'ExecutionContext'),
113 'is_setter_raises_exception': is_setter_raises_exception,
114 'has_setter_exception_state': (
115 is_setter_raises_exception or has_strict_type_checking or
116 v8_types.is_integer_type(idl_type)),
117 'is_static': attribute.is_static,
118 'is_url': 'URL' in extended_attributes,
119 'is_unforgeable': 'Unforgeable' in extended_attributes,
120 'measure_as': v8_utilities.measure_as(attribute), # [MeasureAs]
121 'name': attribute.name,
122 'per_context_enabled_function': v8_utilities.per_context_enabled_function_name(attribute), # [PerContextEnabled]
123 'property_attributes': property_attributes(attribute),
124 'put_forwards': 'PutForwards' in extended_attributes,
125 'reflect_empty': extended_attributes.get('ReflectEmpty'),
126 'reflect_invalid': extended_attributes.get('ReflectInvalid', ''),
127 'reflect_missing': extended_attributes.get('ReflectMissing'),
128 'reflect_only': extended_attributes['ReflectOnly'].split('|')
129 if 'ReflectOnly' in extended_attributes else None,
130 'setter_callback': setter_callback_name(interface, attribute),
131 'v8_type': v8_types.v8_type(idl_type),
132 'runtime_enabled_function': v8_utilities.runtime_enabled_function_name(attribute), # [RuntimeEnabled]
133 'world_suffixes': ['', 'ForMainWorld']
134 if 'PerWorldBindings' in extended_attributes
135 else [''], # [PerWorldBindings]
138 if is_constructor_attribute(attribute):
140 if not has_custom_getter:
141 generate_getter(interface, attribute, contents)
142 if (not has_custom_setter and
143 (not attribute.is_read_only or 'PutForwards' in extended_attributes)):
144 generate_setter(interface, attribute, contents)
149 ################################################################################
151 ################################################################################
153 def generate_getter(interface, attribute, contents):
154 idl_type = attribute.idl_type
155 extended_attributes = attribute.extended_attributes
157 cpp_value = getter_expression(interface, attribute, contents)
158 # Normally we can inline the function call into the return statement to
159 # avoid the overhead of using a Ref<> temporary, but for some cases
160 # (nullable types, EventHandler, [CachedAttribute], or if there are
161 # exceptions), we need to use a local variable.
162 # FIXME: check if compilers are smart enough to inline this, and if so,
163 # always use a local variable (for readability and CG simplicity).
165 if (attribute.is_nullable or
166 idl_type == 'EventHandler' or
167 'CachedAttribute' in extended_attributes or
168 contents['is_getter_raises_exception']):
169 contents['cpp_value_original'] = cpp_value
170 cpp_value = 'jsValue'
171 # EventHandler has special handling
172 if idl_type != 'EventHandler' and v8_types.is_interface_type(idl_type):
175 if 'ReflectOnly' in extended_attributes:
176 contents['cpp_value_original'] = cpp_value
177 # FIXME: rename to jsValue
178 cpp_value = 'resultValue'
180 def v8_set_return_value_statement(for_main_world=False):
181 if contents['is_keep_alive_for_gc']:
182 return 'v8SetReturnValue(info, wrapper)'
183 return v8_types.v8_set_return_value(idl_type, cpp_value, extended_attributes=extended_attributes, script_wrappable='imp', release=release, for_main_world=for_main_world)
186 'cpp_value': cpp_value,
187 'v8_set_return_value_for_main_world': v8_set_return_value_statement(for_main_world=True),
188 'v8_set_return_value': v8_set_return_value_statement(),
192 def getter_expression(interface, attribute, contents):
194 this_getter_base_name = getter_base_name(attribute, arguments)
195 getter_name = v8_utilities.scoped_name(interface, attribute, this_getter_base_name)
197 arguments.extend(v8_utilities.call_with_arguments(attribute))
198 if ('ImplementedBy' in attribute.extended_attributes and
199 not attribute.is_static):
200 arguments.append('imp')
201 if attribute.is_nullable:
202 arguments.append('isNull')
203 if contents['is_getter_raises_exception']:
204 arguments.append('exceptionState')
205 return '%s(%s)' % (getter_name, ', '.join(arguments))
208 CONTENT_ATTRIBUTE_GETTER_NAMES = {
209 'boolean': 'fastHasAttribute',
210 'long': 'getIntegralAttribute',
211 'unsigned long': 'getUnsignedIntegralAttribute',
215 def getter_base_name(attribute, arguments):
216 extended_attributes = attribute.extended_attributes
217 if 'Reflect' not in extended_attributes:
218 return uncapitalize(cpp_name(attribute))
220 content_attribute_name = extended_attributes['Reflect'] or attribute.name.lower()
221 if content_attribute_name in ['class', 'id', 'name']:
222 # Special-case for performance optimization.
223 return 'get%sAttribute' % content_attribute_name.capitalize()
225 arguments.append(scoped_content_attribute_name(attribute))
227 idl_type = attribute.idl_type
228 if idl_type in CONTENT_ATTRIBUTE_GETTER_NAMES:
229 return CONTENT_ATTRIBUTE_GETTER_NAMES[idl_type]
230 if 'URL' in attribute.extended_attributes:
231 return 'getURLAttribute'
232 return 'fastGetAttribute'
235 def is_keep_alive_for_gc(interface, attribute):
236 idl_type = attribute.idl_type
237 extended_attributes = attribute.extended_attributes
239 # For readonly attributes, for performance reasons we keep the attribute
240 # wrapper alive while the owner wrapper is alive, because the attribute
242 (attribute.is_read_only and
243 v8_types.is_wrapper_type(idl_type) and
244 # There are some exceptions, however:
246 # Node lifetime is managed by object grouping.
247 v8_types.inherits_interface(interface.name, 'Node') or
248 v8_types.inherits_interface(idl_type, 'Node') or
249 # A self-reference is unnecessary.
250 attribute.name == 'self' or
251 # FIXME: Remove these hard-coded hacks.
252 idl_type in ['EventTarget', 'Window'] or
253 idl_type.startswith('HTML'))))
256 ################################################################################
258 ################################################################################
260 def generate_setter(interface, attribute, contents):
261 def target_attribute():
262 target_interface_name = attribute.idl_type
263 target_attribute_name = extended_attributes['PutForwards']
264 target_interface = interfaces[target_interface_name]
266 return next(attribute
267 for attribute in target_interface.attributes
268 if attribute.name == target_attribute_name)
269 except StopIteration:
270 raise Exception('[PutForward] target not found:\n'
271 'Attribute "%s" is not present in interface "%s"' %
272 (target_attribute_name, target_interface_name))
274 extended_attributes = attribute.extended_attributes
276 if 'PutForwards' in extended_attributes:
277 # Use target attribute in place of original attribute
278 attribute = target_attribute()
281 'cpp_setter': setter_expression(interface, attribute, contents),
282 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value(
283 attribute.idl_type, extended_attributes, 'jsValue', 'cppValue'),
287 def setter_expression(interface, attribute, contents):
288 extended_attributes = attribute.extended_attributes
289 arguments = v8_utilities.call_with_arguments(attribute, extended_attributes.get('SetterCallWith'))
291 this_setter_base_name = setter_base_name(attribute, arguments)
292 setter_name = v8_utilities.scoped_name(interface, attribute, this_setter_base_name)
294 if ('ImplementedBy' in extended_attributes and
295 not attribute.is_static):
296 arguments.append('imp')
297 idl_type = attribute.idl_type
298 if idl_type == 'EventHandler':
299 getter_name = v8_utilities.scoped_name(interface, attribute, cpp_name(attribute))
300 contents['event_handler_getter_expression'] = '%s(%s)' % (
301 getter_name, ', '.join(arguments))
302 if (interface.name in ['Window', 'WorkerGlobalScope'] and
303 attribute.name == 'onerror'):
304 includes.add('bindings/v8/V8ErrorHandler.h')
305 arguments.append('V8EventListenerList::findOrCreateWrapper<V8ErrorHandler>(jsValue, true, info.GetIsolate())')
307 arguments.append('V8EventListenerList::getEventListener(jsValue, true, ListenerFindOrCreate)')
308 elif v8_types.is_interface_type(idl_type) and not v8_types.array_type(idl_type):
309 # FIXME: should be able to eliminate WTF::getPtr in most or all cases
310 arguments.append('WTF::getPtr(cppValue)')
312 arguments.append('cppValue')
313 if contents['is_setter_raises_exception']:
314 arguments.append('exceptionState')
316 return '%s(%s)' % (setter_name, ', '.join(arguments))
319 CONTENT_ATTRIBUTE_SETTER_NAMES = {
320 'boolean': 'setBooleanAttribute',
321 'long': 'setIntegralAttribute',
322 'unsigned long': 'setUnsignedIntegralAttribute',
326 def setter_base_name(attribute, arguments):
327 if 'Reflect' not in attribute.extended_attributes:
328 return 'set%s' % capitalize(cpp_name(attribute))
329 arguments.append(scoped_content_attribute_name(attribute))
331 idl_type = attribute.idl_type
332 if idl_type in CONTENT_ATTRIBUTE_SETTER_NAMES:
333 return CONTENT_ATTRIBUTE_SETTER_NAMES[idl_type]
334 return 'setAttribute'
337 def scoped_content_attribute_name(attribute):
338 content_attribute_name = attribute.extended_attributes['Reflect'] or attribute.name.lower()
339 namespace = 'HTMLNames' # FIXME: can be SVG too
340 includes.add('%s.h' % namespace)
341 return '%s::%sAttr' % (namespace, content_attribute_name)
344 ################################################################################
345 # Attribute configuration
346 ################################################################################
349 def setter_callback_name(interface, attribute):
350 cpp_class_name = cpp_name(interface)
351 extended_attributes = attribute.extended_attributes
352 if (('Replaceable' in extended_attributes and
353 'PutForwards' not in extended_attributes) or
354 is_constructor_attribute(attribute)):
355 # FIXME: rename to ForceSetAttributeOnThisCallback, since also used for Constructors
356 return '{0}V8Internal::{0}ReplaceableAttributeSetterCallback'.format(cpp_class_name)
357 if attribute.is_read_only and 'PutForwards' not in extended_attributes:
359 return '%sV8Internal::%sAttributeSetterCallback' % (cpp_class_name, attribute.name)
362 # [DoNotCheckSecurity], [Unforgeable]
363 def access_control_list(attribute):
364 extended_attributes = attribute.extended_attributes
366 if 'DoNotCheckSecurity' in extended_attributes:
367 do_not_check_security = extended_attributes['DoNotCheckSecurity']
368 if do_not_check_security == 'Setter':
369 access_control.append('v8::ALL_CAN_WRITE')
371 access_control.append('v8::ALL_CAN_READ')
372 if (not attribute.is_read_only or
373 'Replaceable' in extended_attributes):
374 access_control.append('v8::ALL_CAN_WRITE')
375 if 'Unforgeable' in extended_attributes:
376 access_control.append('v8::PROHIBITS_OVERWRITING')
377 return access_control or ['v8::DEFAULT']
380 # [NotEnumerable], [Unforgeable]
381 def property_attributes(attribute):
382 extended_attributes = attribute.extended_attributes
383 property_attributes_list = []
384 if ('NotEnumerable' in extended_attributes or
385 is_constructor_attribute(attribute)):
386 property_attributes_list.append('v8::DontEnum')
387 if 'Unforgeable' in extended_attributes:
388 property_attributes_list.append('v8::DontDelete')
389 return property_attributes_list or ['v8::None']
392 ################################################################################
394 ################################################################################
396 def is_constructor_attribute(attribute):
397 return attribute.idl_type.endswith('Constructor')