• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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