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 |