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 methods.
31 Extends IdlArgument with property |default_cpp_value|.
32 Extends IdlTypeBase and IdlUnionType with property |union_arguments|.
34 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
37 from idl_definitions
import IdlArgument
, IdlOperation
38 from idl_types
import IdlTypeBase
, IdlUnionType
, inherits_interface
39 from v8_globals
import includes
42 from v8_utilities
import (has_extended_attribute_value
, is_unforgeable
,
43 is_legacy_interface_type_checking
)
46 # Methods with any of these require custom method registration code in the
47 # interface's configure*Template() function.
48 CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES
= frozenset([
50 'DoNotCheckSignature',
56 def use_local_result(method
):
57 extended_attributes
= method
.extended_attributes
58 idl_type
= method
.idl_type
59 return (has_extended_attribute_value(method
, 'CallWith', 'ScriptState') or
60 'ImplementedInPrivateScript' in extended_attributes
or
61 'RaisesException' in extended_attributes
or
62 idl_type
.is_union_type
or
63 idl_type
.is_explicit_nullable
)
66 def method_context(interface
, method
, is_visible
=True):
67 arguments
= method
.arguments
68 extended_attributes
= method
.extended_attributes
69 idl_type
= method
.idl_type
70 is_static
= method
.is_static
74 idl_type
.add_includes_for_type(extended_attributes
)
76 this_cpp_value
= cpp_value(interface
, method
, len(arguments
))
78 is_implemented_in_private_script
= 'ImplementedInPrivateScript' in extended_attributes
79 if is_implemented_in_private_script
:
80 includes
.add('bindings/core/v8/PrivateScriptRunner.h')
81 includes
.add('core/frame/LocalFrame.h')
82 includes
.add('platform/ScriptForbiddenScope.h')
84 # [OnlyExposedToPrivateScript]
85 is_only_exposed_to_private_script
= 'OnlyExposedToPrivateScript' in extended_attributes
87 is_call_with_script_arguments
= has_extended_attribute_value(method
, 'CallWith', 'ScriptArguments')
88 if is_call_with_script_arguments
:
89 includes
.update(['bindings/core/v8/ScriptCallStackFactory.h',
90 'core/inspector/ScriptArguments.h'])
91 is_call_with_script_state
= has_extended_attribute_value(method
, 'CallWith', 'ScriptState')
92 is_call_with_this_value
= has_extended_attribute_value(method
, 'CallWith', 'ThisValue')
93 if is_call_with_script_state
or is_call_with_this_value
:
94 includes
.add('bindings/core/v8/ScriptState.h')
95 is_check_security_for_node
= 'CheckSecurity' in extended_attributes
96 if is_check_security_for_node
:
97 includes
.add('bindings/core/v8/BindingSecurity.h')
98 is_custom_element_callbacks
= 'CustomElementCallbacks' in extended_attributes
99 if is_custom_element_callbacks
:
100 includes
.add('core/dom/custom/CustomElementProcessingStack.h')
102 is_do_not_check_security
= 'DoNotCheckSecurity' in extended_attributes
104 is_check_security_for_frame
= (
105 has_extended_attribute_value(interface
, 'CheckSecurity', 'Frame') and
106 not is_do_not_check_security
)
108 is_check_security_for_window
= (
109 has_extended_attribute_value(interface
, 'CheckSecurity', 'Window') and
110 not is_do_not_check_security
)
112 is_raises_exception
= 'RaisesException' in extended_attributes
113 is_custom_call_prologue
= has_extended_attribute_value(method
, 'Custom', 'CallPrologue')
114 is_custom_call_epilogue
= has_extended_attribute_value(method
, 'Custom', 'CallEpilogue')
115 is_post_message
= 'PostMessage' in extended_attributes
117 includes
.add('bindings/core/v8/SerializedScriptValueFactory.h')
118 includes
.add('core/dom/DOMArrayBuffer.h')
119 includes
.add('core/dom/MessagePort.h')
121 if 'LenientThis' in extended_attributes
:
122 raise Exception('[LenientThis] is not supported for operations.')
125 'activity_logging_world_list': v8_utilities
.activity_logging_world_list(method
), # [ActivityLogging]
126 'arguments': [argument_context(interface
, method
, argument
, index
, is_visible
=is_visible
)
127 for index
, argument
in enumerate(arguments
)],
128 'argument_declarations_for_private_script':
129 argument_declarations_for_private_script(interface
, method
),
130 'conditional_string': v8_utilities
.conditional_string(method
),
131 'cpp_type': (v8_types
.cpp_template_type('Nullable', idl_type
.cpp_type
)
132 if idl_type
.is_explicit_nullable
else idl_type
.cpp_type
),
133 'cpp_value': this_cpp_value
,
134 'cpp_type_initializer': idl_type
.cpp_type_initializer
,
135 'custom_registration_extended_attributes':
136 CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES
.intersection(
137 extended_attributes
.iterkeys()),
138 'deprecate_as': v8_utilities
.deprecate_as(method
), # [DeprecateAs]
139 'exposed_test': v8_utilities
.exposed(method
, interface
), # [Exposed]
140 # TODO(yukishiino): Retire has_custom_registration flag. Should be
141 # replaced with V8DOMConfiguration::PropertyLocationConfiguration.
142 'has_custom_registration':
144 is_unforgeable(interface
, method
) or
145 v8_utilities
.has_extended_attribute(
146 method
, CUSTOM_REGISTRATION_EXTENDED_ATTRIBUTES
),
147 'has_exception_state':
148 is_raises_exception
or
149 is_check_security_for_frame
or
150 is_check_security_for_window
or
151 any(argument
for argument
in arguments
152 if (argument
.idl_type
.name
== 'SerializedScriptValue' or
153 argument_conversion_needs_exception_state(method
, argument
))),
154 'idl_type': idl_type
.base_type
,
155 'is_call_with_execution_context': has_extended_attribute_value(method
, 'CallWith', 'ExecutionContext'),
156 'is_call_with_script_arguments': is_call_with_script_arguments
,
157 'is_call_with_script_state': is_call_with_script_state
,
158 'is_call_with_this_value': is_call_with_this_value
,
159 'is_check_security_for_frame': is_check_security_for_frame
,
160 'is_check_security_for_node': is_check_security_for_node
,
161 'is_check_security_for_window': is_check_security_for_window
,
162 'is_custom': 'Custom' in extended_attributes
and
163 not (is_custom_call_prologue
or is_custom_call_epilogue
),
164 'is_custom_call_prologue': is_custom_call_prologue
,
165 'is_custom_call_epilogue': is_custom_call_epilogue
,
166 'is_custom_element_callbacks': is_custom_element_callbacks
,
167 'is_do_not_check_security': is_do_not_check_security
,
168 'is_do_not_check_signature': 'DoNotCheckSignature' in extended_attributes
,
169 'is_explicit_nullable': idl_type
.is_explicit_nullable
,
170 'is_implemented_in_private_script': is_implemented_in_private_script
,
171 'is_partial_interface_member':
172 'PartialInterfaceImplementedAs' in extended_attributes
,
173 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes
,
174 'is_post_message': is_post_message
,
175 'is_raises_exception': is_raises_exception
,
176 'is_read_only': is_unforgeable(interface
, method
),
177 'is_static': is_static
,
178 'is_variadic': arguments
and arguments
[-1].is_variadic
,
179 'measure_as': v8_utilities
.measure_as(method
, interface
), # [MeasureAs]
181 'number_of_arguments': len(arguments
),
182 'number_of_required_arguments': len([
183 argument
for argument
in arguments
184 if not (argument
.is_optional
or argument
.is_variadic
)]),
185 'number_of_required_or_variadic_arguments': len([
186 argument
for argument
in arguments
187 if not argument
.is_optional
]),
188 'on_instance': v8_utilities
.on_instance(interface
, method
),
189 'on_interface': v8_utilities
.on_interface(interface
, method
),
190 'on_prototype': v8_utilities
.on_prototype(interface
, method
),
191 'only_exposed_to_private_script': is_only_exposed_to_private_script
,
192 'private_script_v8_value_to_local_cpp_value': idl_type
.v8_value_to_local_cpp_value(
193 extended_attributes
, 'v8Value', 'cppValue', isolate
='scriptState->isolate()', bailout_return_value
='false'),
194 'property_attributes': property_attributes(interface
, method
),
195 'returns_promise': method
.returns_promise
,
196 'runtime_enabled_function': v8_utilities
.runtime_enabled_function_name(method
), # [RuntimeEnabled]
197 'should_be_exposed_to_script': not (is_implemented_in_private_script
and is_only_exposed_to_private_script
),
198 'use_output_parameter_for_result': idl_type
.use_output_parameter_for_result
,
199 'use_local_result': use_local_result(method
),
200 'v8_set_return_value': v8_set_return_value(interface
.name
, method
, this_cpp_value
),
201 'v8_set_return_value_for_main_world': v8_set_return_value(interface
.name
, method
, this_cpp_value
, for_main_world
=True),
202 'visible': is_visible
,
203 'world_suffixes': ['', 'ForMainWorld'] if 'PerWorldBindings' in extended_attributes
else [''], # [PerWorldBindings],
207 def argument_context(interface
, method
, argument
, index
, is_visible
=True):
208 extended_attributes
= argument
.extended_attributes
209 idl_type
= argument
.idl_type
211 idl_type
.add_includes_for_type(extended_attributes
)
212 this_cpp_value
= cpp_value(interface
, method
, index
)
213 is_variadic_wrapper_type
= argument
.is_variadic
and idl_type
.is_wrapper_type
215 # [TypeChecking=Interface] / [LegacyInterfaceTypeChecking]
216 has_type_checking_interface
= (
217 not is_legacy_interface_type_checking(interface
, method
) and
218 idl_type
.is_wrapper_type
)
220 if ('ImplementedInPrivateScript' in extended_attributes
and
221 not idl_type
.is_wrapper_type
and
222 not idl_type
.is_basic_type
):
223 raise Exception('Private scripts supports only primitive types and DOM wrappers.')
225 set_default_value
= argument
.set_default_value
226 this_cpp_type
= idl_type
.cpp_type_args(extended_attributes
=extended_attributes
,
228 used_as_variadic_argument
=argument
.is_variadic
)
231 v8_types
.cpp_template_type('Nullable', this_cpp_type
)
232 if idl_type
.is_explicit_nullable
and not argument
.is_variadic
234 'cpp_value': this_cpp_value
,
235 # FIXME: check that the default value's type is compatible with the argument's
236 'set_default_value': set_default_value
,
237 'enum_type': idl_type
.enum_type
,
238 'enum_values': idl_type
.enum_values
,
239 'handle': '%sHandle' % argument
.name
,
240 # FIXME: remove once [Default] removed and just use argument.default_value
241 'has_default': 'Default' in extended_attributes
or set_default_value
,
242 'has_type_checking_interface': has_type_checking_interface
,
243 # Dictionary is special-cased, but arrays and sequences shouldn't be
244 'idl_type': idl_type
.base_type
,
245 'idl_type_object': idl_type
,
247 'is_callback_function': idl_type
.is_callback_function
,
248 'is_callback_interface': idl_type
.is_callback_interface
,
249 # FIXME: Remove generic 'Dictionary' special-casing
250 'is_dictionary': idl_type
.is_dictionary
or idl_type
.base_type
== 'Dictionary',
251 'is_explicit_nullable': idl_type
.is_explicit_nullable
,
252 'is_nullable': idl_type
.is_nullable
,
253 'is_optional': argument
.is_optional
,
254 'is_variadic': argument
.is_variadic
,
255 'is_variadic_wrapper_type': is_variadic_wrapper_type
,
256 'is_wrapper_type': idl_type
.is_wrapper_type
,
257 'name': argument
.name
,
258 'private_script_cpp_value_to_v8_value': idl_type
.cpp_value_to_v8_value(
259 argument
.name
, isolate
='scriptState->isolate()',
260 creation_context
='scriptState->context()->Global()'),
261 'use_permissive_dictionary_conversion': 'PermissiveDictionaryConversion' in extended_attributes
,
262 'v8_set_return_value': v8_set_return_value(interface
.name
, method
, this_cpp_value
),
263 'v8_set_return_value_for_main_world': v8_set_return_value(interface
.name
, method
, this_cpp_value
, for_main_world
=True),
264 'v8_value_to_local_cpp_value': v8_value_to_local_cpp_value(method
, argument
, index
),
268 def argument_declarations_for_private_script(interface
, method
):
269 argument_declarations
= ['LocalFrame* frame']
270 argument_declarations
.append('%s* holderImpl' % interface
.name
)
271 argument_declarations
.extend(['%s %s' % (argument
.idl_type
.cpp_type_args(
272 used_as_rvalue_type
=True), argument
.name
) for argument
in method
.arguments
])
273 if method
.idl_type
.name
!= 'void':
274 argument_declarations
.append('%s* %s' % (method
.idl_type
.cpp_type
, 'result'))
275 return argument_declarations
278 ################################################################################
280 ################################################################################
282 def cpp_value(interface
, method
, number_of_arguments
):
283 def cpp_argument(argument
):
284 idl_type
= argument
.idl_type
285 if idl_type
.name
== 'EventListener':
287 if (idl_type
.name
in ['NodeFilter', 'NodeFilterOrNull',
288 'XPathNSResolver', 'XPathNSResolverOrNull']):
289 # FIXME: remove this special case
290 return '%s.release()' % argument
.name
293 # Truncate omitted optional arguments
294 arguments
= method
.arguments
[:number_of_arguments
]
296 if 'ImplementedInPrivateScript' in method
.extended_attributes
:
297 cpp_arguments
.append('toLocalFrame(toFrameIfNotDetached(info.GetIsolate()->GetCurrentContext()))')
298 cpp_arguments
.append('impl')
300 if method
.is_constructor
:
301 call_with_values
= interface
.extended_attributes
.get('ConstructorCallWith')
303 call_with_values
= method
.extended_attributes
.get('CallWith')
304 cpp_arguments
.extend(v8_utilities
.call_with_arguments(call_with_values
))
306 # Members of IDL partial interface definitions are implemented in C++ as
307 # static member functions, which for instance members (non-static members)
308 # take *impl as their first argument
309 if ('PartialInterfaceImplementedAs' in method
.extended_attributes
and
310 not 'ImplementedInPrivateScript' in method
.extended_attributes
and
311 not method
.is_static
):
312 cpp_arguments
.append('*impl')
313 cpp_arguments
.extend(cpp_argument(argument
) for argument
in arguments
)
315 if 'ImplementedInPrivateScript' in method
.extended_attributes
:
316 if method
.idl_type
.name
!= 'void':
317 cpp_arguments
.append('&result')
318 elif ('RaisesException' in method
.extended_attributes
or
319 (method
.is_constructor
and
320 has_extended_attribute_value(interface
, 'RaisesException', 'Constructor'))):
321 cpp_arguments
.append('exceptionState')
323 # If a method returns an IDL dictionary or union type, the return value is
324 # passed as an argument to impl classes.
325 idl_type
= method
.idl_type
326 if idl_type
and idl_type
.use_output_parameter_for_result
:
327 cpp_arguments
.append('result')
329 if method
.name
== 'Constructor':
331 elif method
.name
== 'NamedConstructor':
332 base_name
= 'createForJSConstructor'
333 elif 'ImplementedInPrivateScript' in method
.extended_attributes
:
334 base_name
= '%sMethod' % method
.name
336 base_name
= v8_utilities
.cpp_name(method
)
338 cpp_method_name
= v8_utilities
.scoped_name(interface
, method
, base_name
)
339 return '%s(%s)' % (cpp_method_name
, ', '.join(cpp_arguments
))
342 def v8_set_return_value(interface_name
, method
, cpp_value
, for_main_world
=False):
343 idl_type
= method
.idl_type
344 extended_attributes
= method
.extended_attributes
345 if not idl_type
or idl_type
.name
== 'void':
346 # Constructors and void methods don't have a return type
349 if ('ImplementedInPrivateScript' in extended_attributes
and
350 not idl_type
.is_wrapper_type
and
351 not idl_type
.is_basic_type
):
352 raise Exception('Private scripts supports only primitive types and DOM wrappers.')
355 # [CallWith=ScriptState], [RaisesException]
356 if use_local_result(method
):
357 if idl_type
.is_explicit_nullable
:
358 # result is of type Nullable<T>
359 cpp_value
= 'result.get()'
362 release
= idl_type
.release
364 script_wrappable
= 'impl' if inherits_interface(interface_name
, 'Node') else ''
365 return idl_type
.v8_set_return_value(cpp_value
, extended_attributes
, script_wrappable
=script_wrappable
, release
=release
, for_main_world
=for_main_world
, is_static
=method
.is_static
)
368 def v8_value_to_local_cpp_variadic_value(method
, argument
, index
, return_promise
):
369 assert argument
.is_variadic
370 idl_type
= argument
.idl_type
371 this_cpp_type
= idl_type
.cpp_type
373 if method
.returns_promise
:
374 check_expression
= 'exceptionState.hadException()'
376 check_expression
= 'exceptionState.throwIfNeeded()'
378 if idl_type
.is_dictionary
or idl_type
.is_union_type
:
379 vector_type
= 'HeapVector'
381 vector_type
= 'Vector'
384 'assign_expression': 'toImplArguments<%s<%s>>(info, %s, exceptionState)' % (vector_type
, this_cpp_type
, index
),
385 'check_expression': check_expression
,
386 'cpp_type': this_cpp_type
,
387 'cpp_name': argument
.name
,
388 'declare_variable': False,
392 def v8_value_to_local_cpp_value(method
, argument
, index
, return_promise
=False, restricted_float
=False):
393 extended_attributes
= argument
.extended_attributes
394 idl_type
= argument
.idl_type
396 if argument
.is_variadic
:
397 return v8_value_to_local_cpp_variadic_value(method
, argument
, index
, return_promise
)
398 return idl_type
.v8_value_to_local_cpp_value(extended_attributes
, 'info[%s]' % index
,
399 name
, index
=index
, declare_variable
=False,
400 use_exception_state
=method
.returns_promise
,
401 restricted_float
=restricted_float
)
404 ################################################################################
405 # Auxiliary functions
406 ################################################################################
409 def property_attributes(interface
, method
):
410 extended_attributes
= method
.extended_attributes
411 property_attributes_list
= []
412 if 'NotEnumerable' in extended_attributes
:
413 property_attributes_list
.append('v8::DontEnum')
414 if is_unforgeable(interface
, method
):
415 property_attributes_list
.append('v8::ReadOnly')
416 if property_attributes_list
:
417 property_attributes_list
.insert(0, 'v8::DontDelete')
418 return property_attributes_list
421 def argument_set_default_value(argument
):
422 idl_type
= argument
.idl_type
423 default_value
= argument
.default_value
424 if not default_value
:
426 if idl_type
.is_dictionary
:
427 if not argument
.default_value
.is_null
:
428 raise Exception('invalid default value for dictionary type')
430 if idl_type
.is_array_or_sequence_type
:
431 if default_value
.value
!= '[]':
432 raise Exception('invalid default value for sequence type: %s' % default_value
.value
)
433 # Nothing to do when we set an empty sequence as default value, but we
434 # need to return non-empty value so that we don't generate method calls
435 # without this argument.
436 return '/* Nothing to do */'
437 if idl_type
.is_union_type
:
438 if argument
.default_value
.is_null
:
439 if not idl_type
.includes_nullable_type
:
440 raise Exception('invalid default value for union type: null for %s'
442 # Union container objects are "null" initially.
443 return '/* null default value */'
444 if isinstance(default_value
.value
, basestring
):
445 member_type
= idl_type
.string_member_type
446 elif isinstance(default_value
.value
, (int, float)):
447 member_type
= idl_type
.numeric_member_type
448 elif isinstance(default_value
.value
, bool):
449 member_type
= idl_type
.boolean_member_type
452 if member_type
is None:
453 raise Exception('invalid default value for union type: %r for %s'
454 % (default_value
.value
, idl_type
.name
))
455 member_type_name
= (member_type
.inner_type
.name
456 if member_type
.is_nullable
else
458 return '%s.set%s(%s)' % (argument
.name
, member_type_name
,
459 member_type
.literal_cpp_value(default_value
))
460 return '%s = %s' % (argument
.name
,
461 idl_type
.literal_cpp_value(default_value
))
463 IdlArgument
.set_default_value
= property(argument_set_default_value
)
466 def method_returns_promise(method
):
467 return method
.idl_type
and method
.idl_type
.name
== 'Promise'
469 IdlOperation
.returns_promise
= property(method_returns_promise
)
472 def argument_conversion_needs_exception_state(method
, argument
):
473 idl_type
= argument
.idl_type
474 return (idl_type
.v8_conversion_needs_exception_state
or
475 argument
.is_variadic
or
476 (method
.returns_promise
and idl_type
.is_string_type
))