1# Copyright 2019 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import itertools
6
7import web_idl
8
9from . import name_style
10from .blink_v8_bridge import blink_class_name
11from .blink_v8_bridge import blink_type_info
12from .blink_v8_bridge import make_v8_to_blink_value
13from .blink_v8_bridge import make_v8_to_blink_value_variadic
14from .blink_v8_bridge import v8_bridge_class_name
15from .code_node import EmptyNode
16from .code_node import ListNode
17from .code_node import SequenceNode
18from .code_node import SymbolDefinitionNode
19from .code_node import SymbolNode
20from .code_node import SymbolScopeNode
21from .code_node import TextNode
22from .code_node import WeakDependencyNode
23from .code_node_cxx import CxxBlockNode
24from .code_node_cxx import CxxBreakableBlockNode
25from .code_node_cxx import CxxClassDefNode
26from .code_node_cxx import CxxFuncDeclNode
27from .code_node_cxx import CxxFuncDefNode
28from .code_node_cxx import CxxLikelyIfNode
29from .code_node_cxx import CxxMultiBranchesNode
30from .code_node_cxx import CxxNamespaceNode
31from .code_node_cxx import CxxSwitchNode
32from .code_node_cxx import CxxUnlikelyIfNode
33from .codegen_accumulator import CodeGenAccumulator
34from .codegen_context import CodeGenContext
35from .codegen_expr import CodeGenExpr
36from .codegen_expr import expr_and
37from .codegen_expr import expr_from_exposure
38from .codegen_expr import expr_or
39from .codegen_format import format_template as _format
40from .codegen_utils import component_export
41from .codegen_utils import component_export_header
42from .codegen_utils import enclose_with_header_guard
43from .codegen_utils import make_copyright_header
44from .codegen_utils import make_forward_declarations
45from .codegen_utils import make_header_include_directives
46from .codegen_utils import write_code_node_to_file
47from .mako_renderer import MakoRenderer
48from .package_initializer import package_initializer
49from .path_manager import PathManager
50from .task_queue import TaskQueue
51
52
53def _is_none_or_str(arg):
54    return arg is None or isinstance(arg, str)
55
56
57def backward_compatible_api_func(cg_context):
58    """
59    Returns the Blink function name compatible with the old bindings generator.
60    """
61    assert isinstance(cg_context, CodeGenContext)
62
63    name = (cg_context.member_like.code_generator_info.property_implemented_as
64            or cg_context.member_like.identifier
65            or cg_context.property_.identifier)
66
67    if cg_context.attribute_get:
68        # modules/webaudio/biquad_filter_node.idl has readonly attribute "Q"
69        # and somehow it's implemented as "q" in Blink.
70        if name == "Q":
71            name = "q"
72
73    if cg_context.attribute_set:
74        tokens = name_style.raw.tokenize(name)
75        if tokens[0] in ("IDL", "css", "xml"):
76            tokens[0] = tokens[0].upper()
77        else:
78            tokens[0] = tokens[0].capitalize()
79        tokens.insert(0, "set")
80        name = "".join(tokens)
81
82    if cg_context.indexed_property_getter and not name:
83        name = "AnonymousIndexedGetter"
84    if cg_context.indexed_property_setter and not name:
85        name = "AnonymousIndexedSetter"
86    if cg_context.named_property_getter and not name:
87        name = "AnonymousNamedGetter"
88    if cg_context.named_property_setter and not name:
89        name = "AnonymousNamedSetter"
90    if cg_context.named_property_deleter and not name:
91        name = "AnonymousNamedDeleter"
92
93    return name
94
95
96def callback_function_name(cg_context,
97                           overload_index=None,
98                           for_cross_origin=False,
99                           no_alloc_direct_call=False):
100    assert isinstance(cg_context, CodeGenContext)
101
102    def _cxx_name(name):
103        """
104        Returns a property name that the bindings generator can use in
105        generated code.
106
107        Note that Web IDL allows '-' (hyphen-minus) and '_' (low line) in
108        identifiers but C++ does not allow or recommend them.  This function
109        encodes these characters.
110        """
111        # In Python3, we can use str.maketrans and str.translate.
112        #
113        # We're optimistic about name conflict.  It's highly unlikely that
114        # these replacements will cause a conflict.
115        assert "Dec45" not in name
116        assert "Dec95" not in name
117        name = name.replace("-", "Dec45")
118        name = name.replace("_", "Dec95")
119        return name
120
121    if cg_context.constant:
122        property_name = cg_context.property_.identifier
123    else:
124        property_name = _cxx_name(cg_context.property_.identifier)
125
126    if cg_context.attribute_get:
127        kind = "AttributeGet"
128    elif cg_context.attribute_set:
129        kind = "AttributeSet"
130    elif cg_context.constant:
131        kind = "Constant"
132    elif cg_context.constructor_group:
133        if cg_context.is_named_constructor:
134            kind = "NamedConstructor"
135        else:
136            property_name = ""
137            kind = "Constructor"
138    elif cg_context.exposed_construct:
139        if cg_context.is_named_constructor:
140            kind = "NamedConstructorProperty"
141        elif cg_context.legacy_window_alias:
142            kind = "LegacyWindowAlias"
143        else:
144            kind = "ExposedConstruct"
145    elif cg_context.operation_group:
146        kind = "Operation"
147    elif cg_context.stringifier:
148        kind = "Operation"
149
150    if for_cross_origin:
151        suffix = "CrossOrigin"
152    elif overload_index is not None:
153        suffix = "Overload{}".format(overload_index + 1)
154    elif no_alloc_direct_call:
155        suffix = "NoAllocDirectCallback"
156    else:
157        suffix = "Callback"
158
159    if cg_context.for_world == CodeGenContext.MAIN_WORLD:
160        world_suffix = "ForMainWorld"
161    elif cg_context.for_world == CodeGenContext.NON_MAIN_WORLDS:
162        world_suffix = "ForNonMainWorlds"
163    elif cg_context.for_world == CodeGenContext.ALL_WORLDS:
164        world_suffix = ""
165
166    return name_style.func(property_name, kind, suffix, world_suffix)
167
168
169def constant_name(cg_context):
170    assert isinstance(cg_context, CodeGenContext)
171    assert cg_context.constant
172
173    property_name = cg_context.property_.identifier.lower()
174
175    return name_style.constant(property_name)
176
177
178def custom_function_name(cg_context):
179    assert isinstance(cg_context, CodeGenContext)
180
181    if cg_context.named_property_getter:
182        return "NamedPropertyGetterCustom"
183    if cg_context.named_property_setter:
184        return "NamedPropertySetterCustom"
185    if cg_context.named_property_deleter:
186        return "NamedPropertyDeleterCustom"
187
188    if cg_context.attribute_get:
189        suffix = "AttributeGetterCustom"
190    elif cg_context.attribute_set:
191        suffix = "AttributeSetterCustom"
192    elif cg_context.operation_group:
193        suffix = "MethodCustom"
194    else:
195        assert False
196
197    return name_style.func(cg_context.property_.identifier, suffix)
198
199
200# ----------------------------------------------------------------------------
201# Callback functions
202# ----------------------------------------------------------------------------
203
204
205def bind_blink_api_arguments(code_node, cg_context):
206    assert isinstance(code_node, SymbolScopeNode)
207    assert isinstance(cg_context, CodeGenContext)
208
209    if cg_context.attribute_get:
210        return
211
212    if cg_context.attribute_set:
213        real_type = cg_context.attribute.idl_type.unwrap(typedef=True)
214        if real_type.is_enumeration:
215            pattern = """\
216// https://heycam.github.io/webidl/#dfn-attribute-setter
217// step 4.6.1. Let S be ? ToString(V).
218const auto&& arg1_value_string =
219    NativeValueTraits<IDLStringV2>::NativeValue(
220        ${isolate}, ${v8_property_value}, ${exception_state});
221if (${exception_state}.HadException())
222  return;
223// step 4.6.2. If S is not one of the enumeration's values, then return
224//   undefined.
225const auto arg1_value_maybe_enum = {enum_type}::Create(arg1_value_string);
226if (!arg1_value_maybe_enum) {{
227  bindings::ReportInvalidEnumSetToAttribute(
228      ${isolate}, arg1_value_string, "{enum_type_name}", ${exception_state});
229  return;  // Return undefined.
230}}
231const auto ${arg1_value} = arg1_value_maybe_enum.value();
232"""
233            text = _format(pattern,
234                           enum_type=blink_class_name(
235                               real_type.type_definition_object),
236                           enum_type_name=real_type.identifier)
237            code_node.register_code_symbol(SymbolNode("arg1_value", text))
238            return
239
240        name = "arg1_value"
241        v8_value = "${v8_property_value}"
242        code_node.register_code_symbol(
243            make_v8_to_blink_value(name, v8_value,
244                                   cg_context.attribute.idl_type))
245        return
246
247    for index, argument in enumerate(cg_context.function_like.arguments):
248        name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier)
249        if argument.is_variadic:
250            code_node.register_code_symbol(
251                make_v8_to_blink_value_variadic(name, "${info}", index,
252                                                argument.idl_type))
253        else:
254            v8_value = "${{info}}[{}]".format(argument.index)
255            code_node.register_code_symbol(
256                make_v8_to_blink_value(name,
257                                       v8_value,
258                                       argument.idl_type,
259                                       argument_index=index,
260                                       default_value=argument.default_value,
261                                       cg_context=cg_context))
262
263
264def bind_callback_local_vars(code_node, cg_context):
265    assert isinstance(code_node, SymbolScopeNode)
266    assert isinstance(cg_context, CodeGenContext)
267
268    S = SymbolNode
269    T = TextNode
270
271    local_vars = []
272    template_vars = {}
273
274    local_vars.extend([
275        S("blink_property_name",
276          ("const AtomicString& ${blink_property_name} = "
277           "ToCoreAtomicString(${v8_property_name}.As<v8::String>());")),
278        S("class_like_name", ("const char* const ${class_like_name} = "
279                              "\"${class_like.identifier}\";")),
280        S("current_context", ("v8::Local<v8::Context> ${current_context} = "
281                              "${isolate}->GetCurrentContext();")),
282        S("current_script_state", ("ScriptState* ${current_script_state} = "
283                                   "ScriptState::From(${current_context});")),
284        S("isolate", "v8::Isolate* ${isolate} = ${info}.GetIsolate();"),
285        S("non_undefined_argument_length",
286          ("const int ${non_undefined_argument_length} = "
287           "bindings::NonUndefinedArgumentLength(${info});")),
288        S("per_context_data", ("V8PerContextData* ${per_context_data} = "
289                               "${script_state}->PerContextData();")),
290        S("per_isolate_data", ("V8PerIsolateData* ${per_isolate_data} = "
291                               "V8PerIsolateData::From(${isolate});")),
292        S("property_name",
293          "const char* const ${property_name} = \"${property.identifier}\";"),
294        S("receiver_context", ("v8::Local<v8::Context> ${receiver_context} = "
295                               "${v8_receiver}->CreationContext();")),
296        S("receiver_script_state",
297          ("ScriptState* ${receiver_script_state} = "
298           "ScriptState::From(${receiver_context});")),
299    ])
300
301    is_receiver_context = not (
302        (cg_context.member_like and cg_context.member_like.is_static)
303        or cg_context.constructor)
304
305    # creation_context
306    pattern = "const v8::Local<v8::Context>& ${creation_context} = {_1};"
307    _1 = "${receiver_context}" if is_receiver_context else "${current_context}"
308    local_vars.append(S("creation_context", _format(pattern, _1=_1)))
309
310    # creation_context_object
311    text = ("${v8_receiver}"
312            if is_receiver_context else "${current_context}->Global()")
313    template_vars["creation_context_object"] = T(text)
314
315    # script_state
316    pattern = "ScriptState* ${script_state} = {_1};"
317    _1 = ("${receiver_script_state}"
318          if is_receiver_context else "${current_script_state}")
319    local_vars.append(S("script_state", _format(pattern, _1=_1)))
320
321    # execution_context
322    pattern = "ExecutionContext* ${execution_context} = {_1};"
323    _1 = ("${receiver_execution_context}"
324          if is_receiver_context else "${current_execution_context}")
325    local_vars.append(S("execution_context", _format(pattern, _1=_1)))
326    node = S("current_execution_context",
327             ("ExecutionContext* ${current_execution_context} = "
328              "ExecutionContext::From(${current_context});"))
329    node.accumulate(
330        CodeGenAccumulator.require_include_headers([
331            "third_party/blink/renderer/core/execution_context/execution_context.h"
332        ]))
333    local_vars.append(node)
334    node = S("receiver_execution_context",
335             ("ExecutionContext* ${receiver_execution_context} = "
336              "ExecutionContext::From(${receiver_context});"))
337    node.accumulate(
338        CodeGenAccumulator.require_include_headers([
339            "third_party/blink/renderer/core/execution_context/execution_context.h"
340        ]))
341    local_vars.append(node)
342
343    # execution_context_of_document_tree
344    pattern = "ExecutionContext* ${execution_context_of_document_tree} = {_1};"
345    if is_receiver_context:
346        _1 = "bindings::ExecutionContextFromV8Wrappable(${blink_receiver})"
347    else:
348        _1 = "${current_execution_context}"
349    text = _format(pattern, _1=_1)
350    local_vars.append(S("execution_context_of_document_tree", text))
351
352    # exception_state_context_type
353    pattern = (
354        "const ExceptionState::ContextType ${exception_state_context_type} = "
355        "{_1};")
356    if cg_context.attribute_get:
357        _1 = "ExceptionState::kGetterContext"
358    elif cg_context.attribute_set:
359        _1 = "ExceptionState::kSetterContext"
360    elif cg_context.constructor_group:
361        _1 = "ExceptionState::kConstructionContext"
362    elif cg_context.indexed_property_getter:
363        _1 = "ExceptionState::kIndexedGetterContext"
364    elif cg_context.indexed_property_setter:
365        _1 = "ExceptionState::kIndexedSetterContext"
366    elif cg_context.named_property_getter:
367        _1 = "ExceptionState::kNamedGetterContext"
368    elif cg_context.named_property_setter:
369        _1 = "ExceptionState::kNamedSetterContext"
370    elif cg_context.named_property_deleter:
371        _1 = "ExceptionState::kNamedDeletionContext"
372    else:
373        _1 = "ExceptionState::kExecutionContext"
374    local_vars.append(
375        S("exception_state_context_type", _format(pattern, _1=_1)))
376
377    # exception_state
378    pattern = "ExceptionState ${exception_state}({_1});{_2}"
379    _1 = ["${isolate}", "${exception_state_context_type}"]
380    if cg_context.is_named_constructor:
381        _1.append("\"{}\"".format(cg_context.property_.identifier))
382    else:
383        _1.append("${class_like_name}")
384    if (cg_context.property_ and cg_context.property_.identifier
385            and not cg_context.constructor_group):
386        _1.append("${property_name}")
387    _2 = ""
388    if cg_context.is_return_type_promise_type:
389        _2 = ("\n"
390              "ExceptionToRejectPromiseScope reject_promise_scope"
391              "(${info}, ${exception_state});")
392    local_vars.append(
393        S("exception_state", _format(pattern, _1=", ".join(_1), _2=_2)))
394
395    # blink_receiver
396    if cg_context.class_like.identifier == "Window":
397        # TODO(yukishiino): Window interface should be
398        # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow],
399        # and [CrossOrigin] properties should be implemented specifically with
400        # DOMWindow class.  Then, we'll have less hacks.
401        if (not cg_context.member_like or
402                "CrossOrigin" in cg_context.member_like.extended_attributes):
403            text = ("DOMWindow* ${blink_receiver} = "
404                    "${class_name}::ToWrappableUnsafe(${v8_receiver});")
405        else:
406            text = ("LocalDOMWindow* ${blink_receiver} = To<LocalDOMWindow>("
407                    "${class_name}::ToWrappableUnsafe(${v8_receiver}));")
408    else:
409        pattern = ("{_1}* ${blink_receiver} = "
410                   "${class_name}::ToWrappableUnsafe(${v8_receiver});")
411        _1 = blink_class_name(cg_context.class_like)
412        text = _format(pattern, _1=_1)
413    local_vars.append(S("blink_receiver", text))
414
415    # v8_property_value
416    if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK:
417        # In case of V8_ACCESSOR_NAME_SETTER_CALLBACK, |v8_property_value| is
418        # defined as an argument.  In case of V8_FUNCTION_CALLBACK (of IDL
419        # attribute set function), |info[0]| is the value to be set.
420        local_vars.append(
421            S("v8_property_value",
422              "v8::Local<v8::Value> ${v8_property_value} = ${info}[0];"))
423
424    # v8_receiver
425    if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK:
426        # In case of v8::FunctionCallbackInfo, This() is the receiver object.
427        local_vars.append(
428            S("v8_receiver",
429              "v8::Local<v8::Object> ${v8_receiver} = ${info}.This();"))
430    else:
431        # In case of v8::PropertyCallbackInfo, Holder() is the object that has
432        # the property being processed.
433        local_vars.append(
434            S("v8_receiver",
435              "v8::Local<v8::Object> ${v8_receiver} = ${info}.Holder();"))
436
437    # throw_security_error
438    template_vars["throw_security_error"] = T(
439        "BindingSecurity::FailedAccessCheckFor("
440        "${info}.GetIsolate(), "
441        "${class_name}::GetWrapperTypeInfo(), "
442        "${info}.Holder());")
443
444    code_node.register_code_symbols(local_vars)
445    code_node.add_template_vars(template_vars)
446
447
448def _make_reflect_content_attribute_key(code_node, cg_context):
449    assert isinstance(code_node, SymbolScopeNode)
450    assert isinstance(cg_context, CodeGenContext)
451
452    name = (cg_context.attribute.extended_attributes.value_of("Reflect")
453            or cg_context.attribute.identifier.lower())
454    if cg_context.attribute_get and name in ("class", "id", "name"):
455        return None
456
457    if cg_context.class_like.identifier.startswith("SVG"):
458        namespace = "svg_names"
459        code_node.accumulate(
460            CodeGenAccumulator.require_include_headers(
461                ["third_party/blink/renderer/core/svg_names.h"]))
462    else:
463        namespace = "html_names"
464        code_node.accumulate(
465            CodeGenAccumulator.require_include_headers(
466                ["third_party/blink/renderer/core/html_names.h"]))
467    return "{}::{}".format(namespace, name_style.constant(name, "attr"))
468
469
470def _make_reflect_accessor_func_name(cg_context):
471    assert isinstance(cg_context, CodeGenContext)
472    assert cg_context.attribute_get or cg_context.attribute_set
473
474    if cg_context.attribute_get:
475        name = (cg_context.attribute.extended_attributes.value_of("Reflect")
476                or cg_context.attribute.identifier.lower())
477        if name in ("class", "id", "name"):
478            return name_style.func("get", name, "attribute")
479
480        if "URL" in cg_context.attribute.extended_attributes:
481            return "GetURLAttribute"
482
483    FAST_ACCESSORS = {
484        "boolean": ("FastHasAttribute", "SetBooleanAttribute"),
485        "long": ("GetIntegralAttribute", "SetIntegralAttribute"),
486        "unsigned long": ("GetUnsignedIntegralAttribute",
487                          "SetUnsignedIntegralAttribute"),
488    }
489    idl_type = cg_context.attribute.idl_type.unwrap()
490    accessors = FAST_ACCESSORS.get(idl_type.keyword_typename)
491    if accessors:
492        return accessors[0 if cg_context.attribute_get else 1]
493
494    if (idl_type.is_interface
495            and idl_type.type_definition_object.does_implement("Element")):
496        if cg_context.attribute_get:
497            return "GetElementAttribute"
498        else:
499            return "SetElementAttribute"
500
501    if idl_type.element_type:
502        element_type = idl_type.element_type.unwrap()
503        if (element_type.is_interface and
504                element_type.type_definition_object.does_implement("Element")):
505            if cg_context.attribute_get:
506                return "GetElementArrayAttribute"
507            else:
508                return "SetElementArrayAttribute"
509
510    if cg_context.attribute_get:
511        return "FastGetAttribute"
512    else:
513        return "setAttribute"
514
515
516def _make_reflect_process_keyword_state(cg_context):
517    # https://html.spec.whatwg.org/C/#keywords-and-enumerated-attributes
518
519    assert isinstance(cg_context, CodeGenContext)
520    assert cg_context.attribute_get or cg_context.attribute_set
521
522    T = TextNode
523    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
524
525    if not cg_context.attribute_get:
526        return None
527
528    ext_attrs = cg_context.attribute.extended_attributes
529    keywords = ext_attrs.values_of("ReflectOnly")
530    missing_default = ext_attrs.value_of("ReflectMissing")
531    empty_default = ext_attrs.value_of("ReflectEmpty")
532    invalid_default = ext_attrs.value_of("ReflectInvalid")
533
534    def constant(keyword):
535        if not keyword:
536            return "g_empty_atom"
537        return "keywords::{}".format(name_style.constant(keyword))
538
539    branches = CxxMultiBranchesNode()
540    branches.accumulate(
541        CodeGenAccumulator.require_include_headers(
542            ["third_party/blink/renderer/core/keywords.h"]))
543    nodes = [
544        T("// [ReflectOnly]"),
545        T("const AtomicString reflect_value(${return_value}.LowerASCII());"),
546        branches,
547    ]
548
549    if missing_default is not None:
550        branches.append(
551            cond="reflect_value.IsNull()",
552            body=F("${return_value} = {};", constant(missing_default)))
553    elif cg_context.return_type.unwrap(nullable=False).is_nullable:
554        branches.append(
555            cond="reflect_value.IsNull()",
556            body=T("// Null string to IDL null."))
557
558    if empty_default is not None:
559        branches.append(
560            cond="reflect_value.IsEmpty()",
561            body=F("${return_value} = {};", constant(empty_default)))
562
563    expr = " || ".join(
564        map(lambda keyword: "reflect_value == {}".format(constant(keyword)),
565            keywords))
566    branches.append(cond=expr, body=T("${return_value} = reflect_value;"))
567
568    if invalid_default is not None:
569        branches.append(
570            cond=True,
571            body=F("${return_value} = {};", constant(invalid_default)))
572    else:
573        branches.append(
574            cond=True, body=F("${return_value} = {};", constant("")))
575
576    return SequenceNode(nodes)
577
578
579def _make_blink_api_call(code_node,
580                         cg_context,
581                         num_of_args=None,
582                         overriding_args=None):
583    assert isinstance(code_node, SymbolScopeNode)
584    assert isinstance(cg_context, CodeGenContext)
585    assert num_of_args is None or isinstance(num_of_args, (int, long))
586    assert (overriding_args is None
587            or (isinstance(overriding_args, (list, tuple))
588                and all(isinstance(arg, str) for arg in overriding_args)))
589
590    arguments = []
591    ext_attrs = cg_context.member_like.extended_attributes
592
593    values = ext_attrs.values_of("CallWith") + (
594        ext_attrs.values_of("GetterCallWith") if cg_context.attribute_get else
595        ext_attrs.values_of("SetterCallWith") if cg_context.attribute_set else
596        ())
597    if "Isolate" in values:
598        arguments.append("${isolate}")
599    if "ScriptState" in values:
600        arguments.append("${script_state}")
601    if "ExecutionContext" in values:
602        arguments.append("${execution_context}")
603    if "Document" in values:
604        arguments.append(
605            "*bindings::ToDocumentFromExecutionContext(${execution_context})")
606    if "ThisValue" in values:
607        arguments.append("ScriptValue(${isolate}, ${v8_receiver})")
608
609    code_generator_info = cg_context.member_like.code_generator_info
610    is_partial = code_generator_info.defined_in_partial
611    if (is_partial and
612            not (cg_context.constructor or cg_context.member_like.is_static)):
613        arguments.append("*${blink_receiver}")
614
615    if "Reflect" in ext_attrs:  # [Reflect]
616        key = _make_reflect_content_attribute_key(code_node, cg_context)
617        if key:
618            arguments.append(key)
619
620    if overriding_args is not None:
621        arguments.extend(overriding_args)
622    elif cg_context.attribute_get:
623        pass
624    elif cg_context.attribute_set:
625        arguments.append("${arg1_value}")
626    else:
627        for index, argument in enumerate(cg_context.function_like.arguments):
628            if num_of_args is not None and index == num_of_args:
629                break
630            name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier)
631            arguments.append(_format("${{{}}}", name))
632
633    if cg_context.is_return_by_argument:
634        arguments.append("${return_value}")
635
636    if cg_context.may_throw_exception:
637        arguments.append("${exception_state}")
638
639    func_name = backward_compatible_api_func(cg_context)
640    if cg_context.constructor:
641        if cg_context.is_named_constructor:
642            func_name = "CreateForJSConstructor"
643        else:
644            func_name = "Create"
645    if "Reflect" in ext_attrs:  # [Reflect]
646        func_name = _make_reflect_accessor_func_name(cg_context)
647
648    if (cg_context.constructor or cg_context.member_like.is_static
649            or is_partial):
650        class_like = cg_context.member_like.owner_mixin or cg_context.class_like
651        class_name = (code_generator_info.receiver_implemented_as
652                      or name_style.class_(class_like.identifier))
653        func_designator = "{}::{}".format(class_name, func_name)
654    else:
655        func_designator = _format("${blink_receiver}->{}", func_name)
656
657    return _format("{_1}({_2})", _1=func_designator, _2=", ".join(arguments))
658
659
660def bind_return_value(code_node, cg_context, overriding_args=None):
661    assert isinstance(code_node, SymbolScopeNode)
662    assert isinstance(cg_context, CodeGenContext)
663    assert (overriding_args is None
664            or (isinstance(overriding_args, (list, tuple))
665                and all(isinstance(arg, str) for arg in overriding_args)))
666
667    T = TextNode
668    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
669
670    def create_definition(symbol_node):
671        api_calls = []  # Pairs of (num_of_args, api_call_text)
672        if overriding_args is None:
673            arguments = (cg_context.function_like.arguments
674                         if cg_context.function_like else [])
675            for index, arg in enumerate(arguments):
676                if arg.is_optional and not arg.default_value:
677                    api_calls.append((index,
678                                      _make_blink_api_call(
679                                          code_node, cg_context, index)))
680            api_calls.append((None, _make_blink_api_call(
681                code_node, cg_context)))
682        else:
683            api_calls.append((None,
684                              _make_blink_api_call(
685                                  code_node,
686                                  cg_context,
687                                  overriding_args=overriding_args)))
688
689        nodes = []
690        is_return_type_void = ((not cg_context.return_type
691                                or cg_context.return_type.unwrap().is_void) and
692                               not cg_context.does_override_idl_return_type)
693        if not (is_return_type_void
694                or cg_context.does_override_idl_return_type):
695            return_type = blink_type_info(cg_context.return_type).value_t
696        if len(api_calls) == 1:
697            _, api_call = api_calls[0]
698            if is_return_type_void:
699                nodes.append(F("{};", api_call))
700            elif cg_context.is_return_by_argument:
701                nodes.append(F("{} ${return_value};", return_type))
702                nodes.append(F("{};", api_call))
703            elif "ReflectOnly" in cg_context.member_like.extended_attributes:
704                # [ReflectOnly]
705                nodes.append(F("auto ${return_value} = {};", api_call))
706            else:
707                nodes.append(F("auto&& ${return_value} = {};", api_call))
708        else:
709            branches = SequenceNode()
710            for index, api_call in api_calls:
711                if is_return_type_void or cg_context.is_return_by_argument:
712                    assignment = "{};".format(api_call)
713                else:
714                    assignment = _format("${return_value} = {};", api_call)
715                if index is not None:
716                    branches.append(
717                        CxxLikelyIfNode(
718                            cond=_format(
719                                "${non_undefined_argument_length} <= {}",
720                                index),
721                            body=[
722                                T(assignment),
723                                T("break;"),
724                            ]))
725                else:
726                    branches.append(T(assignment))
727
728            if not is_return_type_void:
729                nodes.append(F("{} ${return_value};", return_type))
730            nodes.append(CxxBreakableBlockNode(branches))
731
732        if cg_context.may_throw_exception:
733            nodes.append(
734                CxxUnlikelyIfNode(
735                    cond="${exception_state}.HadException()",
736                    body=T("return;")))
737
738        if "ReflectOnly" in cg_context.member_like.extended_attributes:
739            # [ReflectOnly]
740            node = _make_reflect_process_keyword_state(cg_context)
741            if node:
742                nodes.append(EmptyNode())
743                nodes.append(node)
744
745        return SymbolDefinitionNode(symbol_node, nodes)
746
747    code_node.register_code_symbol(
748        SymbolNode("return_value", definition_constructor=create_definition))
749
750
751def make_bindings_trace_event(cg_context):
752    assert isinstance(cg_context, CodeGenContext)
753
754    event_name = "{}.{}".format(cg_context.class_like.identifier,
755                                cg_context.property_.identifier)
756    if cg_context.attribute_get:
757        event_name = "{}.{}".format(event_name, "get")
758    elif cg_context.attribute_set:
759        event_name = "{}.{}".format(event_name, "set")
760    elif cg_context.constructor_group and not cg_context.is_named_constructor:
761        event_name = "{}.{}".format(cg_context.class_like.identifier,
762                                    "constructor")
763
764    return TextNode("BLINK_BINDINGS_TRACE_EVENT(\"{}\");".format(event_name))
765
766
767def make_check_argument_length(cg_context):
768    assert isinstance(cg_context, CodeGenContext)
769
770    T = TextNode
771    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
772
773    if cg_context.v8_callback_type != CodeGenContext.V8_FUNCTION_CALLBACK:
774        return None
775
776    if cg_context.attribute_get:
777        num_of_required_args = 0
778    elif cg_context.attribute_set:
779        idl_type = cg_context.attribute.idl_type
780        if not (idl_type.does_include_nullable_or_dict
781                or idl_type.unwrap().is_any or "LegacyTreatNonObjectAsNull" in
782                idl_type.unwrap().extended_attributes
783                or "PutForwards" in cg_context.attribute.extended_attributes
784                or "Replaceable" in cg_context.attribute.extended_attributes):
785            # ES undefined in ${v8_property_value} will cause a TypeError
786            # anyway, so omit the check against the number of arguments.
787            return None
788        num_of_required_args = 1
789    elif cg_context.function_like:
790        num_of_required_args = (
791            cg_context.function_like.num_of_required_arguments)
792    elif isinstance(cg_context.property_, web_idl.OverloadGroup):
793        num_of_required_args = (
794            cg_context.property_.min_num_of_required_arguments)
795    else:
796        assert False
797
798    if num_of_required_args == 0:
799        return None
800
801    return CxxUnlikelyIfNode(
802        cond=_format("UNLIKELY(${info}.Length() < {})", num_of_required_args),
803        body=[
804            F(("${exception_state}.ThrowTypeError("
805               "ExceptionMessages::NotEnoughArguments"
806               "({}, ${info}.Length()));"), num_of_required_args),
807            T("return;"),
808        ])
809
810
811def make_check_constructor_call(cg_context):
812    assert isinstance(cg_context, CodeGenContext)
813
814    T = TextNode
815
816    node = SequenceNode([
817        CxxUnlikelyIfNode(
818            cond="!${info}.IsConstructCall()",
819            body=T("${exception_state}.ThrowTypeError("
820                   "ExceptionMessages::ConstructorCalledAsFunction());\n"
821                   "return;")),
822    ])
823    if not cg_context.is_named_constructor:
824        node.append(
825            CxxLikelyIfNode(
826                cond=("ConstructorMode::Current(${isolate}) == "
827                      "ConstructorMode::kWrapExistingObject"),
828                body=T("bindings::V8SetReturnValue(${info}, ${v8_receiver});\n"
829                       "return;")))
830    node.accumulate(
831        CodeGenAccumulator.require_include_headers([
832            "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
833        ]))
834    return node
835
836
837def make_check_receiver(cg_context):
838    assert isinstance(cg_context, CodeGenContext)
839
840    T = TextNode
841
842    if cg_context.member_like.is_static:
843        return None
844
845    if (cg_context.attribute and
846            "LegacyLenientThis" in cg_context.attribute.extended_attributes):
847        return SequenceNode([
848            T("// [LegacyLenientThis]"),
849            CxxUnlikelyIfNode(
850                cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})",
851                body=T("return;")),
852        ])
853
854    if cg_context.is_return_type_promise_type:
855        return SequenceNode([
856            T("// Promise returning function: "
857              "Convert a TypeError to a reject promise."),
858            CxxUnlikelyIfNode(
859                cond="!${class_name}::HasInstance(${isolate}, ${v8_receiver})",
860                body=[
861                    T("${exception_state}.ThrowTypeError("
862                      "\"Illegal invocation\");"),
863                    T("return;"),
864                ])
865        ])
866
867    return None
868
869
870def make_check_security_of_return_value(cg_context):
871    assert isinstance(cg_context, CodeGenContext)
872
873    T = TextNode
874
875    check_security = cg_context.member_like.extended_attributes.value_of(
876        "CheckSecurity")
877    if check_security != "ReturnValue":
878        return None
879
880    web_feature = _format(
881        "WebFeature::{}",
882        name_style.constant("CrossOrigin", cg_context.class_like.identifier,
883                            cg_context.property_.identifier))
884    use_counter = _format(
885        "UseCounter::Count(${current_execution_context}, {});", web_feature)
886    cond = T("!BindingSecurity::ShouldAllowAccessTo("
887             "ToLocalDOMWindow(${current_context}), ${return_value}, "
888             "BindingSecurity::ErrorReportOption::kDoNotReport)")
889    body = [
890        T(use_counter),
891        T("bindings::V8SetReturnValue(${info}, nullptr);\n"
892          "return;"),
893    ]
894    node = SequenceNode([
895        T("// [CheckSecurity=ReturnValue]"),
896        CxxUnlikelyIfNode(cond=cond, body=body),
897    ])
898    node.accumulate(
899        CodeGenAccumulator.require_include_headers([
900            "third_party/blink/renderer/bindings/core/v8/binding_security.h",
901            "third_party/blink/renderer/core/frame/web_feature.h",
902            "third_party/blink/renderer/platform/instrumentation/use_counter.h",
903        ]))
904    return node
905
906
907def make_cooperative_scheduling_safepoint(cg_context):
908    assert isinstance(cg_context, CodeGenContext)
909
910    node = TextNode("scheduler::CooperativeSchedulingManager::Instance()"
911                    "->Safepoint();")
912    node.accumulate(
913        CodeGenAccumulator.require_include_headers([
914            "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h"
915        ]))
916    return node
917
918
919def make_log_activity(cg_context):
920    assert isinstance(cg_context, CodeGenContext)
921
922    target = cg_context.member_like or cg_context.property_
923    ext_attrs = target.extended_attributes
924    if "LogActivity" not in ext_attrs:
925        return None
926    target = ext_attrs.value_of("LogActivity")
927    if target:
928        assert target in ("GetterOnly", "SetterOnly")
929        if ((target == "GetterOnly" and not cg_context.attribute_get)
930                or (target == "SetterOnly" and not cg_context.attribute_set)):
931            return None
932    if (cg_context.for_world == cg_context.MAIN_WORLD
933            and "LogAllWorlds" not in ext_attrs):
934        return None
935
936    pattern = "{_1}${per_context_data} && ${per_context_data}->ActivityLogger()"
937    _1 = ""
938    if (cg_context.attribute and "PerWorldBindings" not in ext_attrs
939            and "LogAllWorlds" not in ext_attrs):
940        _1 = "${script_state}->World().IsIsolatedWorld() && "
941    cond = _format(pattern, _1=_1)
942
943    pattern = "${per_context_data}->ActivityLogger()->{_1}(\"{_2}.{_3}\"{_4});"
944    _2 = cg_context.class_like.identifier
945    _3 = cg_context.property_.identifier
946    if cg_context.attribute_get:
947        _1 = "LogGetter"
948        _4 = ""
949    elif cg_context.attribute_set:
950        _1 = "LogSetter"
951        _4 = ", ${v8_property_value}"
952    elif cg_context.operation_group:
953        _1 = "LogMethod"
954        _4 = ", ${info}"
955    body = _format(pattern, _1=_1, _2=_2, _3=_3, _4=_4)
956
957    pattern = ("// [LogActivity], [LogAllWorlds]\n" "if ({_1}) {{ {_2} }}")
958    node = TextNode(_format(pattern, _1=cond, _2=body))
959    node.accumulate(
960        CodeGenAccumulator.require_include_headers([
961            "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h",
962            "third_party/blink/renderer/platform/bindings/v8_per_context_data.h",
963        ]))
964    return node
965
966
967def _make_overload_dispatcher_per_arg_size(cg_context, items):
968    """
969    https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
970
971    Args:
972        items: Partial list of an "effective overload set" with the same
973            type list size.
974
975    Returns:
976        A pair of a resulting CodeNode and a boolean flag that is True if there
977        exists a case that overload resolution will fail, i.e. a bailout that
978        throws a TypeError is necessary.
979    """
980    assert isinstance(cg_context, CodeGenContext)
981    assert isinstance(items, (list, tuple))
982    assert all(
983        isinstance(item, web_idl.OverloadGroup.EffectiveOverloadItem)
984        for item in items)
985
986    # Variables shared with nested functions
987    if len(items) > 1:
988        arg_index = web_idl.OverloadGroup.distinguishing_argument_index(items)
989    else:
990        arg_index = None
991    func_like = None
992    dispatcher_nodes = SequenceNode()
993
994    # True if there exists a case that overload resolution will fail.
995    can_fail = True
996
997    def find_test(item, test):
998        # |test| is a callable that takes (t, u) where:
999        #   t = the idl_type (in the original form)
1000        #   u = the unwrapped version of t
1001        idl_type = item.type_list[arg_index]
1002        t = idl_type
1003        u = idl_type.unwrap()
1004        return test(t, u) or (u.is_union and any(
1005            [test(m, m.unwrap()) for m in u.flattened_member_types]))
1006
1007    def find(test):
1008        for item in items:
1009            if find_test(item, test):
1010                return item.function_like
1011        return None
1012
1013    def find_all_interfaces():
1014        result = []  # [(func_like, idl_type), ...]
1015        for item in items:
1016            idl_type = item.type_list[arg_index].unwrap()
1017            if idl_type.is_interface:
1018                result.append((item.function_like, idl_type))
1019            if idl_type.is_union:
1020                for member_type in idl_type.flattened_member_types:
1021                    if member_type.unwrap().is_interface:
1022                        result.append((item.function_like,
1023                                       member_type.unwrap()))
1024        return result
1025
1026    def make_node(pattern):
1027        value = _format("${info}[{}]", arg_index)
1028        func_name = callback_function_name(cg_context,
1029                                           func_like.overload_index)
1030        return TextNode(_format(pattern, value=value, func_name=func_name))
1031
1032    def dispatch_if(expr):
1033        if expr is True:
1034            pattern = "return {func_name}(${info});"
1035        else:
1036            pattern = ("if (" + expr + ") {{\n"
1037                       "  return {func_name}(${info});\n"
1038                       "}}")
1039        node = make_node(pattern)
1040        conditional = expr_from_exposure(func_like.exposure)
1041        if not conditional.is_always_true:
1042            node = CxxUnlikelyIfNode(cond=conditional, body=node)
1043        dispatcher_nodes.append(node)
1044        return expr is True and conditional.is_always_true
1045
1046    if len(items) == 1:
1047        func_like = items[0].function_like
1048        can_fail = False
1049        return make_node("return {func_name}(${info});"), can_fail
1050
1051    # 12.2. If V is undefined, ...
1052    func_like = find(lambda t, u: t.is_optional)
1053    if func_like:
1054        dispatch_if("{value}->IsUndefined()")
1055
1056    # 12.3. if V is null or undefined, ...
1057    func_like = find(lambda t, u: t.does_include_nullable_or_dict)
1058    if func_like:
1059        dispatch_if("{value}->IsNullOrUndefined()")
1060
1061    # 12.4. if V is a platform object, ...
1062    def inheritance_length(func_and_type):
1063        return len(func_and_type[1].type_definition_object.
1064                   inclusive_inherited_interfaces)
1065
1066    # Attempt to match from most derived to least derived.
1067    for func_like, idl_type in sorted(
1068            find_all_interfaces(), key=inheritance_length, reverse=True):
1069        v8_bridge_name = v8_bridge_class_name(
1070            idl_type.unwrap().type_definition_object)
1071        dispatch_if(
1072            _format("{}::HasInstance(${isolate}, {value})", v8_bridge_name))
1073
1074    # V8 specific optimization: BufferSource = ArrayBufferView or ArrayBuffer
1075    is_typedef_name = lambda t, name: t.is_typedef and t.identifier == name
1076    func_like = find(
1077        lambda t, u: is_typedef_name(t.unwrap(typedef=False), "BufferSource"))
1078    if func_like:
1079        dispatch_if("{value}->IsArrayBufferView() || "
1080                    "{value}->IsArrayBuffer() || "
1081                    "{value}->IsSharedArrayBuffer()")
1082    else:
1083        # 12.5. if Type(V) is Object, V has an [[ArrayBufferData]] internal
1084        #   slot, ...
1085        func_like = find(lambda t, u: u.is_array_buffer)
1086        if func_like:
1087            dispatch_if("{value}->IsArrayBuffer() || "
1088                        "{value}->IsSharedArrayBuffer()")
1089
1090        # V8 specific optimization: ArrayBufferView
1091        func_like = find(lambda t, u: u.is_array_buffer_view)
1092        if func_like:
1093            dispatch_if("{value}->IsArrayBufferView()")
1094
1095    # 12.6. if Type(V) is Object, V has a [[DataView]] internal slot, ...
1096    func_like = find(lambda t, u: u.is_data_view)
1097    if func_like:
1098        dispatch_if("{value}->IsDataView()")
1099
1100    # 12.7. if Type(V) is Object, V has a [[TypedArrayName]] internal slot, ...
1101    typed_array_types = ("Int8Array", "Int16Array", "Int32Array", "Uint8Array",
1102                         "Uint16Array", "Uint32Array", "Uint8ClampedArray",
1103                         "Float32Array", "Float64Array")
1104    for typed_array_type in typed_array_types:
1105        func_like = find(lambda t, u: u.keyword_typename == typed_array_type)
1106        if func_like:
1107            dispatch_if(_format("{value}->Is{}()", typed_array_type))
1108
1109    # 12.8. if IsCallable(V) is true, ...
1110    func_like = find(lambda t, u: u.is_callback_function)
1111    if func_like:
1112        dispatch_if("{value}->IsFunction()")
1113
1114    # 12.9. if Type(V) is Object and ... @@iterator ...
1115    func_like = find(lambda t, u: u.is_sequence or u.is_frozen_array)
1116    if func_like:
1117        dispatch_if("{value}->IsArray() || "  # Excessive optimization
1118                    "bindings::IsEsIterableObject"
1119                    "(${isolate}, {value}, ${exception_state})")
1120        dispatcher_nodes.append(
1121            TextNode("if (${exception_state}.HadException()) {\n"
1122                     "  return;\n"
1123                     "}"))
1124
1125    # 12.10. if Type(V) is Object and ...
1126    def is_es_object_type(t, u):
1127        return (u.is_callback_interface or u.is_dictionary or u.is_record
1128                or u.is_object)
1129
1130    func_like = find(is_es_object_type)
1131    if func_like:
1132        dispatch_if("{value}->IsObject()")
1133
1134    # 12.11. if Type(V) is Boolean and ...
1135    func_like = find(lambda t, u: u.is_boolean)
1136    if func_like:
1137        dispatch_if("{value}->IsBoolean()")
1138
1139    # 12.12. if Type(V) is Number and ...
1140    func_like = find(lambda t, u: u.is_numeric)
1141    if func_like:
1142        dispatch_if("{value}->IsNumber()")
1143
1144    # 12.13. if there is an entry in S that has ... a string type ...
1145    # 12.14. if there is an entry in S that has ... a numeric type ...
1146    # 12.15. if there is an entry in S that has ... boolean ...
1147    # 12.16. if there is an entry in S that has any ...
1148    func_likes = [
1149        find(lambda t, u: u.is_enumeration),
1150        find(lambda t, u: u.is_string),
1151        find(lambda t, u: u.is_numeric),
1152        find(lambda t, u: u.is_boolean),
1153        find(lambda t, u: u.is_any),
1154    ]
1155    for func_like in func_likes:
1156        if func_like:
1157            if dispatch_if(True):
1158                can_fail = False
1159                break
1160
1161    return dispatcher_nodes, can_fail
1162
1163
1164def make_overload_dispatcher(cg_context):
1165    # https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
1166
1167    assert isinstance(cg_context, CodeGenContext)
1168
1169    T = TextNode
1170    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
1171
1172    overload_group = cg_context.property_
1173    items = overload_group.effective_overload_set()
1174    args_size = lambda item: len(item.type_list)
1175    items_grouped_by_arg_size = itertools.groupby(
1176        sorted(items, key=args_size, reverse=True), key=args_size)
1177
1178    # TODO(yukishiino): Runtime-enabled features should be taken into account
1179    # when calculating the max argument size.
1180    max_arg_size = max(map(args_size, items))
1181    arg_count_def = F("const int arg_count = std::min(${info}.Length(), {});",
1182                      max_arg_size)
1183
1184    branches = SequenceNode()
1185    did_use_break = False
1186    for arg_size, items in items_grouped_by_arg_size:
1187        items = list(items)
1188
1189        node, can_fail = _make_overload_dispatcher_per_arg_size(
1190            cg_context, items)
1191
1192        if arg_size > 0:
1193            node = CxxLikelyIfNode(
1194                cond="arg_count == {}".format(arg_size),
1195                body=[node, T("break;") if can_fail else None])
1196            did_use_break = did_use_break or can_fail
1197
1198        conditional = expr_or(
1199            map(lambda item: expr_from_exposure(item.function_like.exposure),
1200                items))
1201        if not conditional.is_always_true:
1202            node = CxxUnlikelyIfNode(cond=conditional, body=node)
1203
1204        branches.append(node)
1205
1206    if did_use_break:
1207        branches = CxxBreakableBlockNode(branches)
1208    branches = SequenceNode([
1209        arg_count_def,
1210        branches,
1211    ])
1212
1213    if not did_use_break and arg_size == 0 and conditional.is_always_true:
1214        return branches
1215
1216    return SequenceNode([
1217        branches,
1218        EmptyNode(),
1219        make_check_argument_length(cg_context),
1220        T("${exception_state}.ThrowTypeError"
1221          "(\"Overload resolution failed.\");\n"
1222          "return;"),
1223    ])
1224
1225
1226def make_report_coop_access(cg_context):
1227    assert isinstance(cg_context, CodeGenContext)
1228
1229    if cg_context.class_like.identifier != "Window":
1230        return None
1231
1232    ext_attrs = cg_context.member_like.extended_attributes
1233    if "CrossOrigin" not in ext_attrs:
1234        return None
1235
1236    values = ext_attrs.values_of("CrossOrigin")
1237    if (cg_context.attribute_get and not (not values or "Getter" in values)):
1238        return None
1239    elif (cg_context.attribute_set and not ("Setter" in values)):
1240        return None
1241
1242    return TextNode("${blink_receiver}->ReportCoopAccess(${property_name});")
1243
1244
1245def make_report_deprecate_as(cg_context):
1246    assert isinstance(cg_context, CodeGenContext)
1247
1248    target = cg_context.member_like or cg_context.property_
1249    name = target.extended_attributes.value_of("DeprecateAs")
1250    if not name:
1251        return None
1252
1253    pattern = ("// [DeprecateAs]\n"
1254               "Deprecation::CountDeprecation("
1255               "${current_execution_context}, WebFeature::k{_1});")
1256    _1 = name
1257    node = TextNode(_format(pattern, _1=_1))
1258    node.accumulate(
1259        CodeGenAccumulator.require_include_headers(
1260            ["third_party/blink/renderer/core/frame/deprecation.h"]))
1261    return node
1262
1263
1264def _make_measure_web_feature_constant(cg_context):
1265    assert isinstance(cg_context, CodeGenContext)
1266
1267    target = cg_context.member_like or cg_context.property_
1268    ext_attrs = target.extended_attributes
1269
1270    suffix = ""
1271    if cg_context.attribute_get:
1272        suffix = "_AttributeGetter"
1273    elif cg_context.attribute_set:
1274        suffix = "_AttributeSetter"
1275    elif cg_context.constructor:
1276        suffix = "_Constructor"
1277    elif cg_context.exposed_construct:
1278        suffix = "_ConstructorGetter"
1279    elif cg_context.operation:
1280        suffix = "_Method"
1281
1282    name = ext_attrs.value_of("MeasureAs") or ext_attrs.value_of("Measure")
1283    if name:
1284        name = "k{}".format(name)
1285    elif cg_context.constructor:
1286        name = "kV8{}{}".format(cg_context.class_like.identifier, suffix)
1287    else:
1288        name = "kV8{}_{}{}".format(
1289            cg_context.class_like.identifier,
1290            name_style.raw.upper_camel_case(cg_context.property_.identifier),
1291            suffix)
1292
1293    return "WebFeature::{}".format(name)
1294
1295
1296def make_report_high_entropy(cg_context):
1297    assert isinstance(cg_context, CodeGenContext)
1298
1299    target = cg_context.member_like or cg_context.property_
1300    ext_attrs = target.extended_attributes
1301    if cg_context.attribute_set or "HighEntropy" not in ext_attrs:
1302        return None
1303    assert "Measure" in ext_attrs or "MeasureAs" in ext_attrs, "{}: {}".format(
1304        cg_context.idl_location_and_name,
1305        "[HighEntropy] must be specified with either [Measure] or "
1306        "[MeasureAs].")
1307
1308    if ext_attrs.value_of("HighEntropy") == "Direct":
1309        text = _format(
1310            "// [HighEntropy=Direct]\n"
1311            "Dactyloscoper::RecordDirectSurface("
1312            "${current_execution_context}, {measure_constant}, "
1313            "${return_value});",
1314            measure_constant=_make_measure_web_feature_constant(cg_context))
1315    else:
1316        text = _format(
1317            "// [HighEntropy]\n"
1318            "Dactyloscoper::Record("
1319            "${current_execution_context}, {measure_constant});",
1320            measure_constant=_make_measure_web_feature_constant(cg_context))
1321    node = TextNode(text)
1322    node.accumulate(
1323        CodeGenAccumulator.require_include_headers(
1324            ["third_party/blink/renderer/core/frame/dactyloscoper.h"]))
1325    return node
1326
1327
1328def make_report_measure_as(cg_context):
1329    assert isinstance(cg_context, CodeGenContext)
1330
1331    target = cg_context.member_like or cg_context.property_
1332    ext_attrs = target.extended_attributes
1333    if not ("Measure" in ext_attrs or "MeasureAs" in ext_attrs):
1334        return None
1335
1336    text = _format(
1337        "// [Measure], [MeasureAs]\n"
1338        "UseCounter::Count(${current_execution_context}, {measure_constant});",
1339        measure_constant=_make_measure_web_feature_constant(cg_context))
1340    node = TextNode(text)
1341    node.accumulate(
1342        CodeGenAccumulator.require_include_headers([
1343            "third_party/blink/renderer/core/frame/web_feature.h",
1344            "third_party/blink/renderer/platform/instrumentation/use_counter.h",
1345        ]))
1346    return node
1347
1348
1349def make_return_value_cache_return_early(cg_context):
1350    assert isinstance(cg_context, CodeGenContext)
1351
1352    pred = cg_context.member_like.extended_attributes.value_of(
1353        "CachedAttribute")
1354    if pred:
1355        return TextNode("""\
1356// [CachedAttribute]
1357static const V8PrivateProperty::SymbolKey kPrivatePropertyCachedAttribute;
1358auto&& v8_private_cached_attribute =
1359    V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyCachedAttribute);
1360if (!${blink_receiver}->""" + pred + """()) {
1361  v8::Local<v8::Value> v8_value;
1362  if (!v8_private_cached_attribute.GetOrUndefined(${v8_receiver})
1363           .ToLocal(&v8_value)) {
1364    return;
1365  }
1366  if (!v8_value->IsUndefined()) {
1367    bindings::V8SetReturnValue(${info}, v8_value);
1368    return;
1369  }
1370}""")
1371
1372    if "SaveSameObject" in cg_context.member_like.extended_attributes:
1373        return TextNode("""\
1374// [SaveSameObject]
1375static const V8PrivateProperty::SymbolKey kPrivatePropertySaveSameObject;
1376auto&& v8_private_save_same_object =
1377    V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertySaveSameObject);
1378{
1379  v8::Local<v8::Value> v8_value;
1380  if (!v8_private_save_same_object.GetOrUndefined(${v8_receiver})
1381           .ToLocal(&v8_value)) {
1382    return;
1383  }
1384  if (!v8_value->IsUndefined()) {
1385    bindings::V8SetReturnValue(${info}, v8_value);
1386    return;
1387  }
1388}""")
1389
1390
1391def make_return_value_cache_update_value(cg_context):
1392    assert isinstance(cg_context, CodeGenContext)
1393
1394    if "CachedAttribute" in cg_context.member_like.extended_attributes:
1395        return TextNode("// [CachedAttribute]\n"
1396                        "v8_private_cached_attribute.Set"
1397                        "(${v8_receiver}, ${info}.GetReturnValue().Get());")
1398
1399    if "SaveSameObject" in cg_context.member_like.extended_attributes:
1400        return TextNode("// [SaveSameObject]\n"
1401                        "v8_private_save_same_object.Set"
1402                        "(${v8_receiver}, ${info}.GetReturnValue().Get());")
1403
1404
1405def make_runtime_call_timer_scope(cg_context, overriding_name=None):
1406    assert isinstance(cg_context, CodeGenContext)
1407    assert _is_none_or_str(overriding_name)
1408
1409    target = cg_context.member_like or cg_context.property_
1410
1411    suffix = ""
1412    if cg_context.attribute_get:
1413        suffix = "_Getter"
1414    elif cg_context.attribute_set:
1415        suffix = "_Setter"
1416    elif cg_context.exposed_construct:
1417        suffix = "_ConstructorGetterCallback"
1418
1419    counter = (target and
1420               target.extended_attributes.value_of("RuntimeCallStatsCounter"))
1421    if counter:
1422        macro_name = "RUNTIME_CALL_TIMER_SCOPE"
1423        counter_name = "RuntimeCallStats::CounterId::k{}{}".format(
1424            counter, suffix)
1425    else:
1426        macro_name = "RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT"
1427        counter_name = "\"Blink_{}_{}{}\"".format(
1428            blink_class_name(cg_context.class_like), overriding_name
1429            or target.identifier, suffix)
1430
1431    return TextNode(
1432        _format(
1433            "{macro_name}(${info}.GetIsolate(), {counter_name});",
1434            macro_name=macro_name,
1435            counter_name=counter_name))
1436
1437
1438def make_steps_of_ce_reactions(cg_context):
1439    assert isinstance(cg_context, CodeGenContext)
1440    assert (cg_context.attribute_set or cg_context.operation
1441            or cg_context.indexed_property_setter
1442            or cg_context.named_property_setter
1443            or cg_context.named_property_deleter)
1444
1445    T = TextNode
1446
1447    nodes = []
1448
1449    ext_attrs = cg_context.member_like.extended_attributes
1450    if "CustomElementCallbacks" in ext_attrs or "Reflect" in ext_attrs:
1451        if "CustomElementCallbacks" in ext_attrs:
1452            nodes.append(T("// [CustomElementCallbacks]"))
1453        elif "Reflect" in ext_attrs:
1454            nodes.append(T("// [Reflect]"))
1455        nodes.append(
1456            T("V0CustomElementProcessingStack::CallbackDeliveryScope "
1457              "v0_custom_element_scope;"))
1458        nodes[-1].accumulate(
1459            CodeGenAccumulator.require_include_headers([
1460                "third_party/blink/renderer/core/html/custom/v0_custom_element_processing_stack.h"
1461            ]))
1462
1463    if "CEReactions" in ext_attrs:
1464        nodes.append(T("// [CEReactions]"))
1465        nodes.append(T("CEReactionsScope ce_reactions_scope;"))
1466        nodes[-1].accumulate(
1467            CodeGenAccumulator.require_include_headers([
1468                "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
1469            ]))
1470
1471    if not nodes:
1472        return None
1473
1474    # CEReactions scope is not tolerant of V8 exception, so it's necessary to
1475    # invoke custom element reactions before throwing an exception.  Thus, put
1476    # an ExceptionState before CEReactions scope.
1477    nodes.insert(0, WeakDependencyNode(dep_syms=["exception_state"]))
1478
1479    return SequenceNode(nodes)
1480
1481
1482def make_steps_of_put_forwards(cg_context):
1483    assert isinstance(cg_context, CodeGenContext)
1484
1485    T = TextNode
1486
1487    return SequenceNode([
1488        T("// [PutForwards]"),
1489        T("v8::Local<v8::Value> target;"),
1490        T("if (!${v8_receiver}->Get(${current_context}, "
1491          "V8AtomicString(${isolate}, ${property_name}))"
1492          ".ToLocal(&target)) {\n"
1493          "  return;\n"
1494          "}"),
1495        CxxUnlikelyIfNode(
1496            cond="!target->IsObject()",
1497            body=[
1498                T("${exception_state}.ThrowTypeError("
1499                  "\"The attribute value is not an object\");"),
1500                T("return;"),
1501            ]),
1502        T("bool did_set;"),
1503        T("if (!target.As<v8::Object>()->Set(${current_context}, "
1504          "V8AtomicString(${isolate}, "
1505          "\"${attribute.extended_attributes.value_of(\"PutForwards\")}\""
1506          "), ${v8_property_value}).To(&did_set)) {{\n"
1507          "  return;\n"
1508          "}}"),
1509    ])
1510
1511
1512def make_steps_of_replaceable(cg_context):
1513    assert isinstance(cg_context, CodeGenContext)
1514
1515    T = TextNode
1516
1517    return SequenceNode([
1518        T("// [Replaceable]"),
1519        T("bool did_create;"),
1520        T("if (!${v8_receiver}->CreateDataProperty(${current_context}, "
1521          "V8AtomicString(${isolate}, ${property_name}), "
1522          "${v8_property_value}).To(&did_create)) {\n"
1523          "  return;\n"
1524          "}"),
1525    ])
1526
1527
1528def make_v8_set_return_value(cg_context):
1529    assert isinstance(cg_context, CodeGenContext)
1530
1531    T = TextNode
1532    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
1533
1534    if cg_context.does_override_idl_return_type:
1535        return T("bindings::V8SetReturnValue(${info}, ${return_value});")
1536
1537    if not cg_context.return_type or cg_context.return_type.unwrap().is_void:
1538        # Request a SymbolNode |return_value| to define itself without
1539        # rendering any text.
1540        return T("<% return_value.request_symbol_definition() %>")
1541
1542    operation = cg_context.operation
1543    if operation and (operation.is_setter or operation.is_deleter):
1544        # Blink implementation returns in a type different from the IDL type.
1545        # Namely, IndexedPropertySetterResult, NamedPropertySetterResult, and
1546        # NamedPropertyDeleterResult are returned ignoring the operation's
1547        # return type.
1548        return T("bindings::V8SetReturnValue(${info}, ${return_value});")
1549
1550    return_type = cg_context.return_type
1551    if return_type.is_typedef:
1552        if return_type.identifier in ("EventHandler",
1553                                      "OnBeforeUnloadEventHandler",
1554                                      "OnErrorEventHandler"):
1555            return T("bindings::V8SetReturnValue(${info}, ${return_value}, "
1556                     "${isolate}, ${blink_receiver});")
1557
1558    # [CheckSecurity=ReturnValue]
1559    #
1560    # The returned object must be wrapped in its own realm instead of the
1561    # receiver object's relevant realm or the current realm.
1562    #
1563    # [CheckSecurity=ReturnValue] is used only for 'contentDocument' attribute
1564    # and 'getSVGDocument' operation of HTML{IFrame,Frame,Object,Embed}Element
1565    # interfaces, and Window.frameElement attribute, so far.
1566    #
1567    # All the interfaces above except for Window support 'contentWindow'
1568    # attribute and that's the global object of the creation context of the
1569    # returned V8 wrapper.  Window.frameElement is implemented with [Custom]
1570    # for now and there is no need to support it.
1571    #
1572    # Note that the global object has its own context and there is no need to
1573    # pass the creation context to ToV8.
1574    if (cg_context.member_like.extended_attributes.value_of("CheckSecurity") ==
1575            "ReturnValue"):
1576        return T("""\
1577// [CheckSecurity=ReturnValue]
1578bindings::V8SetReturnValue(
1579    ${info},
1580    ToV8(${return_value},
1581         ToV8(${blink_receiver}->contentWindow(),
1582              v8::Local<v8::Object>(),
1583              ${isolate}).As<v8::Object>(),
1584         ${isolate}));\
1585""")
1586
1587    return_type = return_type.unwrap(typedef=True)
1588    return_type_body = return_type.unwrap()
1589
1590    PRIMITIVE_TYPE_TO_CXX_TYPE = {
1591        "boolean": "bool",
1592        "byte": "int8_t",
1593        "octet": "uint8_t",
1594        "short": "int16_t",
1595        "unsigned short": "uint16_t",
1596        "long": "int32_t",
1597        "unsigned long": "uint32_t",
1598        "long long": "int64_t",
1599        "unsigned long long": "uint64_t",
1600        "float": "float",
1601        "unrestricted float": "float",
1602        "double": "double",
1603        "unrestricted double": "double",
1604    }
1605    cxx_type = PRIMITIVE_TYPE_TO_CXX_TYPE.get(
1606        return_type_body.keyword_typename)
1607    if cxx_type:
1608        return F(
1609            "bindings::V8SetReturnValue(${info}, ${return_value}, "
1610            "bindings::V8ReturnValue::PrimitiveType<{cxx_type}>());",
1611            cxx_type=cxx_type)
1612
1613    # TODO(yukishiino): Remove |return_type_body.is_enumeration| below once
1614    # the migration from String to V8Enum type is done.
1615    if return_type_body.is_string or return_type_body.is_enumeration:
1616        args = ["${info}", "${return_value}", "${isolate}"]
1617        if return_type.is_nullable:
1618            args.append("bindings::V8ReturnValue::kNullable")
1619        else:
1620            args.append("bindings::V8ReturnValue::kNonNullable")
1621        return T("bindings::V8SetReturnValue({});".format(", ".join(args)))
1622
1623    if return_type_body.is_interface:
1624        args = ["${info}", "${return_value}"]
1625        if cg_context.for_world == cg_context.MAIN_WORLD:
1626            args.append("bindings::V8ReturnValue::kMainWorld")
1627        elif cg_context.constructor or cg_context.member_like.is_static:
1628            args.append("${creation_context}")
1629        else:
1630            args.append("${blink_receiver}")
1631        return T("bindings::V8SetReturnValue({});".format(", ".join(args)))
1632
1633    if return_type.is_frozen_array:
1634        return T(
1635            "bindings::V8SetReturnValue("
1636            "${info}, "
1637            "ToV8(${return_value}, ${creation_context_object}, ${isolate}), "
1638            "bindings::V8ReturnValue::kFrozen);")
1639
1640    if return_type.is_promise:
1641        return T("bindings::V8SetReturnValue"
1642                 "(${info}, ${return_value}.V8Value());")
1643
1644    return T("bindings::V8SetReturnValue(${info}, "
1645             "ToV8(${return_value}, ${creation_context_object}, ${isolate}));")
1646
1647
1648def _make_empty_callback_def(cg_context, function_name):
1649    assert isinstance(cg_context, CodeGenContext)
1650    assert isinstance(function_name, str)
1651
1652    if cg_context.v8_callback_type == CodeGenContext.V8_FUNCTION_CALLBACK:
1653        arg_decls = ["const v8::FunctionCallbackInfo<v8::Value>& info"]
1654        arg_names = ["info"]
1655    elif (cg_context.v8_callback_type == CodeGenContext.
1656          V8_ACCESSOR_NAME_GETTER_CALLBACK):
1657        arg_decls = [
1658            "v8::Local<v8::Name> v8_property_name",
1659            "const v8::PropertyCallbackInfo<v8::Value>& info",
1660        ]
1661        arg_names = ["v8_property_name", "info"]
1662    elif (cg_context.v8_callback_type == CodeGenContext.
1663          V8_ACCESSOR_NAME_SETTER_CALLBACK):
1664        arg_decls = [
1665            "v8::Local<v8::Name> v8_property_name",
1666            "v8::Local<v8::Value> v8_property_value",
1667            "const v8::PropertyCallbackInfo<void>& info",
1668        ]
1669        arg_names = ["v8_property_name", "v8_property_value", "info"]
1670    elif (cg_context.v8_callback_type == CodeGenContext.
1671          V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK):
1672        arg_decls = [
1673            "v8::Local<v8::Name> v8_property_name",
1674            "v8::Local<v8::Value> v8_property_value",
1675            "const v8::PropertyCallbackInfo<v8::Value>& info",
1676        ]
1677        arg_names = ["v8_property_name", "v8_property_value", "info"]
1678
1679    func_def = CxxFuncDefNode(
1680        name=function_name, arg_decls=arg_decls, return_type="void")
1681    func_def.set_base_template_vars(cg_context.template_bindings())
1682    body = func_def.body
1683
1684    for arg_name in arg_names:
1685        body.add_template_var(arg_name, arg_name)
1686
1687    bind_callback_local_vars(body, cg_context)
1688    if cg_context.attribute or cg_context.function_like:
1689        bind_blink_api_arguments(body, cg_context)
1690        bind_return_value(body, cg_context)
1691
1692    return func_def
1693
1694
1695def make_attribute_get_callback_def(cg_context, function_name):
1696    assert isinstance(cg_context, CodeGenContext)
1697    assert isinstance(function_name, str)
1698
1699    func_def = _make_empty_callback_def(cg_context, function_name)
1700    body = func_def.body
1701
1702    body.extend([
1703        make_check_receiver(cg_context),
1704        EmptyNode(),
1705        make_runtime_call_timer_scope(cg_context),
1706        make_bindings_trace_event(cg_context),
1707        make_report_coop_access(cg_context),
1708        make_report_deprecate_as(cg_context),
1709        make_report_measure_as(cg_context),
1710        make_log_activity(cg_context),
1711        EmptyNode(),
1712    ])
1713
1714    if "Getter" in cg_context.property_.extended_attributes.values_of(
1715            "Custom"):
1716        text = _format("${class_name}::{}(${info});",
1717                       custom_function_name(cg_context))
1718        body.append(TextNode(text))
1719        return func_def
1720
1721    body.extend([
1722        make_return_value_cache_return_early(cg_context),
1723        EmptyNode(),
1724        make_check_security_of_return_value(cg_context),
1725        make_v8_set_return_value(cg_context),
1726        make_report_high_entropy(cg_context),
1727        make_return_value_cache_update_value(cg_context),
1728    ])
1729
1730    return func_def
1731
1732
1733def make_attribute_set_callback_def(cg_context, function_name):
1734    assert isinstance(cg_context, CodeGenContext)
1735    assert isinstance(function_name, str)
1736
1737    ext_attrs = cg_context.attribute.extended_attributes
1738    if cg_context.attribute.is_readonly and not any(
1739            ext_attr in ext_attrs
1740            for ext_attr in ("LegacyLenientSetter", "PutForwards",
1741                             "Replaceable")):
1742        return None
1743
1744    func_def = _make_empty_callback_def(cg_context, function_name)
1745    body = func_def.body
1746
1747    if "LegacyLenientSetter" in ext_attrs:
1748        body.append(TextNode("// [LegacyLenientSetter]"))
1749        return func_def
1750
1751    body.extend([
1752        make_check_receiver(cg_context),
1753        EmptyNode(),
1754        make_runtime_call_timer_scope(cg_context),
1755        make_bindings_trace_event(cg_context),
1756        make_report_deprecate_as(cg_context),
1757        make_report_measure_as(cg_context),
1758        make_log_activity(cg_context),
1759        EmptyNode(),
1760    ])
1761
1762    if "Setter" in cg_context.property_.extended_attributes.values_of(
1763            "Custom"):
1764        text = _format("${class_name}::{}(${v8_property_value}, ${info});",
1765                       custom_function_name(cg_context))
1766        body.append(TextNode(text))
1767        return func_def
1768
1769    # Binary size reduction hack
1770    # 1. Drop the check of argument length although this is a violation of
1771    #   Web IDL.
1772    # 2. Leverage the nature of [LegacyTreatNonObjectAsNull] (ES to IDL
1773    #   conversion never fails).
1774    if (cg_context.attribute.idl_type.is_typedef
1775            and (cg_context.attribute.idl_type.identifier in (
1776                "EventHandler", "OnBeforeUnloadEventHandler",
1777                "OnErrorEventHandler"))):
1778        body.extend([
1779            TextNode("""\
1780EventListener* event_handler = JSEventHandler::CreateOrNull(
1781    ${v8_property_value},
1782    JSEventHandler::HandlerType::k${attribute.idl_type.identifier});\
1783"""),
1784        ])
1785        code_generator_info = cg_context.attribute.code_generator_info
1786        func_name = name_style.api_func("set", cg_context.attribute.identifier)
1787        if code_generator_info.defined_in_partial:
1788            class_name = (code_generator_info.receiver_implemented_as
1789                          or name_style.class_(
1790                              cg_context.attribute.owner_mixin.identifier))
1791            text = _format(
1792                "{class_name}::{func_name}"
1793                "(*${blink_receiver}, event_handler);",
1794                class_name=class_name,
1795                func_name=func_name)
1796        else:
1797            text = _format("${blink_receiver}->{func_name}(event_handler);",
1798                           func_name=func_name)
1799        body.append(TextNode(text))
1800        return func_def
1801
1802    # Binary size reduction hack
1803    # When the following conditions are met, the implementation is shared.
1804    # 1. The attribute is annotated with [CEReactions, Reflect] and not
1805    #   annotated with other extended attributes having side effect.
1806    # 2. The interface is implementing Element.
1807    def optimize_element_cereactions_reflect():
1808        has_cereactions = False
1809        has_reflect = False
1810        for key in ext_attrs.keys():
1811            if key == "CEReactions":
1812                has_cereactions = True
1813            elif key == "Reflect":
1814                has_reflect = True
1815            elif key in ("Affects", "CustomElementCallbacks", "DeprecateAs",
1816                         "Exposed", "LogActivity", "LogAllWorlds", "Measure",
1817                         "MeasureAs", "ReflectEmpty", "ReflectInvalid",
1818                         "ReflectMissing", "ReflectOnly",
1819                         "RuntimeCallStatsCounter", "RuntimeEnabled",
1820                         "SecureContext", "URL", "Unscopable"):
1821                pass
1822            else:
1823                return None
1824        if not (has_cereactions and has_reflect):
1825            return None
1826        if not cg_context.interface.does_implement("Element"):
1827            return None
1828        content_attribute = _make_reflect_content_attribute_key(
1829            body, cg_context)
1830        idl_type = cg_context.attribute.idl_type.unwrap(typedef=True)
1831        if idl_type.is_boolean:
1832            func_name = "PerformAttributeSetCEReactionsReflectTypeBoolean"
1833        elif idl_type.type_name == "String":
1834            func_name = "PerformAttributeSetCEReactionsReflectTypeString"
1835        elif idl_type.type_name == "StringTreatNullAs":
1836            func_name = ("PerformAttributeSetCEReactionsReflect"
1837                         "TypeStringLegacyNullToEmptyString")
1838        elif idl_type.type_name == "StringOrNull":
1839            func_name = "PerformAttributeSetCEReactionsReflectTypeStringOrNull"
1840        else:
1841            return None
1842        text = _format(
1843            "bindings::{func_name}"
1844            "(${info}, {content_attribute}, "
1845            "${class_like_name}, ${property_name});",
1846            func_name=func_name,
1847            content_attribute=content_attribute)
1848        return TextNode(text)
1849
1850    node = optimize_element_cereactions_reflect()
1851    if node:
1852        body.append(node)
1853        return func_def
1854
1855    body.extend([
1856        make_check_argument_length(cg_context),
1857        EmptyNode(),
1858    ])
1859
1860    if "PutForwards" in ext_attrs:
1861        body.append(make_steps_of_put_forwards(cg_context))
1862        return func_def
1863
1864    if "Replaceable" in ext_attrs:
1865        body.append(make_steps_of_replaceable(cg_context))
1866        return func_def
1867
1868    body.extend([
1869        make_steps_of_ce_reactions(cg_context),
1870        EmptyNode(),
1871        make_v8_set_return_value(cg_context),
1872    ])
1873
1874    return func_def
1875
1876
1877def make_constant_callback_def(cg_context, function_name):
1878    assert isinstance(cg_context, CodeGenContext)
1879    assert isinstance(function_name, str)
1880
1881    logging_nodes = SequenceNode([
1882        make_report_deprecate_as(cg_context),
1883        make_report_measure_as(cg_context),
1884        make_log_activity(cg_context),
1885    ])
1886    if not logging_nodes:
1887        return None
1888
1889    func_def = _make_empty_callback_def(cg_context, function_name)
1890    body = func_def.body
1891
1892    v8_set_return_value = _format(
1893        "bindings::V8SetReturnValue(${info}, ${class_name}::Constant::{});",
1894        constant_name(cg_context))
1895    body.extend([
1896        make_runtime_call_timer_scope(cg_context),
1897        make_bindings_trace_event(cg_context),
1898        logging_nodes,
1899        EmptyNode(),
1900        TextNode(v8_set_return_value),
1901        make_report_high_entropy(cg_context),
1902    ])
1903
1904    return func_def
1905
1906
1907def make_constant_constant_def(cg_context, constant_name):
1908    # IDL constant's C++ constant definition
1909    assert isinstance(cg_context, CodeGenContext)
1910    assert isinstance(constant_name, str)
1911
1912    constant_type = blink_type_info(cg_context.constant.idl_type).value_t
1913    return TextNode("static constexpr {type} {name} = {value};".format(
1914        type=constant_type,
1915        name=constant_name,
1916        value=cg_context.constant.value.literal))
1917
1918
1919def make_overload_dispatcher_function_def(cg_context, function_name):
1920    assert isinstance(cg_context, CodeGenContext)
1921    assert isinstance(function_name, str)
1922
1923    func_def = _make_empty_callback_def(cg_context, function_name)
1924    body = func_def.body
1925
1926    if cg_context.operation_group:
1927        body.append(make_operation_entry(cg_context))
1928        body.append(EmptyNode())
1929        body.append(make_cooperative_scheduling_safepoint(cg_context))
1930        body.append(EmptyNode())
1931
1932    if cg_context.constructor_group:
1933        body.append(make_constructor_entry(cg_context))
1934        body.append(EmptyNode())
1935
1936    body.append(make_overload_dispatcher(cg_context))
1937
1938    return func_def
1939
1940
1941def make_constructor_entry(cg_context):
1942    assert isinstance(cg_context, CodeGenContext)
1943
1944    return SequenceNode([
1945        make_runtime_call_timer_scope(cg_context),
1946        make_bindings_trace_event(cg_context),
1947        EmptyNode(),
1948        make_check_constructor_call(cg_context),
1949    ])
1950
1951
1952def make_constructor_function_def(cg_context, function_name):
1953    assert isinstance(cg_context, CodeGenContext)
1954    assert isinstance(function_name, str)
1955
1956    T = TextNode
1957
1958    func_def = _make_empty_callback_def(cg_context, function_name)
1959    body = func_def.body
1960
1961    if len(cg_context.constructor_group) == 1:
1962        body.append(make_constructor_entry(cg_context))
1963        body.append(EmptyNode())
1964
1965    body.extend([
1966        make_report_deprecate_as(cg_context),
1967        make_report_measure_as(cg_context),
1968        make_log_activity(cg_context),
1969        EmptyNode(),
1970        make_check_argument_length(cg_context),
1971        EmptyNode(),
1972    ])
1973
1974    if "HTMLConstructor" in cg_context.constructor.extended_attributes:
1975        body.append(T("// [HTMLConstructor]"))
1976        text = _format(
1977            "V8HTMLConstructor::HtmlConstructor("
1978            "${info}, *${class_name}::GetWrapperTypeInfo(), "
1979            "HTMLElementType::{});",
1980            name_style.constant(cg_context.class_like.identifier))
1981        body.append(T(text))
1982        body.accumulate(
1983            CodeGenAccumulator.require_include_headers([
1984                "third_party/blink/renderer/bindings/core/v8/v8_html_constructor.h"
1985            ]))
1986    else:
1987        body.append(
1988            T("v8::Local<v8::Object> v8_wrapper = "
1989              "${return_value}->AssociateWithWrapper(${isolate}, "
1990              "${class_name}::GetWrapperTypeInfo(), ${v8_receiver});"))
1991        body.append(T("bindings::V8SetReturnValue(${info}, v8_wrapper);"))
1992
1993    return func_def
1994
1995
1996def make_constructor_callback_def(cg_context, function_name):
1997    assert isinstance(cg_context, CodeGenContext)
1998    assert isinstance(function_name, str)
1999
2000    constructor_group = cg_context.constructor_group
2001
2002    if len(constructor_group) == 1:
2003        return make_constructor_function_def(
2004            cg_context.make_copy(constructor=constructor_group[0]),
2005            function_name)
2006
2007    node = SequenceNode()
2008    for constructor in constructor_group:
2009        cgc = cg_context.make_copy(constructor=constructor)
2010        node.extend([
2011            make_constructor_function_def(
2012                cgc, callback_function_name(cgc, constructor.overload_index)),
2013            EmptyNode(),
2014        ])
2015    node.append(
2016        make_overload_dispatcher_function_def(cg_context, function_name))
2017    return node
2018
2019
2020def make_exposed_construct_callback_def(cg_context, function_name):
2021    assert isinstance(cg_context, CodeGenContext)
2022    assert isinstance(function_name, str)
2023
2024    func_def = _make_empty_callback_def(cg_context, function_name)
2025    body = func_def.body
2026
2027    if (cg_context.exposed_construct.is_interface
2028            or cg_context.exposed_construct.is_callback_interface):
2029        tag = "bindings::V8ReturnValue::kInterfaceObject"
2030    elif cg_context.exposed_construct.is_namespace:
2031        tag = "bindings::V8ReturnValue::kNamespaceObject"
2032    else:
2033        assert False
2034    v8_set_return_value = _format(
2035        "bindings::V8SetReturnValue"
2036        "(${info}, {bridge}::GetWrapperTypeInfo(), {tag});",
2037        bridge=v8_bridge_class_name(cg_context.exposed_construct),
2038        tag=tag)
2039    body.extend([
2040        make_runtime_call_timer_scope(cg_context),
2041        make_bindings_trace_event(cg_context),
2042        make_report_deprecate_as(cg_context),
2043        make_report_measure_as(cg_context),
2044        make_log_activity(cg_context),
2045        EmptyNode(),
2046        TextNode(v8_set_return_value),
2047    ])
2048
2049    return func_def
2050
2051
2052def make_named_constructor_property_callback_def(cg_context, function_name):
2053    assert isinstance(cg_context, CodeGenContext)
2054    assert isinstance(function_name, str)
2055
2056    func_def = _make_empty_callback_def(cg_context, function_name)
2057    body = func_def.body
2058
2059    body.extend([
2060        make_runtime_call_timer_scope(cg_context),
2061        make_bindings_trace_event(cg_context),
2062        make_report_deprecate_as(cg_context),
2063        make_report_measure_as(cg_context),
2064        make_log_activity(cg_context),
2065        EmptyNode(),
2066    ])
2067
2068    constructor_group = cg_context.exposed_construct
2069    assert isinstance(constructor_group, web_idl.ConstructorGroup)
2070    assert isinstance(constructor_group.owner, web_idl.Interface)
2071    named_ctor_v8_bridge = v8_bridge_class_name(constructor_group.owner)
2072    cgc = CodeGenContext(
2073        interface=constructor_group.owner,
2074        constructor_group=constructor_group,
2075        is_named_constructor=True,
2076        class_name=named_ctor_v8_bridge)
2077    named_ctor_name = callback_function_name(cgc)
2078    named_ctor_def = make_constructor_callback_def(cgc, named_ctor_name)
2079
2080    return_value_cache_return_early = """\
2081static const V8PrivateProperty::SymbolKey kPrivatePropertyNamedConstructor;
2082auto&& v8_private_named_constructor =
2083    V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyNamedConstructor);
2084v8::Local<v8::Value> v8_named_constructor;
2085if (!v8_private_named_constructor.GetOrUndefined(${v8_receiver})
2086         .ToLocal(&v8_named_constructor)) {
2087  return;
2088}
2089if (!v8_named_constructor->IsUndefined()) {
2090  bindings::V8SetReturnValue(${info}, v8_named_constructor);
2091  return;
2092}
2093"""
2094
2095    pattern = """\
2096v8::Local<v8::Value> v8_value;
2097if (!bindings::CreateNamedConstructorFunction(
2098         ${script_state},
2099         {callback},
2100         "{func_name}",
2101         {func_length},
2102         {v8_bridge}::GetWrapperTypeInfo())
2103     .ToLocal(&v8_value)) {
2104  return;
2105}
2106bindings::V8SetReturnValue(${info}, v8_value);
2107"""
2108    create_named_constructor_function = _format(
2109        pattern,
2110        callback=named_ctor_name,
2111        func_name=constructor_group.identifier,
2112        func_length=constructor_group.min_num_of_required_arguments,
2113        v8_bridge=named_ctor_v8_bridge)
2114
2115    return_value_cache_update_value = """\
2116v8_private_named_constructor.Set(${v8_receiver}, v8_value);
2117"""
2118
2119    body.extend([
2120        TextNode(return_value_cache_return_early),
2121        TextNode(create_named_constructor_function),
2122        TextNode(return_value_cache_update_value),
2123    ])
2124
2125    return SequenceNode([named_ctor_def, EmptyNode(), func_def])
2126
2127
2128def make_no_alloc_direct_call_callback_def(cg_context, function_name):
2129    assert isinstance(cg_context, CodeGenContext)
2130    assert isinstance(function_name, str)
2131
2132    assert cg_context.operation_group and len(cg_context.operation_group) == 1
2133
2134    func_like = cg_context.operation_group[0]
2135
2136    return_type = ("void" if func_like.return_type.is_void else
2137                   blink_type_info(func_like.return_type).value_t)
2138    arg_type_and_names = [(blink_type_info(arg.idl_type).value_t,
2139                           name_style.arg_f("arg{}_{}", index + 1,
2140                                            arg.identifier))
2141                          for index, arg in enumerate(func_like.arguments)]
2142    arg_decls = ["v8::ApiObject arg0_receiver"] + [
2143        "{} {}".format(arg_type, arg_name)
2144        for arg_type, arg_name in arg_type_and_names
2145    ]
2146    arg_decls.append("v8::FastApiCallbackOptions& arg_callback_options")
2147    func_def = CxxFuncDefNode(name=function_name,
2148                              arg_decls=arg_decls,
2149                              return_type=return_type)
2150    body = func_def.body
2151
2152    pattern = """\
2153ThreadState::NoAllocationScope no_alloc_scope(ThreadState::Current());
2154v8::Object* v8_receiver = reinterpret_cast<v8::Object*>(&arg0_receiver);
2155v8::Isolate* isolate = v8_receiver->GetIsolate();
2156v8::Isolate::DisallowJavascriptExecutionScope no_js_exec_scope(
2157    isolate,
2158    v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
2159{blink_class}* blink_receiver =
2160    ToScriptWrappable(v8_receiver)->ToImpl<{blink_class}>();
2161return blink_receiver->{member_func}({blink_arguments}, arg_callback_options);\
2162"""
2163    blink_class = blink_class_name(cg_context.interface)
2164    member_func = backward_compatible_api_func(cg_context)
2165    blink_arguments = ", ".join(
2166        [arg_name for arg_type, arg_name in arg_type_and_names])
2167    body.append(
2168        TextNode(
2169            _format(pattern,
2170                    blink_class=blink_class,
2171                    member_func=member_func,
2172                    blink_arguments=blink_arguments)))
2173
2174    return func_def
2175
2176
2177def make_operation_entry(cg_context):
2178    assert isinstance(cg_context, CodeGenContext)
2179
2180    return SequenceNode([
2181        make_runtime_call_timer_scope(cg_context),
2182        make_bindings_trace_event(cg_context),
2183    ])
2184
2185
2186def make_operation_function_def(cg_context, function_name):
2187    assert isinstance(cg_context, CodeGenContext)
2188    assert isinstance(function_name, str)
2189
2190    func_def = _make_empty_callback_def(cg_context, function_name)
2191    body = func_def.body
2192
2193    if not cg_context.operation_group or len(cg_context.operation_group) == 1:
2194        body.append(make_operation_entry(cg_context))
2195        body.append(EmptyNode())
2196
2197    body.extend([
2198        make_check_receiver(cg_context),
2199        EmptyNode(),
2200        make_report_coop_access(cg_context),
2201        make_report_deprecate_as(cg_context),
2202        make_report_measure_as(cg_context),
2203        make_log_activity(cg_context),
2204        EmptyNode(),
2205    ])
2206
2207    if "Custom" in cg_context.property_.extended_attributes:
2208        text = _format("${class_name}::{}(${info});",
2209                       custom_function_name(cg_context))
2210        body.append(TextNode(text))
2211        return func_def
2212
2213    body.extend([
2214        make_check_argument_length(cg_context),
2215        EmptyNode(),
2216        make_steps_of_ce_reactions(cg_context),
2217        EmptyNode(),
2218        make_check_security_of_return_value(cg_context),
2219        make_v8_set_return_value(cg_context),
2220        make_report_high_entropy(cg_context),
2221    ])
2222
2223    return func_def
2224
2225
2226def make_operation_callback_def(cg_context,
2227                                function_name,
2228                                no_alloc_direct_callback_name=None):
2229    assert isinstance(cg_context, CodeGenContext)
2230    assert isinstance(function_name, str)
2231
2232    operation_group = cg_context.operation_group
2233
2234    assert (not ("Custom" in operation_group.extended_attributes)
2235            or len(operation_group) == 1)
2236    assert (not ("NoAllocDirectCall" in operation_group.extended_attributes)
2237            or len(operation_group) == 1)
2238
2239    if "NoAllocDirectCall" in operation_group.extended_attributes:
2240        return ListNode([
2241            make_operation_function_def(
2242                cg_context.make_copy(operation=operation_group[0]),
2243                function_name),
2244            EmptyNode(),
2245            make_no_alloc_direct_call_callback_def(
2246                cg_context.make_copy(operation=operation_group[0]),
2247                no_alloc_direct_callback_name),
2248        ])
2249
2250    if len(operation_group) == 1:
2251        return make_operation_function_def(
2252            cg_context.make_copy(operation=operation_group[0]), function_name)
2253
2254    node = SequenceNode()
2255    for operation in operation_group:
2256        cgc = cg_context.make_copy(operation=operation)
2257        node.extend([
2258            make_operation_function_def(
2259                cgc, callback_function_name(cgc, operation.overload_index)),
2260            EmptyNode(),
2261        ])
2262    node.append(
2263        make_overload_dispatcher_function_def(cg_context, function_name))
2264    return node
2265
2266
2267def make_stringifier_callback_def(cg_context, function_name):
2268    assert isinstance(cg_context, CodeGenContext)
2269    assert isinstance(function_name, str)
2270
2271    if cg_context.stringifier.attribute:
2272        return make_attribute_get_callback_def(
2273            cg_context.make_copy(
2274                attribute=cg_context.stringifier.attribute,
2275                attribute_get=True), function_name)
2276    elif cg_context.stringifier.operation:
2277        return make_operation_function_def(
2278            cg_context.make_copy(operation=cg_context.stringifier.operation),
2279            function_name)
2280    assert False
2281
2282
2283# ----------------------------------------------------------------------------
2284# Callback functions of indexed and named interceptors
2285# ----------------------------------------------------------------------------
2286
2287
2288def _make_interceptor_callback(cg_context, function_name, arg_decls, arg_names,
2289                               class_name, runtime_call_timer_name):
2290    assert isinstance(cg_context, CodeGenContext)
2291    assert isinstance(function_name, str)
2292    assert isinstance(arg_decls, (list, tuple))
2293    assert all(isinstance(arg_decl, str) for arg_decl in arg_decls)
2294    assert isinstance(arg_names, (list, tuple))
2295    assert all(isinstance(arg_name, str) for arg_name in arg_names)
2296    assert _is_none_or_str(class_name)
2297    assert isinstance(runtime_call_timer_name, str)
2298
2299    func_decl = CxxFuncDeclNode(
2300        name=function_name,
2301        arg_decls=arg_decls,
2302        return_type="void",
2303        static=True)
2304
2305    func_def = _make_interceptor_callback_def(cg_context, function_name,
2306                                              arg_decls, arg_names, class_name,
2307                                              runtime_call_timer_name)
2308
2309    return func_decl, func_def
2310
2311
2312def _make_interceptor_callback_def(cg_context, function_name, arg_decls,
2313                                   arg_names, class_name,
2314                                   runtime_call_timer_name):
2315    assert isinstance(cg_context, CodeGenContext)
2316    assert isinstance(function_name, str)
2317    assert isinstance(arg_decls, (list, tuple))
2318    assert all(isinstance(arg_decl, str) for arg_decl in arg_decls)
2319    assert isinstance(arg_names, (list, tuple))
2320    assert all(isinstance(arg_name, str) for arg_name in arg_names)
2321    assert _is_none_or_str(class_name)
2322    assert isinstance(runtime_call_timer_name, str)
2323
2324    func_def = CxxFuncDefNode(
2325        name=function_name,
2326        arg_decls=arg_decls,
2327        return_type="void",
2328        class_name=class_name)
2329    func_def.set_base_template_vars(cg_context.template_bindings())
2330    body = func_def.body
2331    for arg_name in arg_names:
2332        body.add_template_var(arg_name, arg_name)
2333    bind_callback_local_vars(body, cg_context)
2334
2335    body.extend([
2336        make_runtime_call_timer_scope(cg_context, runtime_call_timer_name),
2337        EmptyNode(),
2338    ])
2339
2340    return func_def
2341
2342
2343def make_indexed_property_getter_callback(cg_context, function_name):
2344    assert isinstance(cg_context, CodeGenContext)
2345    assert isinstance(function_name, str)
2346
2347    arg_decls = [
2348        "uint32_t index",
2349        "const v8::PropertyCallbackInfo<v8::Value>& info",
2350    ]
2351    arg_names = ["index", "info"]
2352
2353    func_decl, func_def = _make_interceptor_callback(
2354        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2355        "IndexedPropertyGetter")
2356    body = func_def.body
2357
2358    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2359        body.append(
2360            TextNode("""\
2361v8::Local<v8::String> property_name =
2362    V8AtomicString(${isolate}, AtomicString::Number(${index}));
2363${class_name}::NamedPropertyGetterCallback(property_name, ${info});
2364"""))
2365        return func_decl, func_def
2366
2367    bind_return_value(body, cg_context, overriding_args=["${index}"])
2368
2369    body.extend([
2370        TextNode("""\
2371// LegacyPlatformObjectGetOwnProperty
2372// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
2373// step 1.2. If index is a supported property index, then:
2374// step 3. Return OrdinaryGetOwnProperty(O, P).
2375if (${index} >= ${blink_receiver}->length())
2376  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
2377"""),
2378        make_v8_set_return_value(cg_context),
2379    ])
2380
2381    return func_decl, func_def
2382
2383
2384def make_indexed_property_setter_callback(cg_context, function_name):
2385    assert isinstance(cg_context, CodeGenContext)
2386    assert isinstance(function_name, str)
2387
2388    arg_decls = [
2389        "uint32_t index",
2390        "v8::Local<v8::Value> v8_property_value",
2391        "const v8::PropertyCallbackInfo<v8::Value>& info",
2392    ]
2393    arg_names = ["index", "v8_property_value", "info"]
2394
2395    func_decl, func_def = _make_interceptor_callback(
2396        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2397        "IndexedPropertySetter")
2398    body = func_def.body
2399
2400    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2401        body.append(
2402            TextNode("""\
2403v8::Local<v8::String> property_name =
2404    V8AtomicString(${isolate}, AtomicString::Number(${index}));
2405${class_name}::NamedPropertySetterCallback(
2406    property_name, ${v8_property_value}, ${info});
2407"""))
2408        return func_decl, func_def
2409
2410    if not cg_context.indexed_property_setter:
2411        body.append(
2412            TextNode("""\
2413// 3.9.2. [[Set]]
2414// https://heycam.github.io/webidl/#legacy-platform-object-set
2415// OrdinarySetWithOwnDescriptor will end up calling DefineOwnProperty,
2416// which will fail when the receiver object is this legacy platform
2417// object.
2418bindings::V8SetReturnValue(${info}, nullptr);
2419if (${info}.ShouldThrowOnError()) {
2420  ExceptionState exception_state(${info}.GetIsolate(),
2421                                 ExceptionState::kIndexedSetterContext,
2422                                 "${interface.identifier}");
2423  exception_state.ThrowTypeError(
2424      "Indexed property setter is not supported.");
2425}
2426"""))
2427        return func_decl, func_def
2428
2429    bind_return_value(
2430        body,
2431        cg_context,
2432        overriding_args=["${index}", "${blink_property_value}"])
2433    body.register_code_symbol(
2434        make_v8_to_blink_value(
2435            "blink_property_value",
2436            "${v8_property_value}",
2437            cg_context.indexed_property_setter.arguments[1].idl_type,
2438            argument_index=2))
2439
2440    body.extend([
2441        TextNode("""\
2442// 3.9.2. [[Set]]
2443// https://heycam.github.io/webidl/#legacy-platform-object-set
2444// step 1. If O and Receiver are the same object, then:\
2445"""),
2446        CxxLikelyIfNode(cond="${info}.Holder() == ${info}.This()",
2447                        body=[
2448                            TextNode("""\
2449// step 1.1.1. Invoke the indexed property setter with P and V.\
2450"""),
2451                            make_steps_of_ce_reactions(cg_context),
2452                            EmptyNode(),
2453                            make_v8_set_return_value(cg_context),
2454                            TextNode("""\
2455bindings::V8SetReturnValue(${info}, nullptr);
2456return;"""),
2457                        ]),
2458        EmptyNode(),
2459        TextNode("""\
2460// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.
2461"""),
2462    ])
2463
2464    return func_decl, func_def
2465
2466
2467def make_indexed_property_deleter_callback(cg_context, function_name):
2468    assert isinstance(cg_context, CodeGenContext)
2469    assert isinstance(function_name, str)
2470
2471    arg_decls = [
2472        "uint32_t index",
2473        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
2474    ]
2475    arg_names = ["index", "info"]
2476
2477    func_decl, func_def = _make_interceptor_callback(
2478        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2479        "IndexedPropertyDeleter")
2480    body = func_def.body
2481
2482    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2483        body.append(
2484            TextNode("""\
2485v8::Local<v8::String> property_name =
2486    V8AtomicString(${isolate}, AtomicString::Number(${index}));
2487${class_name}::NamedPropertyDeleterCallback(property_name, ${info});
2488"""))
2489        return func_decl, func_def
2490
2491    body.append(
2492        TextNode("""\
2493// 3.9.4. [[Delete]]
2494// https://heycam.github.io/webidl/#legacy-platform-object-delete
2495// step 1.2. If index is not a supported property index, then return true.
2496// step 1.3. Return false.
2497const bool is_supported = ${index} < ${blink_receiver}->length();
2498bindings::V8SetReturnValue(${info}, !is_supported);
2499if (is_supported and ${info}.ShouldThrowOnError()) {
2500  ExceptionState exception_state(${info}.GetIsolate(),
2501                                 ExceptionState::kIndexedDeletionContext,
2502                                 "${interface.identifier}");
2503  exception_state.ThrowTypeError("Index property deleter is not supported.");
2504}
2505"""))
2506
2507    return func_decl, func_def
2508
2509
2510def make_indexed_property_definer_callback(cg_context, function_name):
2511    assert isinstance(cg_context, CodeGenContext)
2512    assert isinstance(function_name, str)
2513
2514    arg_decls = [
2515        "uint32_t index",
2516        "const v8::PropertyDescriptor& v8_property_desc",
2517        "const v8::PropertyCallbackInfo<v8::Value>& info",
2518    ]
2519    arg_names = ["index", "v8_property_desc", "info"]
2520
2521    func_decl, func_def = _make_interceptor_callback(
2522        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2523        "IndexedPropertyDefiner")
2524    body = func_def.body
2525
2526    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2527        body.append(
2528            TextNode("""\
2529v8::Local<v8::String> property_name =
2530    V8AtomicString(${isolate}, AtomicString::Number(${index}));
2531${class_name}::NamedPropertyDefinerCallback(
2532    property_name, ${v8_property_desc}, ${info});
2533"""))
2534        return func_decl, func_def
2535
2536    body.append(
2537        TextNode("""\
2538// 3.9.3. [[DefineOwnProperty]]
2539// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
2540// step 1.1. If the result of calling IsDataDescriptor(Desc) is false, then
2541//   return false.
2542if (v8_property_desc.has_get() || v8_property_desc.has_set()) {
2543  bindings::V8SetReturnValue(${info}, nullptr);
2544  if (${info}.ShouldThrowOnError()) {
2545    ExceptionState exception_state(${info}.GetIsolate(),
2546                                   ExceptionState::kIndexedSetterContext,
2547                                   "${interface.identifier}");
2548    exception_state.ThrowTypeError("Accessor properties are not allowed.");
2549  }
2550  return;
2551}
2552"""))
2553
2554    if not cg_context.interface.indexed_and_named_properties.indexed_setter:
2555        body.append(
2556            TextNode("""\
2557// step 1.2. If O does not implement an interface with an indexed property
2558//   setter, then return false.
2559bindings::V8SetReturnValue(${info}, nullptr);
2560if (${info}.ShouldThrowOnError()) {
2561  ExceptionState exception_state(${info}.GetIsolate(),
2562                                 ExceptionState::kIndexedSetterContext,
2563                                 "${interface.identifier}");
2564  exception_state.ThrowTypeError("Index property setter is not supported.");
2565}
2566"""))
2567    else:
2568        body.append(
2569            TextNode("""\
2570// step 1.3. Invoke the indexed property setter with P and Desc.[[Value]].
2571${class_name}::IndexedPropertySetterCallback(
2572    ${index}, ${v8_property_desc}.value(), ${info});
2573"""))
2574
2575    return func_decl, func_def
2576
2577
2578def make_indexed_property_descriptor_callback(cg_context, function_name):
2579    assert isinstance(cg_context, CodeGenContext)
2580    assert isinstance(function_name, str)
2581
2582    arg_decls = [
2583        "uint32_t index",
2584        "const v8::PropertyCallbackInfo<v8::Value>& info",
2585    ]
2586    arg_names = ["index", "info"]
2587
2588    func_decl, func_def = _make_interceptor_callback(
2589        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2590        "IndexedPropertyDescriptor")
2591    body = func_def.body
2592
2593    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2594        body.append(
2595            TextNode("""\
2596v8::Local<v8::String> property_name =
2597    V8AtomicString(${isolate}, AtomicString::Number(${index}));
2598${class_name}::NamedPropertyDescriptorCallback(property_name, ${info});
2599"""))
2600        return func_decl, func_def
2601
2602    pattern = """\
2603// LegacyPlatformObjectGetOwnProperty
2604// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
2605// step 1.2.3. If operation was defined without an identifier, then set
2606//   value to the result of performing the steps listed in the interface
2607//   description to determine the value of an indexed property with index
2608//   as the index.
2609// step 1.2.4. Otherwise, operation was defined with an identifier. Set
2610//   value to the result of performing the steps listed in the description
2611//   of operation with index as the only argument value.
2612${class_name}::IndexedPropertyGetterCallback(${index}, ${info});
2613v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
2614// step 1.2. If index is a supported property index, then:
2615// step 3. Return OrdinaryGetOwnProperty(O, P).
2616if (v8_value->IsUndefined())
2617  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
2618
2619// step 1.2.6. Set desc.[[Value]] to the result of converting value to an
2620//   ECMAScript value.
2621// step 1.2.7. If O implements an interface with an indexed property setter,
2622//   then set desc.[[Writable]] to true, otherwise set it to false.
2623// step 1.2.8. Set desc.[[Enumerable]] and desc.[[Configurable]] to true.
2624v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
2625desc.set_enumerable(true);
2626desc.set_configurable(true);
2627bindings::V8SetReturnValue(${info}, desc);"""
2628    writable = bool(
2629        cg_context.interface.indexed_and_named_properties.indexed_setter)
2630    cxx_writable = "true" if writable else "false"
2631    body.append(TextNode(_format(pattern, cxx_writable=cxx_writable)))
2632
2633    return func_decl, func_def
2634
2635
2636def make_indexed_property_enumerator_callback(cg_context, function_name):
2637    assert isinstance(cg_context, CodeGenContext)
2638    assert isinstance(function_name, str)
2639
2640    if not cg_context.interface.indexed_and_named_properties.indexed_getter:
2641        return None, None
2642
2643    arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
2644    arg_names = ["info"]
2645
2646    func_decl, func_def = _make_interceptor_callback(
2647        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2648        "IndexedPropertyEnumerator")
2649    body = func_def.body
2650
2651    body.append(
2652        TextNode("""\
2653// 3.9.6. [[OwnPropertyKeys]]
2654// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys
2655// step 2. If O supports indexed properties, then for each index of O's
2656//   supported property indices, in ascending numerical order, append
2657//   ! ToString(index) to keys.
2658uint32_t length = ${blink_receiver}->length();
2659v8::Local<v8::Array> array =
2660    bindings::EnumerateIndexedProperties(${isolate}, length);
2661bindings::V8SetReturnValue(${info}, array);
2662"""))
2663    body.accumulate(
2664        CodeGenAccumulator.require_include_headers([
2665            "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
2666        ]))
2667
2668    return func_decl, func_def
2669
2670
2671def make_named_property_getter_callback(cg_context, function_name):
2672    assert isinstance(cg_context, CodeGenContext)
2673    assert isinstance(function_name, str)
2674
2675    arg_decls = [
2676        "v8::Local<v8::Name> v8_property_name",
2677        "const v8::PropertyCallbackInfo<v8::Value>& info",
2678    ]
2679    arg_names = ["v8_property_name", "info"]
2680
2681    func_decl, func_def = _make_interceptor_callback(
2682        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2683        "NamedPropertyGetter")
2684    body = func_def.body
2685
2686    bind_return_value(
2687        body, cg_context, overriding_args=["${blink_property_name}"])
2688
2689    if "Custom" in cg_context.named_property_getter.extended_attributes:
2690        text = _format("${class_name}::{}(${blink_property_name}, ${info});",
2691                       custom_function_name(cg_context))
2692        body.append(TextNode(text))
2693        return func_decl, func_def
2694
2695    # The named property getter's implementation of Blink is not designed to
2696    # represent the property existence, and we have to determine the property
2697    # existence by heuristics.
2698    type = cg_context.return_type.unwrap()
2699    if type.is_any or type.is_object:
2700        not_found_expr = "${return_value}.IsEmpty()"
2701    elif type.is_string:
2702        not_found_expr = "${return_value}.IsNull()"
2703    elif type.is_interface:
2704        not_found_expr = "!${return_value}"
2705    elif type.is_union:
2706        not_found_expr = "${return_value}.IsNull()"
2707    else:
2708        assert False
2709
2710    body.extend([
2711        TextNode("""\
2712// LegacyPlatformObjectGetOwnProperty
2713// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
2714// step 2.1. If the result of running the named property visibility
2715//   algorithm with property name P and object O is true, then:\
2716"""),
2717        CxxUnlikelyIfNode(
2718            cond=not_found_expr,
2719            body=[
2720                TextNode("// step 3. Return OrdinaryGetOwnProperty(O, P)."),
2721                TextNode("return;  // Do not intercept."),
2722            ]),
2723        TextNode("""\
2724// step 2.1.3. If operation was defined without an identifier, then set
2725//   value to the result of performing the steps listed in the interface
2726//   description to determine the value of a named property with P as the
2727//   name.
2728// step 2.1.4. Otherwise, operation was defined with an identifier. Set
2729//   value to the result of performing the steps listed in the description
2730//   of operation with P as the only argument value.\
2731"""),
2732        make_v8_set_return_value(cg_context),
2733    ])
2734
2735    return func_decl, func_def
2736
2737
2738def make_named_property_setter_callback(cg_context, function_name):
2739    assert isinstance(cg_context, CodeGenContext)
2740    assert isinstance(function_name, str)
2741
2742    arg_decls = [
2743        "v8::Local<v8::Name> v8_property_name",
2744        "v8::Local<v8::Value> v8_property_value",
2745        "const v8::PropertyCallbackInfo<v8::Value>& info",
2746    ]
2747    arg_names = ["v8_property_name", "v8_property_value", "info"]
2748
2749    func_decl, func_def = _make_interceptor_callback(
2750        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2751        "NamedPropertySetter")
2752    body = func_def.body
2753
2754    if not cg_context.named_property_setter:
2755        body.append(
2756            TextNode("""\
2757// 3.9.2. [[Set]]
2758// https://heycam.github.io/webidl/#legacy-platform-object-set
2759// step 3. Perform ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc).\
2760"""))
2761        if ("LegacyOverrideBuiltIns" in
2762                cg_context.interface.extended_attributes):
2763            body.append(
2764                TextNode("""\
2765// [LegacyOverrideBuiltIns]
2766if (${info}.Holder()->GetRealNamedPropertyAttributesInPrototypeChain(
2767        ${current_context}, ${v8_property_name}).IsJust()) {
2768  return;  // Fallback to the existing property.
2769}
2770"""))
2771        body.append(
2772            TextNode("""\
2773${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
2774const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined();
2775if (!is_creating) {
2776  bindings::V8SetReturnValue(${info}, nullptr);
2777  if (${info}.ShouldThrowOnError()) {
2778    ExceptionState exception_state(${info}.GetIsolate(),
2779                                   ExceptionState::kNamedSetterContext,
2780                                   "${interface.identifier}");
2781    exception_state.ThrowTypeError(
2782        "Named property setter is not supported.");
2783  }
2784  return;
2785}
2786
2787// Do not intercept.  Fallback and let it define a new own property.
2788"""))
2789        return func_decl, func_def
2790
2791    bind_return_value(
2792        body,
2793        cg_context,
2794        overriding_args=["${blink_property_name}", "${blink_property_value}"])
2795    body.register_code_symbol(
2796        make_v8_to_blink_value(
2797            "blink_property_value",
2798            "${v8_property_value}",
2799            cg_context.named_property_setter.arguments[1].idl_type,
2800            argument_index=2))
2801
2802    if "Custom" in cg_context.named_property_setter.extended_attributes:
2803        text = _format(
2804            "${class_name}::{}"
2805            "(${blink_property_name}, ${v8_property_value}, ${info});",
2806            custom_function_name(cg_context))
2807        body.append(TextNode(text))
2808        return func_decl, func_def
2809
2810    body.extend([
2811        TextNode("""\
2812// 3.9.2. [[Set]]
2813// https://heycam.github.io/webidl/#legacy-platform-object-set
2814// step 1. If O and Receiver are the same object, then:\
2815"""),
2816        CxxLikelyIfNode(cond="${info}.Holder() == ${info}.This()",
2817                        body=[
2818                            TextNode("""\
2819// step 1.2.1. Invoke the named property setter with P and V.\
2820"""),
2821                            make_steps_of_ce_reactions(cg_context),
2822                            EmptyNode(),
2823                            make_v8_set_return_value(cg_context),
2824                            TextNode("""\
2825% if interface.identifier == "CSSStyleDeclaration":
2826// CSSStyleDeclaration is abusing named properties.
2827// Do not intercept if the property is not found.
2828% else:
2829bindings::V8SetReturnValue(${info}, nullptr);
2830% endif
2831return;"""),
2832                        ]),
2833        EmptyNode(),
2834        TextNode("""\
2835// Do not intercept.  Fallback to OrdinarySetWithOwnDescriptor.
2836"""),
2837    ])
2838
2839    return func_decl, func_def
2840
2841
2842def make_named_property_deleter_callback(cg_context, function_name):
2843    assert isinstance(cg_context, CodeGenContext)
2844    assert isinstance(function_name, str)
2845
2846    arg_decls = [
2847        "v8::Local<v8::Name> v8_property_name",
2848        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
2849    ]
2850    arg_names = ["v8_property_name", "info"]
2851
2852    func_decl, func_def = _make_interceptor_callback(
2853        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2854        "NamedPropertyDeleter")
2855    body = func_def.body
2856
2857    props = cg_context.interface.indexed_and_named_properties
2858    if (not cg_context.named_property_deleter
2859            and "NotEnumerable" in props.named_getter.extended_attributes):
2860        body.append(
2861            TextNode("""\
2862// 3.9.4. [[Delete]]
2863// https://heycam.github.io/webidl/#legacy-platform-object-delete
2864// step 2. If O supports named properties, O does not implement an interface
2865//   with the [Global] extended attribute and the result of calling the
2866//   named property visibility algorithm with property name P and object O
2867//   is true, then:
2868//
2869// There is no easy way to determine whether the named property is visible
2870// or not.  Just do not intercept and fallback to the default behavior.
2871"""))
2872        return func_decl, func_def
2873
2874    if not cg_context.named_property_deleter:
2875        body.append(
2876            TextNode("""\
2877// 3.9.4. [[Delete]]
2878// https://heycam.github.io/webidl/#legacy-platform-object-delete
2879// step 2. If O supports named properties, O does not implement an interface
2880//   with the [Global] extended attribute and the result of calling the
2881//   named property visibility algorithm with property name P and object O
2882//   is true, then:
2883// step 2.1. If O does not implement an interface with a named property
2884//   deleter, then return false.
2885ExceptionState exception_state(${info}.GetIsolate(),
2886                               ExceptionState::kNamedDeletionContext,
2887                               "${interface.identifier}");
2888bool does_exist = ${blink_receiver}->NamedPropertyQuery(
2889    ${blink_property_name}, exception_state);
2890if (exception_state.HadException())
2891  return;
2892if (does_exist) {
2893  bindings::V8SetReturnValue(${info}, false);
2894  if (${info}.ShouldThrowOnError()) {
2895    exception_state.ThrowTypeError("Named property deleter is not supported.");
2896  }
2897  return;
2898}
2899
2900// Do not intercept.
2901"""))
2902        return func_decl, func_def
2903
2904    bind_return_value(
2905        body, cg_context, overriding_args=["${blink_property_name}"])
2906
2907    if "Custom" in cg_context.named_property_deleter.extended_attributes:
2908        text = _format("${class_name}::{}(${blink_property_name}, ${info});",
2909                       custom_function_name(cg_context))
2910        body.append(TextNode(text))
2911        return func_decl, func_def
2912
2913    body.extend([
2914        TextNode("""\
2915// 3.9.4. [[Delete]]
2916// https://heycam.github.io/webidl/#legacy-platform-object-delete\
2917"""),
2918        make_steps_of_ce_reactions(cg_context),
2919        EmptyNode(),
2920        make_v8_set_return_value(cg_context),
2921        TextNode("""\
2922if (${return_value} == NamedPropertyDeleterResult::kDidNotDelete) {
2923  if (${info}.ShouldThrowOnError()) {
2924    ExceptionState exception_state(${info}.GetIsolate(),
2925                                   ExceptionState::kNamedDeletionContext,
2926                                   "${interface.identifier}");
2927    exception_state.ThrowTypeError("Failed to delete a property.");
2928  }
2929  return;
2930}"""),
2931    ])
2932
2933    return func_decl, func_def
2934
2935
2936def make_named_property_definer_callback(cg_context, function_name):
2937    assert isinstance(cg_context, CodeGenContext)
2938    assert isinstance(function_name, str)
2939
2940    arg_decls = [
2941        "v8::Local<v8::Name> v8_property_name",
2942        "const v8::PropertyDescriptor& v8_property_desc",
2943        "const v8::PropertyCallbackInfo<v8::Value>& info",
2944    ]
2945    arg_names = ["v8_property_name", "v8_property_desc", "info"]
2946
2947    func_decl, func_def = _make_interceptor_callback(
2948        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
2949        "NamedPropertyDefiner")
2950    body = func_def.body
2951
2952    if cg_context.interface.identifier == "CSSStyleDeclaration":
2953        body.append(
2954            TextNode("""\
2955// CSSStyleDeclaration is abusing named properties.
2956// Do not intercept.  Fallback to OrdinaryDefineOwnProperty.
2957"""))
2958    elif cg_context.interface.identifier in ("HTMLEmbedElement",
2959                                             "HTMLObjectElement"):
2960        body.append(
2961            TextNode("""\
2962// HTMLEmbedElement and HTMLObjectElement are abusing named properties.
2963// Do not intercept.  Fallback to OrdinaryDefineOwnProperty.
2964"""))
2965    elif not cg_context.interface.indexed_and_named_properties.named_setter:
2966        body.append(
2967            TextNode("""\
2968// 3.9.3. [[DefineOwnProperty]]
2969// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
2970// step 2.1. Let creating be true if P is not a supported property name, and
2971//   false otherwise.
2972// step 2.2.1. If creating is false and O does not implement an interface
2973//   with a named property setter, then return false.
2974${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
2975const bool is_creating = ${info}.GetReturnValue().Get()->IsUndefined();
2976if (!is_creating) {
2977  bindings::V8SetReturnValue(${info}, nullptr);
2978  if (${info}.ShouldThrowOnError()) {
2979    ExceptionState exception_state(${info}.GetIsolate(),
2980                                   ExceptionState::kNamedSetterContext,
2981                                   "${interface.identifier}");
2982    exception_state.ThrowTypeError("Named property setter is not supported.");
2983  }
2984  return;
2985}
2986
2987// Do not intercept.  Fallback to OrdinaryDefineOwnProperty.
2988"""))
2989    else:
2990        body.append(
2991            TextNode("""\
2992// 3.9.3. [[DefineOwnProperty]]
2993// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
2994// step 2.2.2. If O implements an interface with a named property setter,
2995//   then:
2996// step 2.2.2.1. If the result of calling IsDataDescriptor(Desc) is false,
2997//   then return false.
2998if (v8_property_desc.has_get() || v8_property_desc.has_set()) {
2999  bindings::V8SetReturnValue(${info}, nullptr);
3000  if (${info}.ShouldThrowOnError()) {
3001    ExceptionState exception_state(${info}.GetIsolate(),
3002                                   ExceptionState::kNamedSetterContext,
3003                                   "${interface.identifier}");
3004    exception_state.ThrowTypeError("Accessor properties are not allowed.");
3005  }
3006  return;
3007}
3008
3009// step 2.2.2.2. Invoke the named property setter with P and Desc.[[Value]].
3010${class_name}::NamedPropertySetterCallback(
3011    ${v8_property_name}, ${v8_property_desc}.value(), ${info});
3012bindings::V8SetReturnValue(${info}, nullptr);
3013"""))
3014
3015    return func_decl, func_def
3016
3017
3018def make_named_property_descriptor_callback(cg_context, function_name):
3019    assert isinstance(cg_context, CodeGenContext)
3020    assert isinstance(function_name, str)
3021
3022    arg_decls = [
3023        "v8::Local<v8::Name> v8_property_name",
3024        "const v8::PropertyCallbackInfo<v8::Value>& info",
3025    ]
3026    arg_names = ["v8_property_name", "info"]
3027
3028    func_decl, func_def = _make_interceptor_callback(
3029        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
3030        "NamedPropertyDescriptor")
3031    body = func_def.body
3032
3033    body.append(
3034        TextNode("""\
3035// LegacyPlatformObjectGetOwnProperty
3036// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty\
3037"""))
3038
3039    if ("LegacyOverrideBuiltIns" not in
3040            cg_context.interface.extended_attributes):
3041        body.append(
3042            TextNode("""\
3043// step 2.1. If the result of running the named property visibility algorithm
3044//   with property name P and object O is true, then:
3045if (${v8_receiver}->GetRealNamedPropertyAttributesInPrototypeChain(
3046        ${current_context}, ${v8_property_name}).IsJust()) {
3047  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
3048}
3049"""))
3050
3051    pattern = """\
3052// step 2.1.3. If operation was defined without an identifier, then set
3053//   value to the result of performing the steps listed in the interface
3054//   description to determine the value of a named property with P as the
3055//   name.
3056// step 2.1.4. Otherwise, operation was defined with an identifier. Set
3057//   value to the result of performing the steps listed in the description
3058//   of operation with P as the only argument value.
3059${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
3060v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
3061// step 2.1. If the result of running the named property visibility
3062//   algorithm with property name P and object O is true, then:
3063// step 3. Return OrdinaryGetOwnProperty(O, P).
3064if (v8_value->IsUndefined())
3065  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
3066
3067// step 2.1.6. Set desc.[[Value]] to the result of converting value to an
3068//   ECMAScript value.
3069// step 2.1.7. If O implements an interface with a named property setter,
3070//   then set desc.[[Writable]] to true, otherwise set it to false.
3071// step 2.1.8. If O implements an interface with the
3072//   [LegacyUnenumerableNamedProperties] extended attribute, then set
3073//   desc.[[Enumerable]] to false, otherwise set it to true.
3074// step 2.1.9. Set desc.[[Configurable]] to true.
3075v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
3076desc.set_enumerable({cxx_enumerable});
3077desc.set_configurable(true);
3078bindings::V8SetReturnValue(${info}, desc);
3079"""
3080    props = cg_context.interface.indexed_and_named_properties
3081    writable = bool(props.named_setter)
3082    cxx_writable = "true" if writable else "false"
3083    enumerable = props.is_named_property_enumerable
3084    cxx_enumerable = "true" if enumerable else "false"
3085    body.append(
3086        TextNode(
3087            _format(
3088                pattern,
3089                cxx_writable=cxx_writable,
3090                cxx_enumerable=cxx_enumerable)))
3091
3092    return func_decl, func_def
3093
3094
3095def make_named_property_query_callback(cg_context, function_name):
3096    assert isinstance(cg_context, CodeGenContext)
3097    assert isinstance(function_name, str)
3098
3099    props = cg_context.interface.indexed_and_named_properties
3100    if "NotEnumerable" in props.named_getter.extended_attributes:
3101        return None, None
3102
3103    arg_decls = [
3104        "v8::Local<v8::Name> v8_property_name",
3105        "const v8::PropertyCallbackInfo<v8::Integer>& info",
3106    ]
3107    arg_names = ["v8_property_name", "info"]
3108
3109    func_decl, func_def = _make_interceptor_callback(
3110        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
3111        "NamedPropertyQuery")
3112    body = func_def.body
3113
3114    flags = []
3115    if not props.named_setter:
3116        flags.append("v8::ReadOnly")
3117    if not props.is_named_property_enumerable:
3118        flags.append("v8::DontEnum")
3119    if not flags:
3120        flags.append("v8::None")
3121    if len(flags) == 1:
3122        property_attribute = flags[0]
3123    else:
3124        property_attribute = " | ".join(flags)
3125
3126    body.extend([
3127        TextNode("""\
3128ExceptionState exception_state(${isolate},
3129                               ExceptionState::kNamedGetterContext,
3130                               "${interface.identifier}");
3131bool does_exist = ${blink_receiver}->NamedPropertyQuery(
3132    ${blink_property_name}, exception_state);
3133if (!does_exist)
3134  return;  // Do not intercept.
3135"""),
3136        TextNode(
3137            _format(
3138                "bindings::V8SetReturnValue"
3139                "(${info}, uint32_t({property_attribute}));",
3140                property_attribute=property_attribute)),
3141    ])
3142
3143    return func_decl, func_def
3144
3145
3146def make_named_property_enumerator_callback(cg_context, function_name):
3147    assert isinstance(cg_context, CodeGenContext)
3148    assert isinstance(function_name, str)
3149
3150    props = cg_context.interface.indexed_and_named_properties
3151    if "NotEnumerable" in props.named_getter.extended_attributes:
3152        return None, None
3153
3154    arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
3155    arg_names = ["info"]
3156
3157    func_decl, func_def = _make_interceptor_callback(
3158        cg_context, function_name, arg_decls, arg_names, cg_context.class_name,
3159        "NamedPropertyEnumerator")
3160    body = func_def.body
3161
3162    body.append(
3163        TextNode("""\
3164// 3.9.6. [[OwnPropertyKeys]]
3165// https://heycam.github.io/webidl/#legacy-platform-object-ownpropertykeys
3166// step 3. If O supports named properties, then for each P of O's supported
3167//   property names that is visible according to the named property
3168//   visibility algorithm, append P to keys.
3169Vector<String> blink_property_names;
3170ExceptionState exception_state(${info}.GetIsolate(),
3171                               ExceptionState::kEnumerationContext,
3172                               "${interface.identifier}");
3173${blink_receiver}->NamedPropertyEnumerator(
3174    blink_property_names, exception_state);
3175if (exception_state.HadException())
3176  return;
3177bindings::V8SetReturnValue(
3178    ${info},
3179    ToV8(blink_property_names, ${creation_context_object}, ${isolate}));
3180"""))
3181
3182    return func_decl, func_def
3183
3184
3185# ----------------------------------------------------------------------------
3186# Callback functions of interceptors on named properties object
3187# ----------------------------------------------------------------------------
3188
3189
3190def make_named_props_obj_indexed_getter_callback(cg_context, function_name):
3191    assert isinstance(cg_context, CodeGenContext)
3192    assert isinstance(function_name, str)
3193
3194    arg_decls = [
3195        "uint32_t index",
3196        "const v8::PropertyCallbackInfo<v8::Value>& info",
3197    ]
3198    arg_names = ["index", "info"]
3199
3200    func_def = _make_interceptor_callback_def(
3201        cg_context, function_name, arg_decls, arg_names, None,
3202        "NamedPropertiesObject_IndexedPropertyGetter")
3203    body = func_def.body
3204
3205    body.append(
3206        TextNode("""\
3207v8::Local<v8::String> property_name =
3208    V8AtomicString(${isolate}, AtomicString::Number(${index}));
3209NamedPropsObjNamedGetterCallback(property_name, ${info});
3210"""))
3211
3212    return func_def
3213
3214
3215def make_named_props_obj_indexed_deleter_callback(cg_context, function_name):
3216    assert isinstance(cg_context, CodeGenContext)
3217    assert isinstance(function_name, str)
3218
3219    arg_decls = [
3220        "uint32_t index",
3221        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
3222    ]
3223    arg_names = ["index", "info"]
3224
3225    func_def = _make_interceptor_callback_def(
3226        cg_context, function_name, arg_decls, arg_names, None,
3227        "NamedPropertiesObject_IndexedPropertyDeleter")
3228    body = func_def.body
3229
3230    body.append(
3231        TextNode("""\
3232bindings::V8SetReturnValue(${info}, false);
3233if (${info}.ShouldThrowOnError()) {
3234  ExceptionState exception_state(${info}.GetIsolate(),
3235                                 ExceptionState::kIndexedDeletionContext,
3236                                 "${interface.identifier}");
3237  exception_state.ThrowTypeError("Named property deleter is not supported.");
3238}
3239"""))
3240
3241    return func_def
3242
3243
3244def make_named_props_obj_indexed_definer_callback(cg_context, function_name):
3245    assert isinstance(cg_context, CodeGenContext)
3246    assert isinstance(function_name, str)
3247
3248    arg_decls = [
3249        "uint32_t index",
3250        "const v8::PropertyDescriptor& v8_property_desc",
3251        "const v8::PropertyCallbackInfo<v8::Value>& info",
3252    ]
3253    arg_names = ["index", "v8_property_desc", "info"]
3254
3255    func_def = _make_interceptor_callback_def(
3256        cg_context, function_name, arg_decls, arg_names, None,
3257        "NamedPropertiesObject_IndexedPropertyDefiner")
3258    body = func_def.body
3259
3260    body.append(
3261        TextNode("""\
3262// 3.6.4.2. [[DefineOwnProperty]]
3263// https://heycam.github.io/webidl/#named-properties-object-defineownproperty
3264bindings::V8SetReturnValue(${info}, nullptr);
3265if (${info}.ShouldThrowOnError()) {
3266  ExceptionState exception_state(${info}.GetIsolate(),
3267                                 ExceptionState::kIndexedSetterContext,
3268                                 "${interface.identifier}");
3269  exception_state.ThrowTypeError("Named property deleter is not supported.");
3270}
3271"""))
3272
3273    return func_def
3274
3275
3276def make_named_props_obj_indexed_descriptor_callback(cg_context,
3277                                                     function_name):
3278    assert isinstance(cg_context, CodeGenContext)
3279    assert isinstance(function_name, str)
3280
3281    arg_decls = [
3282        "uint32_t index",
3283        "const v8::PropertyCallbackInfo<v8::Value>& info",
3284    ]
3285    arg_names = ["index", "info"]
3286
3287    func_def = _make_interceptor_callback_def(
3288        cg_context, function_name, arg_decls, arg_names, None,
3289        "NamedPropertiesObject_IndexedPropertyDescriptor")
3290    body = func_def.body
3291
3292    body.append(
3293        TextNode("""\
3294v8::Local<v8::String> property_name =
3295    V8AtomicString(${isolate}, AtomicString::Number(${index}));
3296NamedPropsObjNamedDescriptorCallback(property_name, ${info});
3297"""))
3298
3299    return func_def
3300
3301
3302def make_named_props_obj_named_getter_callback(cg_context, function_name):
3303    assert isinstance(cg_context, CodeGenContext)
3304    assert isinstance(function_name, str)
3305
3306    arg_decls = [
3307        "v8::Local<v8::Name> v8_property_name",
3308        "const v8::PropertyCallbackInfo<v8::Value>& info",
3309    ]
3310    arg_names = ["v8_property_name", "info"]
3311
3312    func_def = _make_interceptor_callback_def(
3313        cg_context, function_name, arg_decls, arg_names, None,
3314        "NamedPropertiesObject_NamedPropertyGetter")
3315    body = func_def.body
3316
3317    body.append(
3318        TextNode("""\
3319// 3.6.4.1. [[GetOwnProperty]]
3320// https://heycam.github.io/webidl/#named-properties-object-getownproperty
3321//
3322// TODO(yukishiino): Update the following hard-coded call to an appropriate
3323// one.
3324V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info});
3325"""))
3326
3327    return func_def
3328
3329
3330def make_named_props_obj_named_deleter_callback(cg_context, function_name):
3331    assert isinstance(cg_context, CodeGenContext)
3332    assert isinstance(function_name, str)
3333
3334    arg_decls = [
3335        "v8::Local<v8::Name> v8_property_name",
3336        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
3337    ]
3338    arg_names = ["v8_property_name", "info"]
3339
3340    func_def = _make_interceptor_callback_def(
3341        cg_context, function_name, arg_decls, arg_names, None,
3342        "NamedPropertiesObject_NamedPropertyDeleter")
3343    body = func_def.body
3344
3345    body.append(
3346        TextNode("""\
3347// 3.6.4.3. [[Delete]]
3348// https://heycam.github.io/webidl/#named-properties-object-delete
3349bindings::V8SetReturnValue(${info}, false);
3350if (${info}.ShouldThrowOnError()) {
3351  ExceptionState exception_state(${info}.GetIsolate(),
3352                                 ExceptionState::kNamedDeletionContext,
3353                                 "${interface.identifier}");
3354  exception_state.ThrowTypeError("Named property deleter is not supported.");
3355}
3356"""))
3357
3358    return func_def
3359
3360
3361def make_named_props_obj_named_definer_callback(cg_context, function_name):
3362    assert isinstance(cg_context, CodeGenContext)
3363    assert isinstance(function_name, str)
3364
3365    arg_decls = [
3366        "v8::Local<v8::Name> v8_property_name",
3367        "const v8::PropertyDescriptor& v8_property_desc",
3368        "const v8::PropertyCallbackInfo<v8::Value>& info",
3369    ]
3370    arg_names = ["v8_property_name", "v8_property_desc", "info"]
3371
3372    func_def = _make_interceptor_callback_def(
3373        cg_context, function_name, arg_decls, arg_names, None,
3374        "NamedPropertiesObject_NamedPropertyDefiner")
3375    body = func_def.body
3376
3377    body.append(
3378        TextNode("""\
3379// 3.6.4.2. [[DefineOwnProperty]]
3380// https://heycam.github.io/webidl/#named-properties-object-defineownproperty
3381bindings::V8SetReturnValue(${info}, nullptr);
3382if (${info}.ShouldThrowOnError()) {
3383  ExceptionState exception_state(${info}.GetIsolate(),
3384                                 ExceptionState::kNamedSetterContext,
3385                                 "${interface.identifier}");
3386  exception_state.ThrowTypeError("Named property setter is not supported.");
3387}
3388"""))
3389
3390    return func_def
3391
3392
3393def make_named_props_obj_named_descriptor_callback(cg_context, function_name):
3394    assert isinstance(cg_context, CodeGenContext)
3395    assert isinstance(function_name, str)
3396
3397    arg_decls = [
3398        "v8::Local<v8::Name> v8_property_name",
3399        "const v8::PropertyCallbackInfo<v8::Value>& info",
3400    ]
3401    arg_names = ["v8_property_name", "info"]
3402
3403    func_def = _make_interceptor_callback_def(
3404        cg_context, function_name, arg_decls, arg_names, None,
3405        "NamedPropertiesObject_NamedPropertyDescriptor")
3406    body = func_def.body
3407
3408    body.append(
3409        TextNode("""\
3410// 3.6.4.1. [[GetOwnProperty]]
3411// https://heycam.github.io/webidl/#named-properties-object-getownproperty
3412// step 4. If the result of running the named property visibility algorithm
3413//   with property name P and object object is true, then:
3414if (${v8_receiver}->GetRealNamedPropertyAttributesInPrototypeChain(
3415        ${current_context}, ${v8_property_name}).IsJust()) {
3416  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
3417}
3418
3419// TODO(yukishiino): Update the following hard-coded call to an appropriate
3420// one.
3421V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info});
3422v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
3423if (v8_value->IsUndefined())
3424  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
3425
3426// step 4.7. If A implements an interface with the
3427//   [LegacyUnenumerableNamedProperties] extended attribute, then set
3428//   desc.[[Enumerable]] to false, otherwise set it to true.
3429// step 4.8. Set desc.[[Writable]] to true and desc.[[Configurable]] to
3430//   true.
3431v8::PropertyDescriptor desc(v8_value, /*writable=*/true);
3432desc.set_enumerable(false);
3433desc.set_configurable(true);
3434bindings::V8SetReturnValue(${info}, desc);
3435"""))
3436
3437    return func_def
3438
3439
3440# ----------------------------------------------------------------------------
3441# Callback functions of cross origin interceptors
3442# ----------------------------------------------------------------------------
3443
3444
3445def make_cross_origin_access_check_callback(cg_context, function_name):
3446    assert isinstance(cg_context, CodeGenContext)
3447    assert isinstance(function_name, str)
3448
3449    func_def = CxxFuncDefNode(
3450        name=function_name,
3451        arg_decls=[
3452            "v8::Local<v8::Context> accessing_context",
3453            "v8::Local<v8::Object> accessed_object",
3454            "v8::Local<v8::Value> unused_data",
3455        ],
3456        return_type="bool")
3457    func_def.set_base_template_vars(cg_context.template_bindings())
3458    body = func_def.body
3459    body.add_template_var("accessing_context", "accessing_context")
3460    body.add_template_var("accessed_object", "accessed_object")
3461    bind_callback_local_vars(body, cg_context)
3462
3463    if cg_context.interface.identifier == "Window":
3464        blink_class = "DOMWindow"
3465    else:
3466        blink_class = blink_class_name(cg_context.interface)
3467    body.extend([
3468        TextNode(
3469            _format(
3470                "{blink_class}* blink_accessed_object = "
3471                "${class_name}::ToWrappableUnsafe(${accessed_object});",
3472                blink_class=blink_class)),
3473        TextNode("return BindingSecurity::ShouldAllowAccessTo("
3474                 "ToLocalDOMWindow(${accessing_context}), "
3475                 "blink_accessed_object, "
3476                 "BindingSecurity::ErrorReportOption::kDoNotReport);"),
3477    ])
3478
3479    return func_def
3480
3481
3482def make_cross_origin_indexed_getter_callback(cg_context, function_name):
3483    assert isinstance(cg_context, CodeGenContext)
3484    assert isinstance(function_name, str)
3485
3486    arg_decls = [
3487        "uint32_t index",
3488        "const v8::PropertyCallbackInfo<v8::Value>& info",
3489    ]
3490    arg_names = ["index", "info"]
3491
3492    func_def = _make_interceptor_callback_def(
3493        cg_context, function_name, arg_decls, arg_names, None,
3494        "CrossOriginProperty_IndexedPropertyGetter")
3495    body = func_def.body
3496
3497    if cg_context.interface.identifier != "Window":
3498        body.append(TextNode("${throw_security_error}"))
3499        return func_def
3500
3501    bind_return_value(body, cg_context, overriding_args=["${index}"])
3502
3503    body.extend([
3504        TextNode("""\
3505if (${index} >= ${blink_receiver}->length()) {
3506  ${throw_security_error}
3507  return;
3508}
3509"""),
3510        make_v8_set_return_value(cg_context),
3511    ])
3512
3513    return func_def
3514
3515
3516def make_cross_origin_indexed_setter_callback(cg_context, function_name):
3517    assert isinstance(cg_context, CodeGenContext)
3518    assert isinstance(function_name, str)
3519
3520    arg_decls = [
3521        "uint32_t index",
3522        "v8::Local<v8::Value> v8_property_value",
3523        "const v8::PropertyCallbackInfo<v8::Value>& info",
3524    ]
3525    arg_names = ["index", "v8_property_value", "info"]
3526
3527    func_def = _make_interceptor_callback_def(
3528        cg_context, function_name, arg_decls, arg_names, None,
3529        "CrossOriginProperty_IndexedPropertySetter")
3530    body = func_def.body
3531
3532    body.append(TextNode("${throw_security_error}"))
3533
3534    return func_def
3535
3536
3537def make_cross_origin_indexed_deleter_callback(cg_context, function_name):
3538    assert isinstance(cg_context, CodeGenContext)
3539    assert isinstance(function_name, str)
3540
3541    arg_decls = [
3542        "uint32_t index",
3543        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
3544    ]
3545    arg_names = ["index", "info"]
3546
3547    func_def = _make_interceptor_callback_def(
3548        cg_context, function_name, arg_decls, arg_names, None,
3549        "CrossOriginProperty_IndexedPropertyDeleter")
3550    body = func_def.body
3551
3552    body.append(TextNode("${throw_security_error}"))
3553
3554    return func_def
3555
3556
3557def make_cross_origin_indexed_definer_callback(cg_context, function_name):
3558    assert isinstance(cg_context, CodeGenContext)
3559    assert isinstance(function_name, str)
3560
3561    arg_decls = [
3562        "uint32_t index",
3563        "const v8::PropertyDescriptor& v8_property_desc",
3564        "const v8::PropertyCallbackInfo<v8::Value>& info",
3565    ]
3566    arg_names = ["index", "v8_property_desc", "info"]
3567
3568    func_def = _make_interceptor_callback_def(
3569        cg_context, function_name, arg_decls, arg_names, None,
3570        "CrossOriginProperty_IndexedPropertyDefiner")
3571    body = func_def.body
3572
3573    body.append(TextNode("${throw_security_error}"))
3574
3575    return func_def
3576
3577
3578def make_cross_origin_indexed_descriptor_callback(cg_context, function_name):
3579    assert isinstance(cg_context, CodeGenContext)
3580    assert isinstance(function_name, str)
3581
3582    arg_decls = [
3583        "uint32_t index",
3584        "const v8::PropertyCallbackInfo<v8::Value>& info",
3585    ]
3586    arg_names = ["index", "info"]
3587
3588    func_def = _make_interceptor_callback_def(
3589        cg_context, function_name, arg_decls, arg_names, None,
3590        "CrossOriginProperty_IndexedPropertyDescriptor")
3591    body = func_def.body
3592
3593    if cg_context.interface.identifier != "Window":
3594        body.append(TextNode("${throw_security_error}"))
3595        return func_def
3596
3597    body.append(
3598        TextNode("""\
3599CrossOriginIndexedGetterCallback(${index}, ${info});
3600v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
3601if (v8_value->IsUndefined()) {
3602  // Must have already thrown a SecurityError.
3603  return;
3604}
3605
3606v8::PropertyDescriptor desc(v8_value, /*writable=*/false);
3607desc.set_enumerable(true);
3608desc.set_configurable(true);
3609bindings::V8SetReturnValue(${info}, desc);
3610"""))
3611
3612    return func_def
3613
3614
3615def make_cross_origin_indexed_enumerator_callback(cg_context, function_name):
3616    assert isinstance(cg_context, CodeGenContext)
3617    assert isinstance(function_name, str)
3618
3619    arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
3620    arg_names = ["info"]
3621
3622    func_def = _make_interceptor_callback_def(
3623        cg_context, function_name, arg_decls, arg_names, None,
3624        "CrossOriginProperty_IndexedPropertyEnumerator")
3625    body = func_def.body
3626
3627    if cg_context.interface.identifier != "Window":
3628        return func_def
3629
3630    body.append(
3631        TextNode("""\
3632uint32_t length = ${blink_receiver}->length();
3633v8::Local<v8::Array> array =
3634    bindings::EnumerateIndexedProperties(${isolate}, length);
3635bindings::V8SetReturnValue(${info}, array);
3636"""))
3637
3638    return func_def
3639
3640
3641def make_cross_origin_named_getter_callback(cg_context, function_name):
3642    assert isinstance(cg_context, CodeGenContext)
3643    assert isinstance(function_name, str)
3644
3645    arg_decls = [
3646        "v8::Local<v8::Name> v8_property_name",
3647        "const v8::PropertyCallbackInfo<v8::Value>& info",
3648    ]
3649    arg_names = ["v8_property_name", "info"]
3650
3651    func_def = _make_interceptor_callback_def(
3652        cg_context, function_name, arg_decls, arg_names, None,
3653        "CrossOriginProperty_NamedPropertyGetter")
3654    body = func_def.body
3655
3656    string_case_body = []
3657    string_case_body.append(
3658        TextNode("""\
3659for (const auto& attribute : kCrossOriginAttributeTable) {
3660  if (${blink_property_name} != attribute.name)
3661    continue;
3662  if (UNLIKELY(!attribute.get_value)) {
3663    ${throw_security_error}
3664    return;
3665  }
3666  attribute.get_value(${v8_property_name}, ${info});
3667  return;
3668}
3669for (const auto& operation : kCrossOriginOperationTable) {
3670  if (${blink_property_name} != operation.name)
3671    continue;
3672  v8::Local<v8::Function> function;
3673  if (bindings::GetCrossOriginFunction(
3674          ${info}.GetIsolate(), operation.callback, operation.func_length,
3675          ${class_name}::GetWrapperTypeInfo())
3676          .ToLocal(&function)) {
3677    bindings::V8SetReturnValue(${info}, function);
3678  }
3679  return;
3680}
3681"""))
3682    if cg_context.interface.identifier == "Window":
3683        string_case_body.append(
3684            TextNode("""\
3685// Window object's document-tree child browsing context name property set
3686//
3687// TODO(yukishiino): Update the following hard-coded call to an appropriate
3688// one.
3689V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info});
3690if (!${info}.GetReturnValue().Get()->IsUndefined())
3691  return;
3692"""))
3693
3694    body.extend([
3695        CxxLikelyIfNode(
3696            cond="${v8_property_name}->IsString()", body=string_case_body),
3697        EmptyNode(),
3698        TextNode("""\
3699// 7.2.3.2 CrossOriginPropertyFallback ( P )
3700// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-)
3701if (bindings::IsSupportedInCrossOriginPropertyFallback(
3702        ${info}.GetIsolate(), ${v8_property_name})) {
3703  return ${info}.GetReturnValue().SetUndefined();
3704}
3705${throw_security_error}
3706"""),
3707    ])
3708
3709    return func_def
3710
3711
3712def make_cross_origin_named_setter_callback(cg_context, function_name):
3713    assert isinstance(cg_context, CodeGenContext)
3714    assert isinstance(function_name, str)
3715
3716    arg_decls = [
3717        "v8::Local<v8::Name> v8_property_name",
3718        "v8::Local<v8::Value> v8_property_value",
3719        "const v8::PropertyCallbackInfo<v8::Value>& info",
3720    ]
3721    arg_names = ["v8_property_name", "v8_property_value", "info"]
3722
3723    func_def = _make_interceptor_callback_def(
3724        cg_context, function_name, arg_decls, arg_names, None,
3725        "CrossOriginProperty_NamedPropertySetter")
3726    body = func_def.body
3727
3728    string_case_body = []
3729    string_case_body.append(
3730        TextNode("""\
3731for (const auto& attribute : kCrossOriginAttributeTable) {
3732  if (${blink_property_name} == attribute.name && attribute.set_value) {
3733    attribute.set_value(${v8_property_name}, ${v8_property_value}, ${info});
3734    return;
3735  }
3736}
3737"""))
3738
3739    body.extend([
3740        CxxLikelyIfNode(
3741            cond="${v8_property_name}->IsString()", body=string_case_body),
3742        EmptyNode(),
3743        TextNode("${throw_security_error}"),
3744    ])
3745
3746    return func_def
3747
3748
3749def make_cross_origin_named_deleter_callback(cg_context, function_name):
3750    assert isinstance(cg_context, CodeGenContext)
3751    assert isinstance(function_name, str)
3752
3753    arg_decls = [
3754        "v8::Local<v8::Name> v8_property_name",
3755        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
3756    ]
3757    arg_names = ["v8_property_name", "info"]
3758
3759    func_def = _make_interceptor_callback_def(
3760        cg_context, function_name, arg_decls, arg_names, None,
3761        "CrossOriginProperty_NamedPropertyDeleter")
3762    body = func_def.body
3763
3764    body.append(TextNode("${throw_security_error}"))
3765
3766    return func_def
3767
3768
3769def make_cross_origin_named_definer_callback(cg_context, function_name):
3770    assert isinstance(cg_context, CodeGenContext)
3771    assert isinstance(function_name, str)
3772
3773    arg_decls = [
3774        "v8::Local<v8::Name> v8_property_name",
3775        "const v8::PropertyDescriptor& v8_property_desc",
3776        "const v8::PropertyCallbackInfo<v8::Value>& info",
3777    ]
3778    arg_names = ["v8_property_name", "v8_property_desc", "info"]
3779
3780    func_def = _make_interceptor_callback_def(
3781        cg_context, function_name, arg_decls, arg_names, None,
3782        "CrossOriginProperty_NamedPropertyDefiner")
3783    body = func_def.body
3784
3785    body.append(TextNode("${throw_security_error}"))
3786
3787    return func_def
3788
3789
3790def make_cross_origin_named_descriptor_callback(cg_context, function_name):
3791    assert isinstance(cg_context, CodeGenContext)
3792    assert isinstance(function_name, str)
3793
3794    arg_decls = [
3795        "v8::Local<v8::Name> v8_property_name",
3796        "const v8::PropertyCallbackInfo<v8::Value>& info",
3797    ]
3798    arg_names = ["v8_property_name", "info"]
3799
3800    func_def = _make_interceptor_callback_def(
3801        cg_context, function_name, arg_decls, arg_names, None,
3802        "CrossOriginProperty_NamedPropertyDescriptor")
3803    body = func_def.body
3804
3805    string_case_body = []
3806    string_case_body.append(
3807        TextNode("""\
3808// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P )
3809// https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-)
3810for (const auto& attribute : kCrossOriginAttributeTable) {
3811  if (${blink_property_name} != attribute.name)
3812    continue;
3813  v8::Local<v8::Value> get;
3814  v8::Local<v8::Value> set;
3815  if (!bindings::GetCrossOriginFunctionOrUndefined(
3816           ${info}.GetIsolate(), attribute.get_callback, 0,
3817           ${class_name}::GetWrapperTypeInfo())
3818           .ToLocal(&get) ||
3819      !bindings::GetCrossOriginFunctionOrUndefined(
3820           ${info}.GetIsolate(), attribute.set_callback, 1,
3821           ${class_name}::GetWrapperTypeInfo())
3822           .ToLocal(&set)) {
3823    return;
3824  }
3825  v8::PropertyDescriptor desc(get, set);
3826  desc.set_enumerable(false);
3827  desc.set_configurable(true);
3828  bindings::V8SetReturnValue(${info}, desc);
3829  return;
3830}
3831for (const auto& operation : kCrossOriginOperationTable) {
3832  if (${blink_property_name} != operation.name)
3833    continue;
3834  v8::Local<v8::Function> function;
3835  if (!bindings::GetCrossOriginFunction(
3836           ${info}.GetIsolate(), operation.callback, operation.func_length,
3837           ${class_name}::GetWrapperTypeInfo())
3838           .ToLocal(&function)) {
3839    return;
3840  }
3841  v8::PropertyDescriptor desc(function, /*writable=*/false);
3842  desc.set_enumerable(false);
3843  desc.set_configurable(true);
3844  bindings::V8SetReturnValue(${info}, desc);
3845  return;
3846}
3847"""))
3848    if cg_context.interface.identifier == "Window":
3849        string_case_body.append(
3850            TextNode("""\
3851// Window object's document-tree child browsing context name property set
3852//
3853// TODO(yukishiino): Update the following hard-coded call to an appropriate
3854// one.
3855V8Window::NamedPropertyGetterCustom(${blink_property_name}, ${info});
3856if (!${info}.GetReturnValue().Get()->IsUndefined()) {
3857  v8::PropertyDescriptor desc(${info}.GetReturnValue().Get(),
3858                              /*writable=*/false);
3859  desc.set_enumerable(false);
3860  desc.set_configurable(true);
3861  bindings::V8SetReturnValue(${info}, desc);
3862  return;
3863}
3864"""))
3865
3866    body.extend([
3867        CxxLikelyIfNode(
3868            cond="${v8_property_name}->IsString()", body=string_case_body),
3869        EmptyNode(),
3870        TextNode("""\
3871// 7.2.3.2 CrossOriginPropertyFallback ( P )
3872// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-)
3873if (bindings::IsSupportedInCrossOriginPropertyFallback(
3874        ${info}.GetIsolate(), ${v8_property_name})) {
3875  v8::PropertyDescriptor desc(v8::Undefined(${info}.GetIsolate()),
3876                              /*writable=*/false);
3877  desc.set_enumerable(false);
3878  desc.set_configurable(true);
3879  bindings::V8SetReturnValue(${info}, desc);
3880  return;
3881}
3882${throw_security_error}
3883"""),
3884    ])
3885
3886    return func_def
3887
3888
3889def make_cross_origin_named_query_callback(cg_context, function_name):
3890    assert isinstance(cg_context, CodeGenContext)
3891    assert isinstance(function_name, str)
3892
3893    arg_decls = [
3894        "v8::Local<v8::Name> v8_property_name",
3895        "const v8::PropertyCallbackInfo<v8::Integer>& info",
3896    ]
3897    arg_names = ["v8_property_name", "info"]
3898
3899    func_def = _make_interceptor_callback_def(
3900        cg_context, function_name, arg_decls, arg_names, None,
3901        "CrossOriginProperty_NamedPropertyQuery")
3902    body = func_def.body
3903
3904    string_case_body = []
3905    string_case_body.append(
3906        TextNode("""\
3907// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P )
3908// https://html.spec.whatwg.org/C/#crossorigingetownpropertyhelper-(-o,-p-)
3909for (const auto& attribute : kCrossOriginAttributeTable) {
3910  if (${blink_property_name} != attribute.name)
3911    continue;
3912  int32_t v8_property_attribute = v8::DontEnum;
3913  if (!attribute.set_callback)
3914    v8_property_attribute |= v8::ReadOnly;
3915  bindings::V8SetReturnValue(${info}, v8_property_attribute);
3916  return;
3917}
3918for (const auto& operation : kCrossOriginOperationTable) {
3919  if (${blink_property_name} != operation.name)
3920    continue;
3921  int32_t v8_property_attribute = v8::DontEnum | v8::ReadOnly;
3922  bindings::V8SetReturnValue(${info}, v8_property_attribute);
3923  return;
3924}
3925"""))
3926
3927    body.extend([
3928        CxxLikelyIfNode(
3929            cond="${v8_property_name}->IsString()", body=string_case_body),
3930        EmptyNode(),
3931        TextNode("""\
3932// 7.2.3.2 CrossOriginPropertyFallback ( P )
3933// https://html.spec.whatwg.org/C/#crossoriginpropertyfallback-(-p-)
3934if (bindings::IsSupportedInCrossOriginPropertyFallback(
3935        ${info}.GetIsolate(), ${v8_property_name})) {
3936  int32_t v8_property_attribute = v8::DontEnum | v8::ReadOnly;
3937  bindings::V8SetReturnValue(${info}, v8_property_attribute);
3938  return;
3939}
3940"""),
3941    ])
3942
3943    return func_def
3944
3945
3946def make_cross_origin_named_enumerator_callback(cg_context, function_name):
3947    assert isinstance(cg_context, CodeGenContext)
3948    assert isinstance(function_name, str)
3949
3950    arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
3951    arg_names = ["info"]
3952
3953    func_def = _make_interceptor_callback_def(
3954        cg_context, function_name, arg_decls, arg_names, None,
3955        "CrossOriginProperty_NamedPropertyEnumerator")
3956    body = func_def.body
3957
3958    body.append(
3959        TextNode("""\
3960bindings::V8SetReturnValue(
3961    ${info},
3962    bindings::EnumerateCrossOriginProperties(
3963        ${isolate},
3964        kCrossOriginAttributeTable,
3965        kCrossOriginOperationTable));
3966"""))
3967
3968    return func_def
3969
3970
3971# ----------------------------------------------------------------------------
3972# Callback functions of same origin interceptors
3973# ----------------------------------------------------------------------------
3974
3975
3976def make_same_origin_indexed_getter_callback(cg_context, function_name):
3977    assert isinstance(cg_context, CodeGenContext)
3978    assert isinstance(function_name, str)
3979
3980    arg_decls = [
3981        "uint32_t index",
3982        "const v8::PropertyCallbackInfo<v8::Value>& info",
3983    ]
3984    arg_names = ["index", "info"]
3985
3986    func_def = _make_interceptor_callback_def(
3987        cg_context, function_name, arg_decls, arg_names, None,
3988        "SameOriginProperty_IndexedPropertyGetter")
3989    body = func_def.body
3990
3991    bind_return_value(body, cg_context, overriding_args=["${index}"])
3992
3993    body.extend([
3994        TextNode("""\
3995if (${index} >= ${blink_receiver}->length()) {
3996  return;
3997}
3998"""),
3999        make_v8_set_return_value(cg_context),
4000    ])
4001
4002    return func_def
4003
4004
4005def make_same_origin_indexed_setter_callback(cg_context, function_name):
4006    assert isinstance(cg_context, CodeGenContext)
4007    assert isinstance(function_name, str)
4008
4009    arg_decls = [
4010        "uint32_t index",
4011        "v8::Local<v8::Value> v8_property_value",
4012        "const v8::PropertyCallbackInfo<v8::Value>& info",
4013    ]
4014    arg_names = ["index", "v8_property_value", "info"]
4015
4016    func_def = _make_interceptor_callback_def(
4017        cg_context, function_name, arg_decls, arg_names, None,
4018        "SameOriginProperty_IndexedPropertySetter")
4019    body = func_def.body
4020
4021    body.append(
4022        TextNode("""\
4023bindings::V8SetReturnValue(${info}, nullptr);
4024if (${info}.ShouldThrowOnError()) {
4025  ExceptionState exception_state(${info}.GetIsolate(),
4026                                 ExceptionState::kIndexedSetterContext,
4027                                 "${interface.identifier}");
4028  exception_state.ThrowTypeError(
4029      "Indexed property setter is not supported.");
4030}
4031"""))
4032
4033    return func_def
4034
4035
4036def make_same_origin_indexed_deleter_callback(cg_context, function_name):
4037    assert isinstance(cg_context, CodeGenContext)
4038    assert isinstance(function_name, str)
4039
4040    arg_decls = [
4041        "uint32_t index",
4042        "const v8::PropertyCallbackInfo<v8::Boolean>& info",
4043    ]
4044    arg_names = ["index", "info"]
4045
4046    func_def = _make_interceptor_callback_def(
4047        cg_context, function_name, arg_decls, arg_names, None,
4048        "SameOriginProperty_IndexedPropertyDeleter")
4049    body = func_def.body
4050
4051    body.append(
4052        TextNode("""\
4053// 7.4.9 [[Delete]] ( P )
4054// https://html.spec.whatwg.org/C/#windowproxy-delete
4055const bool is_supported = ${index} < ${blink_receiver}->length();
4056bindings::V8SetReturnValue(${info}, !is_supported);
4057if (is_supported and ${info}.ShouldThrowOnError()) {
4058  ExceptionState exception_state(${info}.GetIsolate(),
4059                                 ExceptionState::kIndexedDeletionContext,
4060                                 "${interface.identifier}");
4061  exception_state.ThrowTypeError("Index property deleter is not supported.");
4062}
4063"""))
4064
4065    return func_def
4066
4067
4068def make_same_origin_indexed_definer_callback(cg_context, function_name):
4069    assert isinstance(cg_context, CodeGenContext)
4070    assert isinstance(function_name, str)
4071
4072    arg_decls = [
4073        "uint32_t index",
4074        "const v8::PropertyDescriptor& v8_property_desc",
4075        "const v8::PropertyCallbackInfo<v8::Value>& info",
4076    ]
4077    arg_names = ["index", "v8_property_desc", "info"]
4078
4079    func_def = _make_interceptor_callback_def(
4080        cg_context, function_name, arg_decls, arg_names, None,
4081        "SameOriginProperty_IndexedPropertyDefiner")
4082    body = func_def.body
4083
4084    body.append(
4085        TextNode("""\
4086// 7.4.6 [[DefineOwnProperty]] ( P, Desc )
4087// https://html.spec.whatwg.org/C/#windowproxy-defineownproperty
4088bindings::V8SetReturnValue(${info}, nullptr);
4089if (${info}.ShouldThrowOnError()) {
4090  ExceptionState exception_state(${info}.GetIsolate(),
4091                                 ExceptionState::kIndexedSetterContext,
4092                                 "${interface.identifier}");
4093  exception_state.ThrowTypeError("Index property setter is not supported.");
4094}
4095"""))
4096
4097    return func_def
4098
4099
4100def make_same_origin_indexed_descriptor_callback(cg_context, function_name):
4101    assert isinstance(cg_context, CodeGenContext)
4102    assert isinstance(function_name, str)
4103
4104    arg_decls = [
4105        "uint32_t index",
4106        "const v8::PropertyCallbackInfo<v8::Value>& info",
4107    ]
4108    arg_names = ["index", "info"]
4109
4110    func_def = _make_interceptor_callback_def(
4111        cg_context, function_name, arg_decls, arg_names, None,
4112        "SameOriginProperty_IndexedPropertyDescriptor")
4113    body = func_def.body
4114
4115    body.append(
4116        TextNode("""\
4117// 7.4.5 [[GetOwnProperty]] ( P )
4118// https://html.spec.whatwg.org/C/#windowproxy-getownproperty
4119SameOriginIndexedGetterCallback(${index}, ${info});
4120v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
4121if (v8_value->IsUndefined()) {
4122  return;  // Do not intercept.
4123}
4124
4125v8::PropertyDescriptor desc(v8_value, /*writable=*/false);
4126desc.set_enumerable(true);
4127desc.set_configurable(true);
4128bindings::V8SetReturnValue(${info}, desc);
4129"""))
4130
4131    return func_def
4132
4133
4134def make_same_origin_indexed_enumerator_callback(cg_context, function_name):
4135    assert isinstance(cg_context, CodeGenContext)
4136    assert isinstance(function_name, str)
4137
4138    arg_decls = ["const v8::PropertyCallbackInfo<v8::Array>& info"]
4139    arg_names = ["info"]
4140
4141    func_def = _make_interceptor_callback_def(
4142        cg_context, function_name, arg_decls, arg_names, None,
4143        "SameOriginProperty_IndexedPropertyEnumerator")
4144    body = func_def.body
4145
4146    body.append(
4147        TextNode("""\
4148uint32_t length = ${blink_receiver}->length();
4149v8::Local<v8::Array> array =
4150    bindings::EnumerateIndexedProperties(${isolate}, length);
4151bindings::V8SetReturnValue(${info}, array);
4152"""))
4153
4154    return func_def
4155
4156
4157# ----------------------------------------------------------------------------
4158# Installer functions
4159# ----------------------------------------------------------------------------
4160
4161# FN = function name
4162FN_INSTALL_INTERFACE_TEMPLATE = name_style.func("InstallInterfaceTemplate")
4163FN_INSTALL_UNCONDITIONAL_PROPS = name_style.func(
4164    "InstallUnconditionalProperties")
4165FN_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.func(
4166    "InstallContextIndependentProperties")
4167FN_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.func(
4168    "InstallContextDependentProperties")
4169
4170# TP = trampoline name
4171TP_INSTALL_INTERFACE_TEMPLATE = name_style.member_var(
4172    "install_interface_template_func")
4173TP_INSTALL_UNCONDITIONAL_PROPS = name_style.member_var(
4174    "install_unconditional_props_func")
4175TP_INSTALL_CONTEXT_INDEPENDENT_PROPS = name_style.member_var(
4176    "install_context_independent_props_func")
4177TP_INSTALL_CONTEXT_DEPENDENT_PROPS = name_style.member_var(
4178    "install_context_dependent_props_func")
4179
4180
4181def bind_installer_local_vars(code_node, cg_context):
4182    assert isinstance(code_node, SymbolScopeNode)
4183    assert isinstance(cg_context, CodeGenContext)
4184
4185    S = SymbolNode
4186
4187    local_vars = []
4188
4189    local_vars.extend([
4190        S("is_in_secure_context",
4191          ("const bool ${is_in_secure_context} = "
4192           "${execution_context}->IsSecureContext();")),
4193        S("isolate", "v8::Isolate* ${isolate} = ${v8_context}->GetIsolate();"),
4194        S("script_state",
4195          "ScriptState* ${script_state} = ScriptState::From(${v8_context});"),
4196        S("wrapper_type_info",
4197          ("const WrapperTypeInfo* const ${wrapper_type_info} = "
4198           "${class_name}::GetWrapperTypeInfo();")),
4199    ])
4200
4201    if cg_context.interface:
4202        local_vars.extend([
4203            S("interface_function_template",
4204              ("v8::Local<v8::FunctionTemplate> "
4205               "${interface_function_template} = "
4206               "${interface_template}.As<v8::FunctionTemplate>();")),
4207            S("instance_object_template",
4208              ("v8::Local<v8::ObjectTemplate> ${instance_object_template} = "
4209               "${interface_function_template}->InstanceTemplate();")),
4210            S("instance_template",
4211              ("v8::Local<v8::Template> ${instance_template} = "
4212               "${instance_object_template};")),
4213            S("prototype_object_template",
4214              ("v8::Local<v8::ObjectTemplate> ${prototype_object_template} = "
4215               "${interface_function_template}->PrototypeTemplate();")),
4216            S("prototype_template",
4217              ("v8::Local<v8::Template> ${prototype_template} = "
4218               "${prototype_object_template};")),
4219            S("signature", ("v8::Local<v8::Signature> ${signature} = "
4220                            "v8::Signature::New(${isolate}, "
4221                            "${interface_function_template});")),
4222        ])
4223    elif cg_context.namespace:
4224        local_vars.extend([
4225            S("namespace_object_template",
4226              ("v8::Local<v8::ObjectTemplate> "
4227               "${namespace_object_template} = "
4228               "${interface_template}.As<v8::ObjectTemplate>();")),
4229            S("instance_template",
4230              "v8::Local<v8::Template> ${instance_template};"),
4231            S("prototype_template",
4232              "v8::Local<v8::Template> ${prototype_template};"),
4233            S("signature", "v8::Local<v8::Signature> ${signature};"),
4234        ])
4235    elif cg_context.callback_interface:
4236        local_vars.extend([
4237            S("interface_function_template",
4238              ("v8::Local<v8::FunctionTemplate> "
4239               "${interface_function_template} = "
4240               "${interface_template}.As<v8::FunctionTemplate>();")),
4241            S("instance_template",
4242              "v8::Local<v8::Template> ${instance_template};"),
4243            S("prototype_template",
4244              "v8::Local<v8::Template> ${prototype_template};"),
4245            S("signature", "v8::Local<v8::Signature> ${signature};"),
4246        ])
4247
4248    # context_feature_settings
4249    node = S("context_feature_settings",
4250             ("const ContextFeatureSettings* ${context_feature_settings} = "
4251              "ContextFeatureSettings::From("
4252              "${execution_context}, "
4253              "ContextFeatureSettings::CreationMode::kDontCreateIfNotExists"
4254              ");"))
4255    node.accumulate(
4256        CodeGenAccumulator.require_include_headers([
4257            "third_party/blink/renderer/core/context_features/context_feature_settings.h"
4258        ]))
4259    local_vars.append(node)
4260
4261    # execution_context
4262    node = S("execution_context", ("ExecutionContext* ${execution_context} = "
4263                                   "ExecutionContext::From(${script_state});"))
4264    node.accumulate(
4265        CodeGenAccumulator.require_include_headers([
4266            "third_party/blink/renderer/core/execution_context/execution_context.h"
4267        ]))
4268    local_vars.append(node)
4269
4270    # parent_interface_template
4271    pattern = (
4272        "v8::Local<v8::FunctionTemplate> ${parent_interface_template}{_1};")
4273    interface = cg_context.interface
4274    if not interface:
4275        _1 = ""
4276    elif (interface and "Global" in interface.extended_attributes
4277          and interface.indexed_and_named_properties
4278          and interface.indexed_and_named_properties.has_named_properties):
4279        # https://heycam.github.io/webidl/#named-properties-object
4280        _1 = " = ${npo_interface_template}"  # npo = named properties object
4281    elif interface.inherited:
4282        _1 = (" = ${wrapper_type_info}->parent_class"
4283              "->GetV8ClassTemplate(${isolate}, ${world})"
4284              ".As<v8::FunctionTemplate>()")
4285    else:
4286        _1 = ""
4287    local_vars.append(S("parent_interface_template", _format(pattern, _1=_1)))
4288
4289    # npo_interface_template
4290    # npo = named properties object
4291    text = """\
4292// Named properties object
4293v8::Local<v8::FunctionTemplate> ${npo_interface_template} =
4294    v8::FunctionTemplate::New(${isolate});
4295v8::Local<v8::ObjectTemplate> ${npo_prototype_template} =
4296    ${npo_interface_template}->PrototypeTemplate();
4297${npo_interface_template}->Inherit(
4298    ${wrapper_type_info}->parent_class
4299    ->GetV8ClassTemplate(${isolate}, ${world}).As<v8::FunctionTemplate>());
4300${npo_prototype_template}->SetImmutableProto();
4301${npo_prototype_template}->Set(
4302    v8::Symbol::GetToStringTag(${isolate}),
4303    V8AtomicString(${isolate}, "${interface.identifier}Properties"),
4304    static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum));
4305// Make the named properties object look like the global object.  Note that
4306// the named properties object is _not_ a prototype object, plus, we'd like
4307// the named properties object to behave just like the global object (= the
4308// wrapper object of the global object) from the point of view of named
4309// properties.
4310// https://heycam.github.io/webidl/#named-properties-object
4311${npo_prototype_template}->SetInternalFieldCount(
4312    kV8DefaultWrapperInternalFieldCount);
4313"""
4314    local_vars.append(S("npo_interface_template", text))
4315    local_vars.append(
4316        S("npo_prototype_template",
4317          "<% npo_interface_template.request_symbol_definition() %>"))
4318
4319    # Arguments have priority over local vars.
4320    template_vars = code_node.template_vars
4321    for symbol_node in local_vars:
4322        if symbol_node.name not in template_vars:
4323            code_node.register_code_symbol(symbol_node)
4324
4325
4326def _make_property_entry_cross_origin_check(property_,
4327                                            is_get=False,
4328                                            is_set=False):
4329    constants = {
4330        False: "unsigned(IDLMemberInstaller::FlagCrossOriginCheck::kCheck)",
4331        True:
4332        "unsigned(IDLMemberInstaller::FlagCrossOriginCheck::kDoNotCheck)",
4333    }
4334    if property_.is_static:
4335        return constants[True]
4336    if "CrossOrigin" not in property_.extended_attributes:
4337        return constants[False]
4338    values = property_.extended_attributes.values_of("CrossOrigin")
4339    if is_get:
4340        return constants[not values or "Getter" in values]
4341    elif is_set:
4342        return constants["Setter" in values]
4343    else:
4344        return constants[True]
4345
4346
4347def _make_property_entry_location(property_):
4348    if hasattr(property_, "is_static") and property_.is_static:
4349        return "unsigned(IDLMemberInstaller::FlagLocation::kInterface)"
4350    if "Global" in property_.owner.extended_attributes:
4351        return "unsigned(IDLMemberInstaller::FlagLocation::kInstance)"
4352    if "LegacyUnforgeable" in property_.extended_attributes:
4353        return "unsigned(IDLMemberInstaller::FlagLocation::kInstance)"
4354    return "unsigned(IDLMemberInstaller::FlagLocation::kPrototype)"
4355
4356
4357def _make_property_entry_receiver_check(property_):
4358    if ("LegacyLenientThis" in property_.extended_attributes
4359            or property_.is_static
4360            or (isinstance(property_, web_idl.Attribute)
4361                and property_.idl_type.unwrap().is_promise)
4362            or (isinstance(property_, web_idl.OverloadGroup)
4363                and property_[0].return_type.unwrap().is_promise)):
4364        return "unsigned(IDLMemberInstaller::FlagReceiverCheck::kDoNotCheck)"
4365    else:
4366        return "unsigned(IDLMemberInstaller::FlagReceiverCheck::kCheck)"
4367
4368
4369def _make_property_entry_v8_c_function(entry):
4370    if entry.no_alloc_direct_callback_name is None:
4371        return None
4372    return "v8::CFunction::MakeWithFallbackSupport({})".format(
4373        entry.no_alloc_direct_callback_name)
4374
4375
4376def _make_property_entry_v8_cached_accessor(property_):
4377    return "unsigned(V8PrivateProperty::CachedAccessor::{})".format(
4378        property_.extended_attributes.value_of("CachedAccessor") or "kNone")
4379
4380
4381def _make_property_entry_v8_property_attribute(property_):
4382    values = []
4383    if "NotEnumerable" in property_.extended_attributes:
4384        values.append("v8::DontEnum")
4385    if "LegacyUnforgeable" in property_.extended_attributes:
4386        if not isinstance(property_, web_idl.Attribute):
4387            values.append("v8::ReadOnly")
4388        values.append("v8::DontDelete")
4389    if not values:
4390        values.append("v8::None")
4391    if len(values) == 1:
4392        return "unsigned({})".format(values[0])
4393    else:
4394        return "unsigned({})".format(" | ".join(values))
4395
4396
4397def _make_property_entry_v8_side_effect(property_):
4398    if property_.extended_attributes.value_of("Affects") == "Nothing":
4399        return "unsigned(v8::SideEffectType::kHasNoSideEffect)"
4400    else:
4401        return "unsigned(v8::SideEffectType::kHasSideEffect)"
4402
4403
4404def _make_property_entry_world(world):
4405    if world == CodeGenContext.MAIN_WORLD:
4406        return "unsigned(IDLMemberInstaller::FlagWorld::kMainWorld)"
4407    if world == CodeGenContext.NON_MAIN_WORLDS:
4408        return "unsigned(IDLMemberInstaller::FlagWorld::kNonMainWorlds)"
4409    if world == CodeGenContext.ALL_WORLDS:
4410        return "unsigned(IDLMemberInstaller::FlagWorld::kAllWorlds)"
4411    assert False
4412
4413
4414def _make_attribute_registration_table(table_name, attribute_entries):
4415    assert isinstance(table_name, str)
4416    assert isinstance(attribute_entries, (list, tuple))
4417    assert all(
4418        isinstance(entry, _PropEntryAttribute) for entry in attribute_entries)
4419
4420    T = TextNode
4421
4422    entry_nodes = []
4423    for entry in attribute_entries:
4424        pattern = ("{{"
4425                   "\"{property_name}\", "
4426                   "{attribute_get_callback}, "
4427                   "{attribute_set_callback}, "
4428                   "{v8_property_attribute}, "
4429                   "{location}, "
4430                   "{world}, "
4431                   "{receiver_check}, "
4432                   "{cross_origin_check_for_get}, "
4433                   "{cross_origin_check_for_set}, "
4434                   "{v8_side_effect}, "
4435                   "{v8_cached_accessor}"
4436                   "}},")
4437        text = _format(
4438            pattern,
4439            property_name=entry.property_.identifier,
4440            attribute_get_callback=entry.attr_get_callback_name,
4441            attribute_set_callback=(entry.attr_set_callback_name or "nullptr"),
4442            v8_property_attribute=_make_property_entry_v8_property_attribute(
4443                entry.property_),
4444            location=_make_property_entry_location(entry.property_),
4445            world=_make_property_entry_world(entry.world),
4446            receiver_check=_make_property_entry_receiver_check(
4447                entry.property_),
4448            cross_origin_check_for_get=(
4449                _make_property_entry_cross_origin_check(entry.property_,
4450                                                        is_get=True)),
4451            cross_origin_check_for_set=(
4452                _make_property_entry_cross_origin_check(entry.property_,
4453                                                        is_set=True)),
4454            v8_side_effect=_make_property_entry_v8_side_effect(
4455                entry.property_),
4456            v8_cached_accessor=_make_property_entry_v8_cached_accessor(
4457                entry.property_))
4458        entry_nodes.append(T(text))
4459
4460    return ListNode([
4461        T("static const IDLMemberInstaller::AttributeConfig " + table_name +
4462          "[] = {"),
4463        ListNode(entry_nodes),
4464        T("};"),
4465    ])
4466
4467
4468def _make_constant_callback_registration_table(table_name, constant_entries):
4469    assert isinstance(table_name, str)
4470    assert isinstance(constant_entries, (list, tuple))
4471    assert all(
4472        isinstance(entry, _PropEntryConstant)
4473        and isinstance(entry.const_callback_name, str)
4474        for entry in constant_entries)
4475
4476    T = TextNode
4477
4478    entry_nodes = []
4479    for entry in constant_entries:
4480        pattern = ("{{" "\"{property_name}\", " "{constant_callback}" "}},")
4481        text = _format(
4482            pattern,
4483            property_name=entry.property_.identifier,
4484            constant_callback=entry.const_callback_name)
4485        entry_nodes.append(T(text))
4486
4487    return ListNode([
4488        T("static const IDLMemberInstaller::ConstantCallbackConfig " +
4489          table_name + "[] = {"),
4490        ListNode(entry_nodes),
4491        T("};"),
4492    ])
4493
4494
4495def _make_constant_value_registration_table(table_name, constant_entries):
4496    assert isinstance(table_name, str)
4497    assert isinstance(constant_entries, (list, tuple))
4498    assert all(
4499        isinstance(entry, _PropEntryConstant)
4500        and entry.const_callback_name is None for entry in constant_entries)
4501
4502    T = TextNode
4503
4504    entry_nodes = []
4505    for entry in constant_entries:
4506        pattern = ("{{"
4507                   "\"{property_name}\", "
4508                   "{constant_value}"
4509                   "}},")
4510        text = _format(pattern,
4511                       property_name=entry.property_.identifier,
4512                       constant_value=entry.const_constant_name)
4513        entry_nodes.append(T(text))
4514
4515    return ListNode([
4516        T("static const IDLMemberInstaller::ConstantValueConfig " +
4517          table_name + "[] = {"),
4518        ListNode(entry_nodes),
4519        T("};"),
4520    ])
4521
4522
4523def _make_exposed_construct_registration_table(table_name,
4524                                               exposed_construct_entries):
4525    assert isinstance(table_name, str)
4526    assert isinstance(exposed_construct_entries, (list, tuple))
4527    assert all(
4528        isinstance(entry, _PropEntryExposedConstruct)
4529        for entry in exposed_construct_entries)
4530
4531    T = TextNode
4532
4533    entry_nodes = []
4534    for entry in exposed_construct_entries:
4535        pattern = ("{{"
4536                   "\"{property_name}\", "
4537                   "{exposed_construct_callback}"
4538                   "}}, ")
4539        text = _format(pattern,
4540                       property_name=entry.property_.identifier,
4541                       exposed_construct_callback=entry.prop_callback_name)
4542        entry_nodes.append(T(text))
4543
4544    return ListNode([
4545        T("static const IDLMemberInstaller::ExposedConstructConfig " +
4546          table_name + "[] = {"),
4547        ListNode(entry_nodes),
4548        T("};"),
4549    ])
4550
4551
4552def _make_operation_registration_table(table_name, operation_entries):
4553    assert isinstance(table_name, str)
4554    assert isinstance(operation_entries, (list, tuple))
4555    assert all(
4556        isinstance(entry, _PropEntryOperationGroup)
4557        for entry in operation_entries)
4558
4559    T = TextNode
4560
4561    no_alloc_direct_call_count = 0
4562    for entry in operation_entries:
4563        if entry.no_alloc_direct_callback_name:
4564            no_alloc_direct_call_count += 1
4565    assert (no_alloc_direct_call_count == 0
4566            or no_alloc_direct_call_count == len(operation_entries))
4567    no_alloc_direct_call_enabled = no_alloc_direct_call_count > 0
4568
4569    entry_nodes = []
4570    for entry in operation_entries:
4571        pattern = ("{{"
4572                   "\"{property_name}\", "
4573                   "{operation_callback}, "
4574                   "{function_length}, "
4575                   "{v8_property_attribute}, "
4576                   "{location}, "
4577                   "{world}, "
4578                   "{receiver_check}, "
4579                   "{cross_origin_check}, "
4580                   "{v8_side_effect}"
4581                   "}}, ")
4582        if no_alloc_direct_call_enabled:
4583            pattern = "{{" + pattern + "{v8_c_function}}}, "
4584        text = _format(
4585            pattern,
4586            property_name=entry.property_.identifier,
4587            operation_callback=entry.op_callback_name,
4588            function_length=entry.op_func_length,
4589            v8_property_attribute=_make_property_entry_v8_property_attribute(
4590                entry.property_),
4591            location=_make_property_entry_location(entry.property_),
4592            world=_make_property_entry_world(entry.world),
4593            receiver_check=_make_property_entry_receiver_check(
4594                entry.property_),
4595            cross_origin_check=_make_property_entry_cross_origin_check(
4596                entry.property_),
4597            v8_side_effect=_make_property_entry_v8_side_effect(
4598                entry.property_),
4599            v8_c_function=_make_property_entry_v8_c_function(entry))
4600        entry_nodes.append(T(text))
4601
4602    table_decl_before_name = (
4603        "static const IDLMemberInstaller::OperationConfig")
4604    if no_alloc_direct_call_enabled:
4605        table_decl_before_name = (
4606            "static const "
4607            "IDLMemberInstaller::NoAllocDirectCallOperationConfig")
4608    return ListNode([
4609        T(table_decl_before_name + " " + table_name + "[] = {"),
4610        ListNode(entry_nodes),
4611        T("};"),
4612    ])
4613
4614
4615class _PropEntryBase(object):
4616    def __init__(self, is_context_dependent, exposure_conditional, world,
4617                 property_):
4618        assert isinstance(is_context_dependent, bool)
4619        assert isinstance(exposure_conditional, CodeGenExpr)
4620
4621        self.is_context_dependent = is_context_dependent
4622        self.exposure_conditional = exposure_conditional
4623        self.world = world
4624        self.property_ = property_
4625
4626
4627class _PropEntryAttribute(_PropEntryBase):
4628    def __init__(self, is_context_dependent, exposure_conditional, world,
4629                 attribute, attr_get_callback_name, attr_set_callback_name):
4630        assert isinstance(attr_get_callback_name, str)
4631        assert _is_none_or_str(attr_set_callback_name)
4632
4633        _PropEntryBase.__init__(self, is_context_dependent,
4634                                exposure_conditional, world, attribute)
4635        self.attr_get_callback_name = attr_get_callback_name
4636        self.attr_set_callback_name = attr_set_callback_name
4637
4638
4639class _PropEntryConstant(_PropEntryBase):
4640    def __init__(self, is_context_dependent, exposure_conditional, world,
4641                 constant, const_callback_name, const_constant_name):
4642        assert _is_none_or_str(const_callback_name)
4643        assert isinstance(const_constant_name, str)
4644
4645        _PropEntryBase.__init__(self, is_context_dependent,
4646                                exposure_conditional, world, constant)
4647        self.const_callback_name = const_callback_name
4648        self.const_constant_name = const_constant_name
4649
4650
4651class _PropEntryConstructorGroup(_PropEntryBase):
4652    def __init__(self, is_context_dependent, exposure_conditional, world,
4653                 constructor_group, ctor_callback_name, ctor_func_length):
4654        assert isinstance(ctor_callback_name, str)
4655        assert isinstance(ctor_func_length, (int, long))
4656
4657        _PropEntryBase.__init__(self, is_context_dependent,
4658                                exposure_conditional, world, constructor_group)
4659        self.ctor_callback_name = ctor_callback_name
4660        self.ctor_func_length = ctor_func_length
4661
4662
4663class _PropEntryExposedConstruct(_PropEntryBase):
4664    def __init__(self, is_context_dependent, exposure_conditional, world,
4665                 exposed_construct, prop_callback_name):
4666        assert isinstance(prop_callback_name, str)
4667
4668        _PropEntryBase.__init__(self, is_context_dependent,
4669                                exposure_conditional, world, exposed_construct)
4670        self.prop_callback_name = prop_callback_name
4671
4672
4673class _PropEntryOperationGroup(_PropEntryBase):
4674    def __init__(self,
4675                 is_context_dependent,
4676                 exposure_conditional,
4677                 world,
4678                 operation_group,
4679                 op_callback_name,
4680                 op_func_length,
4681                 no_alloc_direct_callback_name=None):
4682        assert isinstance(op_callback_name, str)
4683        assert isinstance(op_func_length, (int, long))
4684
4685        _PropEntryBase.__init__(self, is_context_dependent,
4686                                exposure_conditional, world, operation_group)
4687        self.op_callback_name = op_callback_name
4688        self.op_func_length = op_func_length
4689        self.no_alloc_direct_callback_name = no_alloc_direct_callback_name
4690
4691
4692def make_property_entries_and_callback_defs(cg_context, attribute_entries,
4693                                            constant_entries,
4694                                            constructor_entries,
4695                                            exposed_construct_entries,
4696                                            operation_entries):
4697    """
4698    Creates intermediate objects to help property installation and also makes
4699    code nodes of callback functions.
4700
4701    Args:
4702        attribute_entries:
4703        constructor_entries:
4704        exposed_construct_entries:
4705        operation_entries:
4706            Output parameters to store the intermediate objects.
4707    """
4708    assert isinstance(cg_context, CodeGenContext)
4709    assert isinstance(attribute_entries, list)
4710    assert isinstance(constant_entries, list)
4711    assert isinstance(constructor_entries, list)
4712    assert isinstance(exposed_construct_entries, list)
4713    assert isinstance(operation_entries, list)
4714
4715    class_like = cg_context.class_like
4716    interface = cg_context.interface
4717    global_names = class_like.extended_attributes.values_of("Global")
4718
4719    callback_def_nodes = ListNode()
4720
4721    def iterate(members, callback):
4722        for member in members:
4723            is_context_dependent = member.exposure.is_context_dependent(
4724                global_names)
4725            exposure_conditional = expr_from_exposure(
4726                member.exposure,
4727                global_names=global_names,
4728                may_use_feature_selector=True)
4729
4730            if "PerWorldBindings" in member.extended_attributes:
4731                worlds = (CodeGenContext.MAIN_WORLD,
4732                          CodeGenContext.NON_MAIN_WORLDS)
4733            else:
4734                worlds = (CodeGenContext.ALL_WORLDS, )
4735
4736            for world in worlds:
4737                callback(member, is_context_dependent, exposure_conditional,
4738                         world)
4739
4740    def process_attribute(attribute, is_context_dependent,
4741                          exposure_conditional, world):
4742        if "CSSProperty" in attribute.extended_attributes:
4743            return  # [CSSProperty] will be installed in a special manner.
4744
4745        cgc_attr = cg_context.make_copy(attribute=attribute, for_world=world)
4746        cgc = cgc_attr.make_copy(attribute_get=True)
4747        attr_get_callback_name = callback_function_name(cgc)
4748        attr_get_callback_node = make_attribute_get_callback_def(
4749            cgc, attr_get_callback_name)
4750        cgc = cgc_attr.make_copy(attribute_set=True)
4751        attr_set_callback_name = callback_function_name(cgc)
4752        attr_set_callback_node = make_attribute_set_callback_def(
4753            cgc, attr_set_callback_name)
4754        if attr_set_callback_node is None:
4755            attr_set_callback_name = None
4756
4757        callback_def_nodes.extend([
4758            attr_get_callback_node,
4759            EmptyNode(),
4760            attr_set_callback_node,
4761            EmptyNode(),
4762        ])
4763
4764        attribute_entries.append(
4765            _PropEntryAttribute(
4766                is_context_dependent=is_context_dependent,
4767                exposure_conditional=exposure_conditional,
4768                world=world,
4769                attribute=attribute,
4770                attr_get_callback_name=attr_get_callback_name,
4771                attr_set_callback_name=attr_set_callback_name))
4772
4773    def process_constant(constant, is_context_dependent, exposure_conditional,
4774                         world):
4775        cgc = cg_context.make_copy(
4776            constant=constant,
4777            for_world=world,
4778            v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK)
4779        const_callback_name = callback_function_name(cgc)
4780        const_callback_node = make_constant_callback_def(
4781            cgc, const_callback_name)
4782        if const_callback_node is None:
4783            const_callback_name = None
4784        # IDL constant's C++ constant name
4785        const_constant_name = _format("${class_name}::Constant::{}",
4786                                      constant_name(cgc))
4787
4788        callback_def_nodes.extend([
4789            const_callback_node,
4790            EmptyNode(),
4791        ])
4792
4793        constant_entries.append(
4794            _PropEntryConstant(
4795                is_context_dependent=is_context_dependent,
4796                exposure_conditional=exposure_conditional,
4797                world=world,
4798                constant=constant,
4799                const_callback_name=const_callback_name,
4800                const_constant_name=const_constant_name))
4801
4802    def process_constructor_group(constructor_group, is_context_dependent,
4803                                  exposure_conditional, world):
4804        cgc = cg_context.make_copy(
4805            constructor_group=constructor_group, for_world=world)
4806        ctor_callback_name = callback_function_name(cgc)
4807        ctor_callback_node = make_constructor_callback_def(
4808            cgc, ctor_callback_name)
4809
4810        callback_def_nodes.extend([
4811            ctor_callback_node,
4812            EmptyNode(),
4813        ])
4814
4815        constructor_entries.append(
4816            _PropEntryConstructorGroup(
4817                is_context_dependent=is_context_dependent,
4818                exposure_conditional=exposure_conditional,
4819                world=world,
4820                constructor_group=constructor_group,
4821                ctor_callback_name=ctor_callback_name,
4822                ctor_func_length=(
4823                    constructor_group.min_num_of_required_arguments)))
4824
4825    def process_exposed_construct(exposed_construct, is_context_dependent,
4826                                  exposure_conditional, world):
4827        if isinstance(exposed_construct, web_idl.LegacyWindowAlias):
4828            cgc = cg_context.make_copy(
4829                exposed_construct=exposed_construct.original,
4830                legacy_window_alias=exposed_construct,
4831                for_world=world,
4832                v8_callback_type=CodeGenContext.
4833                V8_ACCESSOR_NAME_GETTER_CALLBACK)
4834        elif ("LegacyNoInterfaceObject" in
4835              exposed_construct.extended_attributes):
4836            return  # Skip due to [LegacyNoInterfaceObject].
4837        else:
4838            cgc = cg_context.make_copy(
4839                exposed_construct=exposed_construct,
4840                for_world=world,
4841                v8_callback_type=CodeGenContext.
4842                V8_ACCESSOR_NAME_GETTER_CALLBACK)
4843        prop_callback_name = callback_function_name(cgc)
4844        prop_callback_node = make_exposed_construct_callback_def(
4845            cgc, prop_callback_name)
4846
4847        callback_def_nodes.extend([
4848            prop_callback_node,
4849            EmptyNode(),
4850        ])
4851
4852        exposed_construct_entries.append(
4853            _PropEntryExposedConstruct(
4854                is_context_dependent=is_context_dependent,
4855                exposure_conditional=exposure_conditional,
4856                world=world,
4857                exposed_construct=exposed_construct,
4858                prop_callback_name=prop_callback_name))
4859
4860    def process_named_constructor_group(named_constructor_group,
4861                                        is_context_dependent,
4862                                        exposure_conditional, world):
4863        cgc = cg_context.make_copy(
4864            exposed_construct=named_constructor_group,
4865            is_named_constructor=True,
4866            for_world=world,
4867            v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK)
4868        prop_callback_name = callback_function_name(cgc)
4869        prop_callback_node = make_named_constructor_property_callback_def(
4870            cgc, prop_callback_name)
4871
4872        callback_def_nodes.extend([
4873            prop_callback_node,
4874            EmptyNode(),
4875        ])
4876
4877        exposed_construct_entries.append(
4878            _PropEntryExposedConstruct(
4879                is_context_dependent=is_context_dependent,
4880                exposure_conditional=exposure_conditional,
4881                world=world,
4882                exposed_construct=named_constructor_group,
4883                prop_callback_name=prop_callback_name))
4884
4885    def process_operation_group(operation_group, is_context_dependent,
4886                                exposure_conditional, world):
4887        cgc = cg_context.make_copy(
4888            operation_group=operation_group, for_world=world)
4889        op_callback_name = callback_function_name(cgc)
4890        no_alloc_direct_callback_name = (
4891            callback_function_name(cgc, no_alloc_direct_call=True)
4892            if "NoAllocDirectCall" in operation_group.extended_attributes else
4893            None)
4894        op_callback_node = make_operation_callback_def(
4895            cgc,
4896            op_callback_name,
4897            no_alloc_direct_callback_name=no_alloc_direct_callback_name)
4898
4899        callback_def_nodes.extend([
4900            op_callback_node,
4901            EmptyNode(),
4902        ])
4903
4904        operation_entries.append(
4905            _PropEntryOperationGroup(
4906                is_context_dependent=is_context_dependent,
4907                exposure_conditional=exposure_conditional,
4908                world=world,
4909                operation_group=operation_group,
4910                op_callback_name=op_callback_name,
4911                op_func_length=operation_group.min_num_of_required_arguments,
4912                no_alloc_direct_callback_name=no_alloc_direct_callback_name))
4913
4914    def process_stringifier(_, is_context_dependent, exposure_conditional,
4915                            world):
4916        cgc = cg_context.make_copy(
4917            stringifier=interface.stringifier, for_world=world)
4918        op_callback_name = callback_function_name(cgc)
4919        op_callback_node = make_stringifier_callback_def(cgc, op_callback_name)
4920
4921        callback_def_nodes.extend([
4922            op_callback_node,
4923            EmptyNode(),
4924        ])
4925
4926        operation_entries.append(
4927            _PropEntryOperationGroup(
4928                is_context_dependent=is_context_dependent,
4929                exposure_conditional=exposure_conditional,
4930                world=world,
4931                operation_group=cgc.property_,
4932                op_callback_name=op_callback_name,
4933                op_func_length=0))
4934
4935    iterate(class_like.attributes, process_attribute)
4936    iterate(class_like.constants, process_constant)
4937    if interface:
4938        iterate(interface.constructor_groups, process_constructor_group)
4939        iterate(interface.exposed_constructs, process_exposed_construct)
4940        iterate(interface.legacy_window_aliases, process_exposed_construct)
4941        named_constructor_groups = [
4942            group for construct in interface.exposed_constructs
4943            for group in construct.named_constructor_groups
4944            if construct.named_constructor_groups
4945        ]
4946        iterate(named_constructor_groups, process_named_constructor_group)
4947    if not class_like.is_callback_interface:
4948        iterate(class_like.operation_groups, process_operation_group)
4949    if interface and interface.stringifier:
4950        iterate([interface.stringifier.operation], process_stringifier)
4951    collectionlike = interface and (interface.iterable or interface.maplike
4952                                    or interface.setlike)
4953    if collectionlike:
4954
4955        def should_define(target):
4956            if not target[0].is_optionally_defined:
4957                return True
4958            return all(target.identifier != member.identifier
4959                       for member in itertools.chain(
4960                           interface.attributes, interface.constants,
4961                           interface.operation_groups))
4962
4963        iterate(collectionlike.attributes, process_attribute)
4964        iterate(
4965            filter(should_define, collectionlike.operation_groups),
4966            process_operation_group)
4967
4968    return callback_def_nodes
4969
4970
4971def _make_install_prototype_object(cg_context):
4972    assert isinstance(cg_context, CodeGenContext)
4973
4974    nodes = []
4975
4976    class_like = cg_context.class_like
4977    interface = cg_context.interface
4978
4979    unscopables = []
4980    is_unscopable = lambda member: "Unscopable" in member.extended_attributes
4981    unscopables.extend(filter(is_unscopable, class_like.attributes))
4982    unscopables.extend(filter(is_unscopable, class_like.operations))
4983    if unscopables:
4984        nodes.extend([
4985            TextNode("""\
4986// [Unscopable]
4987// 3.7.3. Interface prototype object
4988// https://heycam.github.io/webidl/#interface-prototype-object
4989// step 10. If interface has any member declared with the [Unscopable]
4990//   extended attribute, then:\
4991"""),
4992            ListNode([
4993                TextNode("static constexpr const char* "
4994                         "kUnscopablePropertyNames[] = {"),
4995                ListNode([
4996                    TextNode("\"{}\", ".format(member.identifier))
4997                    for member in unscopables
4998                ]),
4999                TextNode("};"),
5000            ]),
5001            TextNode("""\
5002bindings::InstallUnscopablePropertyNames(
5003    ${isolate}, ${v8_context}, ${prototype_object}, kUnscopablePropertyNames);
5004"""),
5005        ])
5006
5007    if "LegacyNoInterfaceObject" in class_like.extended_attributes:
5008        nodes.append(
5009            TextNode("""\
5010// [LegacyNoInterfaceObject]
5011// 3.7.3. Interface prototype object
5012// https://heycam.github.io/webidl/#interface-prototype-object
5013// step 13. If the [LegacyNoInterfaceObject] extended attribute was not
5014//   specified on interface, then:
5015//
5016// V8 defines "constructor" property on the prototype object by default.
5017${prototype_object}->Delete(
5018    ${v8_context}, V8AtomicString(${isolate}, "constructor")).ToChecked();
5019"""))
5020
5021    collectionlike = interface and (interface.iterable or interface.maplike
5022                                    or interface.setlike)
5023    if collectionlike:
5024        property_name = None
5025        for operation_group in collectionlike.operation_groups:
5026            if operation_group[0].is_iterator:
5027                property_name = operation_group.identifier
5028                break
5029        if property_name:
5030            pattern = """\
5031// @@iterator == "{property_name}"
5032{{
5033  v8::Local<v8::Value> v8_value = ${prototype_object}->Get(
5034      ${v8_context}, V8AtomicString(${isolate}, "{property_name}"))
5035      .ToLocalChecked();
5036  ${prototype_object}->DefineOwnProperty(
5037      ${v8_context}, v8::Symbol::GetIterator(${isolate}), v8_value,
5038      v8::DontEnum).ToChecked();
5039}}
5040"""
5041            nodes.append(
5042                TextNode(_format(pattern, property_name=property_name)))
5043
5044    if class_like.identifier == "FileSystemDirectoryHandle":
5045        pattern = """\
5046// Temporary @@asyncIterator support for FileSystemDirectoryHandle
5047// TODO(https://crbug.com/1087157): Replace with proper bindings support.
5048// @@asyncIterator == "{property_name}"
5049{{
5050  v8::Local<v8::Value> v8_value = ${prototype_object}->Get(
5051      ${v8_context}, V8AtomicString(${isolate}, "{property_name}"))
5052      .ToLocalChecked();
5053  ${prototype_object}->DefineOwnProperty(
5054      ${v8_context}, v8::Symbol::GetAsyncIterator(${isolate}), v8_value,
5055      v8::DontEnum).ToChecked();
5056}}
5057"""
5058        nodes.append(TextNode(_format(pattern, property_name="entries")))
5059
5060    if ("Global" in class_like.extended_attributes
5061            and class_like.indexed_and_named_properties
5062            and class_like.indexed_and_named_properties.has_named_properties):
5063        nodes.append(
5064            TextNode("""\
5065// https://heycam.github.io/webidl/#named-properties-object
5066// V8 defines "constructor" property on the prototype object by default.
5067// Named properties object is currently implemented as a prototype object
5068// (implemented with v8::FunctionTemplate::PrototypeTemplate()).
5069${prototype_object}->GetPrototype().As<v8::Object>()->Delete(
5070    ${v8_context}, V8AtomicString(${isolate}, "constructor")).ToChecked();
5071"""))
5072
5073    return SequenceNode(nodes) if nodes else None
5074
5075
5076def make_install_interface_template(cg_context, function_name, class_name,
5077                                    trampoline_var_name, constructor_entries,
5078                                    supplemental_install_node,
5079                                    install_unconditional_func_name,
5080                                    install_context_independent_func_name):
5081    """
5082    Returns:
5083        A triplet of CodeNode of:
5084        - function declaration
5085        - function definition
5086        - trampoline function definition (from the API class to the
5087          implementation class), which is supposed to be defined inline
5088    """
5089    assert isinstance(cg_context, CodeGenContext)
5090    assert isinstance(function_name, str)
5091    assert _is_none_or_str(class_name)
5092    assert _is_none_or_str(trampoline_var_name)
5093    assert isinstance(constructor_entries, (list, tuple))
5094    assert all(
5095        isinstance(entry, _PropEntryConstructorGroup)
5096        for entry in constructor_entries)
5097    assert isinstance(supplemental_install_node, SequenceNode)
5098    assert _is_none_or_str(install_unconditional_func_name)
5099    assert _is_none_or_str(install_context_independent_func_name)
5100
5101    T = TextNode
5102
5103    class_like = cg_context.class_like
5104    interface = cg_context.interface
5105
5106    arg_decls = [
5107        "v8::Isolate* isolate",
5108        "const DOMWrapperWorld& world",
5109        "v8::Local<v8::Template> interface_template",
5110    ]
5111    return_type = "void"
5112
5113    if trampoline_var_name is None:
5114        trampoline_def = None
5115    else:
5116        trampoline_def = CxxFuncDefNode(
5117            name=function_name,
5118            arg_decls=arg_decls,
5119            return_type=return_type,
5120            static=True)
5121        trampoline_def.body.append(
5122            TextNode(
5123                _format("return {}(isolate, world, interface_template);",
5124                        trampoline_var_name)))
5125
5126    func_decl = CxxFuncDeclNode(
5127        name=function_name,
5128        arg_decls=arg_decls,
5129        return_type=return_type,
5130        static=True)
5131
5132    func_def = CxxFuncDefNode(
5133        name=function_name,
5134        arg_decls=arg_decls,
5135        return_type=return_type,
5136        class_name=class_name)
5137    func_def.set_base_template_vars(cg_context.template_bindings())
5138
5139    body = func_def.body
5140    body.add_template_vars({
5141        "isolate": "isolate",
5142        "world": "world",
5143        "interface_template": "interface_template",
5144    })
5145    bind_installer_local_vars(body, cg_context)
5146
5147    if cg_context.interface:
5148        body.extend([
5149            T("bindings::SetupIDLInterfaceTemplate("
5150              "${isolate}, ${wrapper_type_info}, "
5151              "${instance_object_template}, "
5152              "${prototype_object_template}, "
5153              "${interface_function_template}, "
5154              "${parent_interface_template});"),
5155            EmptyNode(),
5156        ])
5157    elif cg_context.namespace:
5158        body.extend([
5159            T("bindings::SetupIDLNamespaceTemplate("
5160              "${isolate}, ${wrapper_type_info}, "
5161              "${namespace_object_template});"),
5162            EmptyNode(),
5163        ])
5164    elif cg_context.callback_interface:
5165        body.extend([
5166            T("bindings::SetupIDLCallbackInterfaceTemplate("
5167              "${isolate}, ${wrapper_type_info}, "
5168              "${interface_function_template});"),
5169            EmptyNode(),
5170        ])
5171    else:
5172        assert False
5173
5174    for entry in constructor_entries:
5175        set_callback = _format(
5176            "${interface_function_template}->SetCallHandler({});",
5177            entry.ctor_callback_name)
5178        set_length = _format("${interface_function_template}->SetLength({});",
5179                             entry.ctor_func_length)
5180        if entry.world == CodeGenContext.MAIN_WORLD:
5181            body.append(
5182                CxxLikelyIfNode(
5183                    cond="${world}.IsMainWorld()",
5184                    body=[T(set_callback), T(set_length)]))
5185        elif entry.world == CodeGenContext.NON_MAIN_WORLDS:
5186            body.append(
5187                CxxLikelyIfNode(
5188                    cond="!${world}.IsMainWorld()",
5189                    body=[T(set_callback), T(set_length)]))
5190        elif entry.world == CodeGenContext.ALL_WORLDS:
5191            body.extend([T(set_callback), T(set_length)])
5192        else:
5193            assert False
5194        body.append(EmptyNode())
5195
5196    body.extend([
5197        supplemental_install_node,
5198        EmptyNode(),
5199    ])
5200
5201    if class_like.identifier == "CSSStyleDeclaration":
5202        css_properties = filter(
5203            lambda attr: "CSSProperty" in attr.extended_attributes,
5204            class_like.attributes)
5205        if css_properties:
5206            prop_name_list = "".join(
5207                map(lambda attr: "\"{}\", ".format(attr.identifier),
5208                    css_properties))
5209            body.append(
5210                T("""\
5211// CSSStyleDeclaration-specific settings
5212// [CSSProperty]
5213{
5214  static constexpr const char* kCssProperties[] = {
5215""" + prop_name_list + """
5216  };
5217  bindings::InstallCSSPropertyAttributes(
5218      ${isolate}, ${world},
5219      ${instance_template}, ${prototype_template}, ${interface_template},
5220      ${signature}, kCssProperties);
5221}
5222"""))
5223
5224    if class_like.identifier == "DOMException":
5225        body.append(
5226            T("""\
5227// DOMException-specific settings
5228// https://heycam.github.io/webidl/#es-DOMException-specialness
5229{
5230  v8::Local<v8::FunctionTemplate> intrinsic_error_prototype_interface_template =
5231      v8::FunctionTemplate::New(${isolate});
5232  intrinsic_error_prototype_interface_template->RemovePrototype();
5233  intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
5234      V8AtomicString(${isolate}, "prototype"), v8::kErrorPrototype);
5235  ${interface_function_template}->Inherit(
5236      intrinsic_error_prototype_interface_template);
5237}
5238"""))
5239
5240    if class_like.identifier == "NativeFileSystemDirectoryIterator":
5241        body.append(
5242            T("""\
5243// Temporary @@asyncIterator support for FileSystemDirectoryHandle
5244// TODO(https://crbug.com/1087157): Replace with proper bindings support.
5245{
5246  v8::Local<v8::FunctionTemplate>
5247      intrinsic_iterator_prototype_interface_template =
5248      v8::FunctionTemplate::New(${isolate});
5249  intrinsic_iterator_prototype_interface_template->RemovePrototype();
5250  intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
5251      V8AtomicString(${isolate}, "prototype"), v8::kAsyncIteratorPrototype);
5252  ${interface_function_template}->Inherit(
5253      intrinsic_iterator_prototype_interface_template);
5254}
5255"""))
5256
5257    if class_like.identifier == "HTMLAllCollection":
5258        body.append(
5259            T("""\
5260// HTMLAllCollection-specific settings
5261// https://html.spec.whatwg.org/C/#the-htmlallcollection-interface
5262${instance_object_template}->SetCallAsFunctionHandler(
5263    ${class_name}::LegacyCallCustom);
5264${instance_object_template}->MarkAsUndetectable();
5265"""))
5266
5267    if class_like.identifier == "Iterator":
5268        body.append(
5269            T("""\
5270// Iterator-specific settings
5271// https://heycam.github.io/webidl/#es-iterator-prototype-object
5272{
5273  v8::Local<v8::FunctionTemplate>
5274      intrinsic_iterator_prototype_interface_template =
5275      v8::FunctionTemplate::New(${isolate});
5276  intrinsic_iterator_prototype_interface_template->RemovePrototype();
5277  intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
5278      V8AtomicString(${isolate}, "prototype"), v8::kIteratorPrototype);
5279  ${interface_function_template}->Inherit(
5280      intrinsic_iterator_prototype_interface_template);
5281}
5282"""))
5283
5284    if class_like.identifier == "Location":
5285        body.append(
5286            T("""\
5287// Location-specific settings
5288// https://html.spec.whatwg.org/C/#the-location-interface
5289// To create a Location object, run these steps:
5290// step 3. Let valueOf be location's relevant
5291//   Realm.[[Intrinsics]].[[%ObjProto_valueOf%]].
5292// step 3. Perform ! location.[[DefineOwnProperty]]("valueOf",
5293//   { [[Value]]: valueOf, [[Writable]]: false, [[Enumerable]]: false,
5294//     [[Configurable]]: false }).
5295${instance_template}->SetIntrinsicDataProperty(
5296    V8AtomicString(${isolate}, "valueOf"),
5297    v8::kObjProto_valueOf,
5298    static_cast<v8::PropertyAttribute>(
5299        v8::ReadOnly | v8::DontEnum | v8::DontDelete));
5300// step 4. Perform ! location.[[DefineOwnProperty]](@@toPrimitive,
5301//   { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false,
5302//     [[Configurable]]: false }).
5303${instance_template}->Set(
5304    v8::Symbol::GetToPrimitive(${isolate}),
5305    v8::Undefined(${isolate}),
5306    static_cast<v8::PropertyAttribute>(
5307        v8::ReadOnly | v8::DontEnum | v8::DontDelete));
5308// 7.7.4.2 [[SetPrototypeOf]] ( V )
5309// https://html.spec.whatwg.org/C/#location-setprototypeof
5310${instance_object_template}->SetImmutableProto();
5311${prototype_object_template}->SetImmutableProto();
5312"""))
5313
5314    if (interface and interface.indexed_and_named_properties
5315            and interface.indexed_and_named_properties.indexed_getter
5316            and "Global" not in interface.extended_attributes):
5317        body.append(
5318            T("""\
5319// @@iterator for indexed properties
5320// https://heycam.github.io/webidl/#define-the-iteration-methods
5321${prototype_template}->SetIntrinsicDataProperty(
5322    v8::Symbol::GetIterator(${isolate}), v8::kArrayProto_values, v8::DontEnum);
5323"""))
5324    if interface and interface.iterable and not interface.iterable.key_type:
5325        body.append(
5326            T("""\
5327// Value iterator's properties
5328// https://heycam.github.io/webidl/#define-the-iteration-methods
5329${prototype_template}->SetIntrinsicDataProperty(
5330    V8AtomicString(${isolate}, "entries"), v8::kArrayProto_entries, v8::None);
5331${prototype_template}->SetIntrinsicDataProperty(
5332    V8AtomicString(${isolate}, "keys"), v8::kArrayProto_keys, v8::None);
5333${prototype_template}->SetIntrinsicDataProperty(
5334    V8AtomicString(${isolate}, "values"), v8::kArrayProto_values, v8::None);
5335${prototype_template}->SetIntrinsicDataProperty(
5336    V8AtomicString(${isolate}, "forEach"), v8::kArrayProto_forEach, v8::None);
5337"""))
5338
5339    if interface and "IsCodeLike" in interface.extended_attributes:
5340        body.append(
5341            CxxUnlikelyIfNode(
5342                cond="RuntimeEnabledFeatures::TrustedTypesUseCodeLikeEnabled()",
5343                body=[
5344                    TextNode("// [IsCodeLike]"),
5345                    TextNode("${instance_object_template}->SetCodeLike();"),
5346                ]))
5347
5348    if "Global" in class_like.extended_attributes:
5349        body.append(
5350            TextNode("""\
5351// [Global]
5352// 3.7.1. [[SetPrototypeOf]]
5353// https://heycam.github.io/webidl/#platform-object-setprototypeof
5354${instance_object_template}->SetImmutableProto();
5355${prototype_object_template}->SetImmutableProto();
5356"""))
5357    elif interface and any("Global" in derived.extended_attributes
5358                           for derived in interface.deriveds):
5359        body.append(
5360            TextNode("""\
5361// [Global] - prototype object in the prototype chain of global objects
5362// 3.7.1. [[SetPrototypeOf]]
5363// https://heycam.github.io/webidl/#platform-object-setprototypeof
5364${prototype_object_template}->SetImmutableProto();
5365"""))
5366
5367    func_call_pattern = ("{}(${isolate}, ${world}, ${instance_template}, "
5368                         "${prototype_template}, ${interface_template});")
5369    if install_unconditional_func_name:
5370        func_call = _format(func_call_pattern, install_unconditional_func_name)
5371        body.append(T(func_call))
5372    if install_context_independent_func_name:
5373        func_call = _format(func_call_pattern,
5374                            install_context_independent_func_name)
5375        body.append(T(func_call))
5376
5377    return func_decl, func_def, trampoline_def
5378
5379
5380class PropInstallMode(object):
5381    class Mode(int):
5382        pass
5383
5384    UNCONDITIONAL = Mode(0)
5385    CONTEXT_INDEPENDENT = Mode(1)
5386    CONTEXT_DEPENDENT = Mode(2)
5387    V8_CONTEXT_SNAPSHOT = Mode(3)
5388
5389
5390def make_install_properties(cg_context, function_name, class_name,
5391                            prop_install_mode, trampoline_var_name,
5392                            attribute_entries, constant_entries,
5393                            exposed_construct_entries, operation_entries):
5394    """
5395    Returns:
5396        A triplet of CodeNode of:
5397        - function declaration
5398        - function definition
5399        - trampoline function definition (from the API class to the
5400          implementation class), which is supposed to be defined inline
5401    """
5402    assert isinstance(cg_context, CodeGenContext)
5403    assert isinstance(function_name, str)
5404    assert _is_none_or_str(class_name)
5405    assert isinstance(prop_install_mode, PropInstallMode.Mode)
5406    assert _is_none_or_str(trampoline_var_name)
5407    assert isinstance(attribute_entries, (list, tuple))
5408    assert all(
5409        isinstance(entry, _PropEntryAttribute) for entry in attribute_entries)
5410    assert isinstance(constant_entries, (list, tuple))
5411    assert all(
5412        isinstance(entry, _PropEntryConstant) for entry in constant_entries)
5413    assert isinstance(exposed_construct_entries, (list, tuple))
5414    assert all(
5415        isinstance(entry, _PropEntryExposedConstruct)
5416        for entry in exposed_construct_entries)
5417    assert isinstance(operation_entries, (list, tuple))
5418    assert all(
5419        isinstance(entry, _PropEntryOperationGroup)
5420        for entry in operation_entries)
5421
5422    if prop_install_mode == PropInstallMode.CONTEXT_DEPENDENT:
5423        install_prototype_object_node = _make_install_prototype_object(
5424            cg_context)
5425    else:
5426        install_prototype_object_node = None
5427
5428    if not (attribute_entries or constant_entries or exposed_construct_entries
5429            or operation_entries or install_prototype_object_node):
5430        if prop_install_mode != PropInstallMode.V8_CONTEXT_SNAPSHOT:
5431            return None, None, None
5432
5433    if prop_install_mode in (PropInstallMode.UNCONDITIONAL,
5434                             PropInstallMode.CONTEXT_INDEPENDENT):
5435        arg_decls = [
5436            "v8::Isolate* isolate",
5437            "const DOMWrapperWorld& world",
5438            "v8::Local<v8::Template> instance_template",
5439            "v8::Local<v8::Template> prototype_template",
5440            "v8::Local<v8::Template> interface_template",
5441        ]
5442        arg_names = [
5443            "isolate",
5444            "world",
5445            "instance_template",
5446            "prototype_template",
5447            "interface_template",
5448        ]
5449    elif prop_install_mode == PropInstallMode.CONTEXT_DEPENDENT:
5450        arg_decls = [
5451            "v8::Local<v8::Context> context",
5452            "const DOMWrapperWorld& world",
5453            "v8::Local<v8::Object> instance_object",
5454            "v8::Local<v8::Object> prototype_object",
5455            "v8::Local<v8::Object> interface_object",
5456            "v8::Local<v8::Template> interface_template",
5457            "FeatureSelector feature_selector",
5458        ]
5459        arg_names = [
5460            "context",
5461            "world",
5462            "instance_object",
5463            "prototype_object",
5464            "interface_object",
5465            "interface_template",
5466            "feature_selector",
5467        ]
5468    elif prop_install_mode == PropInstallMode.V8_CONTEXT_SNAPSHOT:
5469        arg_decls = [
5470            "v8::Local<v8::Context> context",
5471            "const DOMWrapperWorld& world",
5472            "v8::Local<v8::Object> instance_object",
5473            "v8::Local<v8::Object> prototype_object",
5474            "v8::Local<v8::Object> interface_object",
5475            "v8::Local<v8::Template> interface_template",
5476        ]
5477        arg_names = [
5478            "context",
5479            "world",
5480            "instance_object",
5481            "prototype_object",
5482            "interface_object",
5483            "interface_template",
5484        ]
5485    return_type = "void"
5486
5487    is_per_context_install = (
5488        prop_install_mode in (PropInstallMode.CONTEXT_DEPENDENT,
5489                              PropInstallMode.V8_CONTEXT_SNAPSHOT))
5490
5491    if trampoline_var_name is None:
5492        trampoline_def = None
5493    else:
5494        trampoline_def = CxxFuncDefNode(
5495            name=function_name,
5496            arg_decls=arg_decls,
5497            return_type=return_type,
5498            static=True)
5499        text = _format(
5500            "return {func}({args});",
5501            func=trampoline_var_name,
5502            args=", ".join(arg_names))
5503        trampoline_def.body.append(TextNode(text))
5504
5505    func_decl = CxxFuncDeclNode(name=function_name,
5506                                arg_decls=arg_decls,
5507                                return_type=return_type,
5508                                static=bool(class_name))
5509
5510    func_def = CxxFuncDefNode(
5511        name=function_name,
5512        arg_decls=arg_decls,
5513        return_type=return_type,
5514        class_name=class_name)
5515    func_def.set_base_template_vars(cg_context.template_bindings())
5516
5517    body = func_def.body
5518    for arg_name in arg_names:
5519        if arg_name == "context":  # 'context' is reserved by Mako.
5520            body.add_template_var("v8_context", "context")
5521        else:
5522            body.add_template_var(arg_name, arg_name)
5523    bind_installer_local_vars(body, cg_context)
5524
5525    body.extend([
5526        TextNode("using bindings::IDLMemberInstaller;"),
5527        EmptyNode(),
5528    ])
5529
5530    if (is_per_context_install
5531            and "Global" in cg_context.class_like.extended_attributes):
5532        body.extend([
5533            CxxLikelyIfNode(cond="${instance_object}.IsEmpty()",
5534                            body=[
5535                                TextNode("""\
5536${instance_object} = ${v8_context}->Global()->GetPrototype().As<v8::Object>();\
5537"""),
5538                            ]),
5539            EmptyNode(),
5540        ])
5541
5542    if install_prototype_object_node:
5543        body.extend([
5544            CxxLikelyIfNode(cond="${feature_selector}.IsAll()",
5545                            body=[install_prototype_object_node]),
5546            EmptyNode(),
5547        ])
5548
5549    def group_by_condition(entries):
5550        unconditional_entries = []
5551        conditional_to_entries = {}
5552        for entry in entries:
5553            if entry.exposure_conditional.is_always_true:
5554                unconditional_entries.append(entry)
5555            else:
5556                conditional_to_entries.setdefault(entry.exposure_conditional,
5557                                                  []).append(entry)
5558        return unconditional_entries, conditional_to_entries
5559
5560    def install_properties(table_name, target_entries, make_table_func,
5561                           installer_call_text):
5562        unconditional_entries, conditional_to_entries = group_by_condition(
5563            target_entries)
5564        if unconditional_entries:
5565            body.append(
5566                CxxBlockNode([
5567                    make_table_func(table_name, unconditional_entries),
5568                    TextNode(installer_call_text),
5569                ]))
5570            body.append(EmptyNode())
5571        for conditional, entries in conditional_to_entries.items():
5572            body.append(
5573                CxxUnlikelyIfNode(
5574                    cond=conditional,
5575                    body=[
5576                        make_table_func(table_name, entries),
5577                        TextNode(installer_call_text),
5578                    ]))
5579        body.append(EmptyNode())
5580
5581    if is_per_context_install:
5582        pattern = ("{install_func}("
5583                   "${isolate}, ${world}, "
5584                   "${instance_object}, "
5585                   "${prototype_object}, "
5586                   "${interface_object}, "
5587                   "${signature}, {table_name});")
5588    else:
5589        pattern = ("{install_func}("
5590                   "${isolate}, ${world}, "
5591                   "${instance_template}, "
5592                   "${prototype_template}, "
5593                   "${interface_template}, "
5594                   "${signature}, {table_name});")
5595
5596    table_name = "kAttributeTable"
5597    installer_call_text = _format(
5598        pattern,
5599        install_func="IDLMemberInstaller::InstallAttributes",
5600        table_name=table_name)
5601    install_properties(table_name, attribute_entries,
5602                       _make_attribute_registration_table, installer_call_text)
5603
5604    table_name = "kConstantCallbackTable"
5605    installer_call_text = _format(
5606        pattern,
5607        install_func="IDLMemberInstaller::InstallConstants",
5608        table_name=table_name)
5609    constant_callback_entries = filter(lambda entry: entry.const_callback_name,
5610                                       constant_entries)
5611    install_properties(table_name, constant_callback_entries,
5612                       _make_constant_callback_registration_table,
5613                       installer_call_text)
5614
5615    table_name = "kConstantValueTable"
5616    installer_call_text = _format(
5617        pattern,
5618        install_func="IDLMemberInstaller::InstallConstants",
5619        table_name=table_name)
5620    constant_value_entries = filter(
5621        lambda entry: not entry.const_callback_name, constant_entries)
5622    install_properties(table_name, constant_value_entries,
5623                       _make_constant_value_registration_table,
5624                       installer_call_text)
5625
5626    table_name = "kExposedConstructTable"
5627    installer_call_text = _format(
5628        pattern,
5629        install_func="IDLMemberInstaller::InstallExposedConstructs",
5630        table_name=table_name)
5631    install_properties(table_name, exposed_construct_entries,
5632                       _make_exposed_construct_registration_table,
5633                       installer_call_text)
5634
5635    table_name = "kOperationTable"
5636    installer_call_text = _format(
5637        pattern,
5638        install_func="IDLMemberInstaller::InstallOperations",
5639        table_name=table_name)
5640    entries = filter(lambda entry: not entry.no_alloc_direct_callback_name,
5641                     operation_entries)
5642    install_properties(table_name, entries, _make_operation_registration_table,
5643                       installer_call_text)
5644    entries = filter(lambda entry: entry.no_alloc_direct_callback_name,
5645                     operation_entries)
5646    install_properties(table_name, entries, _make_operation_registration_table,
5647                       installer_call_text)
5648
5649    return func_decl, func_def, trampoline_def
5650
5651
5652def make_indexed_and_named_property_callbacks_and_install_node(cg_context):
5653    """
5654    Implements non-ordinary internal methods of legacy platform objects.
5655    https://heycam.github.io/webidl/#es-legacy-platform-objects
5656
5657    Also implements the same origin case of indexed access to WindowProxy
5658    objects just same as indexed properties of legacy platform objects.
5659    https://html.spec.whatwg.org/C/#the-windowproxy-exotic-object
5660    """
5661
5662    assert isinstance(cg_context, CodeGenContext)
5663
5664    F = lambda *args, **kwargs: TextNode(_format(*args, **kwargs))
5665
5666    func_decls = ListNode()
5667    func_defs = ListNode()
5668    install_node = SequenceNode()
5669
5670    interface = cg_context.interface
5671    if not (interface and interface.indexed_and_named_properties
5672            and "Global" not in interface.extended_attributes):
5673        return func_decls, func_defs, install_node
5674    props = interface.indexed_and_named_properties
5675
5676    def add_callback(func_decl, func_def):
5677        func_decls.append(func_decl)
5678        if func_def:
5679            func_defs.append(func_def)
5680            func_defs.append(EmptyNode())
5681
5682    def most_derived_interface(*interfaces):
5683        key = lambda interface: len(interface.inclusive_inherited_interfaces)
5684        return sorted(filter(None, interfaces), key=key)[-1]
5685
5686    cg_context = cg_context.make_copy(
5687        v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK)
5688
5689    if props.own_named_getter:
5690        add_callback(*make_named_property_getter_callback(
5691            cg_context.make_copy(named_property_getter=props.named_getter),
5692            "NamedPropertyGetterCallback"))
5693        add_callback(*make_named_property_setter_callback(
5694            cg_context.make_copy(named_property_setter=props.named_setter),
5695            "NamedPropertySetterCallback"))
5696        add_callback(*make_named_property_deleter_callback(
5697            cg_context.make_copy(named_property_deleter=props.named_deleter),
5698            "NamedPropertyDeleterCallback"))
5699        add_callback(*make_named_property_definer_callback(
5700            cg_context, "NamedPropertyDefinerCallback"))
5701        add_callback(*make_named_property_descriptor_callback(
5702            cg_context, "NamedPropertyDescriptorCallback"))
5703        add_callback(*make_named_property_query_callback(
5704            cg_context, "NamedPropertyQueryCallback"))
5705        add_callback(*make_named_property_enumerator_callback(
5706            cg_context, "NamedPropertyEnumeratorCallback"))
5707
5708    if props.named_getter:
5709        impl_bridge = v8_bridge_class_name(
5710            most_derived_interface(
5711                props.named_getter.owner, props.named_setter
5712                and props.named_setter.owner, props.named_deleter
5713                and props.named_deleter.owner))
5714        flags = ["v8::PropertyHandlerFlags::kOnlyInterceptStrings"]
5715        if "LegacyOverrideBuiltIns" not in interface.extended_attributes:
5716            flags.append("v8::PropertyHandlerFlags::kNonMasking")
5717        if (props.named_getter.extended_attributes.value_of("Affects") ==
5718                "Nothing"):
5719            flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect")
5720        property_handler_flags = (
5721            "static_cast<v8::PropertyHandlerFlags>({})".format(" | ".join(
5722                map(lambda flag: "int32_t({})".format(flag), flags))))
5723        pattern = """\
5724// Named interceptors
5725${instance_object_template}->SetHandler(
5726    v8::NamedPropertyHandlerConfiguration(
5727        {impl_bridge}::NamedPropertyGetterCallback,
5728        {impl_bridge}::NamedPropertySetterCallback,
5729% if "NotEnumerable" not in \
5730interface.indexed_and_named_properties.named_getter.extended_attributes:
5731        {impl_bridge}::NamedPropertyQueryCallback,
5732% else:
5733        nullptr,  // query
5734% endif
5735        {impl_bridge}::NamedPropertyDeleterCallback,
5736% if "NotEnumerable" not in \
5737interface.indexed_and_named_properties.named_getter.extended_attributes:
5738        {impl_bridge}::NamedPropertyEnumeratorCallback,
5739% else:
5740        nullptr,  // enumerator
5741% endif
5742        {impl_bridge}::NamedPropertyDefinerCallback,
5743        {impl_bridge}::NamedPropertyDescriptorCallback,
5744        v8::Local<v8::Value>(),
5745        {property_handler_flags}));"""
5746        install_node.append(
5747            F(pattern,
5748              impl_bridge=impl_bridge,
5749              property_handler_flags=property_handler_flags))
5750
5751    if props.own_indexed_getter or props.own_named_getter:
5752        add_callback(*make_indexed_property_getter_callback(
5753            cg_context.make_copy(indexed_property_getter=props.indexed_getter),
5754            "IndexedPropertyGetterCallback"))
5755        add_callback(*make_indexed_property_setter_callback(
5756            cg_context.make_copy(indexed_property_setter=props.indexed_setter),
5757            "IndexedPropertySetterCallback"))
5758        add_callback(*make_indexed_property_deleter_callback(
5759            cg_context, "IndexedPropertyDeleterCallback"))
5760        add_callback(*make_indexed_property_definer_callback(
5761            cg_context, "IndexedPropertyDefinerCallback"))
5762        add_callback(*make_indexed_property_descriptor_callback(
5763            cg_context, "IndexedPropertyDescriptorCallback"))
5764        add_callback(*make_indexed_property_enumerator_callback(
5765            cg_context, "IndexedPropertyEnumeratorCallback"))
5766
5767    if props.indexed_getter or props.named_getter:
5768        impl_bridge = v8_bridge_class_name(
5769            most_derived_interface(
5770                props.indexed_getter and props.indexed_getter.owner,
5771                props.indexed_setter and props.indexed_setter.owner,
5772                props.named_getter and props.named_getter.owner,
5773                props.named_setter and props.named_setter.owner,
5774                props.named_deleter and props.named_deleter.owner))
5775        flags = []
5776        if (props.indexed_getter and props.indexed_getter.extended_attributes.
5777                value_of("Affects") == "Nothing"):
5778            flags.append("v8::PropertyHandlerFlags::kHasNoSideEffect")
5779        else:
5780            flags.append("v8::PropertyHandlerFlags::kNone")
5781        property_handler_flags = flags[0]
5782        pattern = """\
5783// Indexed interceptors
5784${instance_object_template}->SetHandler(
5785    v8::IndexedPropertyHandlerConfiguration(
5786        {impl_bridge}::IndexedPropertyGetterCallback,
5787        {impl_bridge}::IndexedPropertySetterCallback,
5788        nullptr,  // query
5789        {impl_bridge}::IndexedPropertyDeleterCallback,
5790% if interface.indexed_and_named_properties.indexed_getter:
5791        {impl_bridge}::IndexedPropertyEnumeratorCallback,
5792% else:
5793        nullptr,  // enumerator
5794% endif
5795        {impl_bridge}::IndexedPropertyDefinerCallback,
5796        {impl_bridge}::IndexedPropertyDescriptorCallback,
5797        v8::Local<v8::Value>(),
5798        {property_handler_flags}));"""
5799        install_node.append(
5800            F(pattern,
5801              impl_bridge=impl_bridge,
5802              property_handler_flags=property_handler_flags))
5803
5804    func_defs.accumulate(
5805        CodeGenAccumulator.require_include_headers([
5806            "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h"
5807        ]))
5808
5809    return func_decls, func_defs, install_node
5810
5811
5812def make_named_properties_object_callbacks_and_install_node(cg_context):
5813    """
5814    Implements non-ordinary internal methods of named properties objects.
5815    https://heycam.github.io/webidl/#named-properties-object
5816    """
5817
5818    assert isinstance(cg_context, CodeGenContext)
5819
5820    callback_defs = []
5821    install_node = SequenceNode()
5822
5823    interface = cg_context.interface
5824    if not (interface and interface.indexed_and_named_properties
5825            and interface.indexed_and_named_properties.named_getter
5826            and "Global" in interface.extended_attributes):
5827        return callback_defs, install_node
5828
5829    cg_context = cg_context.make_copy(
5830        v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK)
5831
5832    func_defs = [
5833        make_named_props_obj_named_getter_callback(
5834            cg_context, "NamedPropsObjNamedGetterCallback"),
5835        make_named_props_obj_named_deleter_callback(
5836            cg_context, "NamedPropsObjNamedDeleterCallback"),
5837        make_named_props_obj_named_definer_callback(
5838            cg_context, "NamedPropsObjNamedDefinerCallback"),
5839        make_named_props_obj_named_descriptor_callback(
5840            cg_context, "NamedPropsObjNamedDescriptorCallback"),
5841        make_named_props_obj_indexed_getter_callback(
5842            cg_context, "NamedPropsObjIndexedGetterCallback"),
5843        make_named_props_obj_indexed_deleter_callback(
5844            cg_context, "NamedPropsObjIndexedDeleterCallback"),
5845        make_named_props_obj_indexed_definer_callback(
5846            cg_context, "NamedPropsObjIndexedDefinerCallback"),
5847        make_named_props_obj_indexed_descriptor_callback(
5848            cg_context, "NamedPropsObjIndexedDescriptorCallback"),
5849    ]
5850    for func_def in func_defs:
5851        callback_defs.append(func_def)
5852        callback_defs.append(EmptyNode())
5853
5854    text = """\
5855// Named interceptors
5856${npo_prototype_template}->SetHandler(
5857    v8::NamedPropertyHandlerConfiguration(
5858        NamedPropsObjNamedGetterCallback,
5859        nullptr,  // setter
5860        nullptr,  // query
5861        NamedPropsObjNamedDeleterCallback,
5862        nullptr,  // enumerator
5863        NamedPropsObjNamedDefinerCallback,
5864        NamedPropsObjNamedDescriptorCallback,
5865        v8::Local<v8::Value>(),
5866        static_cast<v8::PropertyHandlerFlags>(
5867            int32_t(v8::PropertyHandlerFlags::kNonMasking) |
5868            int32_t(v8::PropertyHandlerFlags::kOnlyInterceptStrings))));
5869// Indexed interceptors
5870${npo_prototype_template}->SetHandler(
5871    v8::IndexedPropertyHandlerConfiguration(
5872        NamedPropsObjIndexedGetterCallback,
5873        nullptr,  // setter
5874        nullptr,  // query
5875        NamedPropsObjIndexedDeleterCallback,
5876        nullptr,  // enumerator
5877        NamedPropsObjIndexedDefinerCallback,
5878        NamedPropsObjIndexedDescriptorCallback,
5879        v8::Local<v8::Value>(),
5880        v8::PropertyHandlerFlags::kNone));"""
5881    install_node.append(TextNode(text))
5882
5883    return callback_defs, install_node
5884
5885
5886def make_cross_origin_property_callbacks_and_install_node(
5887        cg_context, attribute_entries, operation_entries):
5888    """
5889    Implements non-ordinary internal methods of WindowProxy and Location
5890    objects.
5891    https://html.spec.whatwg.org/C/#the-windowproxy-exotic-object
5892    https://html.spec.whatwg.org/C/#the-location-interface
5893    """
5894
5895    assert isinstance(cg_context, CodeGenContext)
5896
5897    callback_defs = []
5898    install_node = SequenceNode()
5899
5900    CROSS_ORIGIN_INTERFACES = ("Window", "Location")
5901    if cg_context.class_like.identifier not in CROSS_ORIGIN_INTERFACES:
5902        return callback_defs, install_node
5903    props = cg_context.interface.indexed_and_named_properties
5904
5905    entry_nodes = []
5906    for entry in attribute_entries:
5907        attribute = entry.property_
5908        if "CrossOrigin" not in attribute.extended_attributes:
5909            continue
5910        assert entry.world == CodeGenContext.ALL_WORLDS
5911        values = attribute.extended_attributes.values_of("CrossOrigin")
5912        get_func = "nullptr"
5913        set_func = "nullptr"
5914        get_value = "nullptr"
5915        set_value = "nullptr"
5916        if not values or "Getter" in values:
5917            get_func = entry.attr_get_callback_name
5918            cgc = cg_context.make_copy(
5919                attribute=attribute,
5920                attribute_get=True,
5921                v8_callback_type=(
5922                    CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK))
5923            get_value = callback_function_name(cgc, for_cross_origin=True)
5924            func_def = make_attribute_get_callback_def(cgc, get_value)
5925            callback_defs.extend([func_def, EmptyNode()])
5926        if values and "Setter" in values:
5927            set_func = entry.attr_set_callback_name
5928            cgc = cg_context.make_copy(
5929                attribute=attribute,
5930                attribute_set=True,
5931                v8_callback_type=(
5932                    CodeGenContext.V8_GENERIC_NAMED_PROPERTY_SETTER_CALLBACK))
5933            set_value = callback_function_name(cgc, for_cross_origin=True)
5934            func_def = make_attribute_set_callback_def(cgc, set_value)
5935            callback_defs.extend([func_def, EmptyNode()])
5936        pattern = ("{{\"{property_name}\", "
5937                   "{get_func}, {set_func}, {get_value}, {set_value}}},")
5938        entry_nodes.append(
5939            TextNode(
5940                _format(
5941                    pattern,
5942                    property_name=attribute.identifier,
5943                    get_func=get_func,
5944                    set_func=set_func,
5945                    get_value=get_value,
5946                    set_value=set_value)))
5947    callback_defs.append(
5948        ListNode([
5949            TextNode("constexpr bindings::CrossOriginAttributeTableEntry "
5950                     "kCrossOriginAttributeTable[] = {"),
5951            ListNode(entry_nodes),
5952            TextNode("};"),
5953            EmptyNode(),
5954        ]))
5955
5956    entry_nodes = []
5957    for entry in operation_entries:
5958        operation_group = entry.property_
5959        if "CrossOrigin" not in operation_group.extended_attributes:
5960            continue
5961        assert entry.world == CodeGenContext.ALL_WORLDS
5962        entry_nodes.append(
5963            TextNode(
5964                _format(
5965                    "{{\"{property_name}\", {op_callback}, {op_func_length}}},",
5966                    property_name=operation_group.identifier,
5967                    op_callback=entry.op_callback_name,
5968                    op_func_length=entry.op_func_length)))
5969    callback_defs.append(
5970        ListNode([
5971            TextNode("constexpr bindings::CrossOriginOperationTableEntry "
5972                     "kCrossOriginOperationTable[] = {"),
5973            ListNode(entry_nodes),
5974            TextNode("};"),
5975            EmptyNode(),
5976        ]))
5977
5978    cg_context = cg_context.make_copy(
5979        v8_callback_type=CodeGenContext.V8_OTHER_CALLBACK)
5980
5981    func_defs = [
5982        make_cross_origin_access_check_callback(
5983            cg_context, "CrossOriginAccessCheckCallback"),
5984        make_cross_origin_named_getter_callback(
5985            cg_context, "CrossOriginNamedGetterCallback"),
5986        make_cross_origin_named_setter_callback(
5987            cg_context, "CrossOriginNamedSetterCallback"),
5988        make_cross_origin_named_deleter_callback(
5989            cg_context, "CrossOriginNamedDeleterCallback"),
5990        make_cross_origin_named_definer_callback(
5991            cg_context, "CrossOriginNamedDefinerCallback"),
5992        make_cross_origin_named_descriptor_callback(
5993            cg_context, "CrossOriginNamedDescriptorCallback"),
5994        make_cross_origin_named_query_callback(
5995            cg_context, "CrossOriginNamedQueryCallback"),
5996        make_cross_origin_named_enumerator_callback(
5997            cg_context, "CrossOriginNamedEnumeratorCallback"),
5998        make_cross_origin_indexed_getter_callback(
5999            cg_context.make_copy(
6000                indexed_property_getter=(props and props.indexed_getter)),
6001            "CrossOriginIndexedGetterCallback"),
6002        make_cross_origin_indexed_setter_callback(
6003            cg_context, "CrossOriginIndexedSetterCallback"),
6004        make_cross_origin_indexed_deleter_callback(
6005            cg_context, "CrossOriginIndexedDeleterCallback"),
6006        make_cross_origin_indexed_definer_callback(
6007            cg_context, "CrossOriginIndexedDefinerCallback"),
6008        make_cross_origin_indexed_descriptor_callback(
6009            cg_context, "CrossOriginIndexedDescriptorCallback"),
6010        make_cross_origin_indexed_enumerator_callback(
6011            cg_context, "CrossOriginIndexedEnumeratorCallback"),
6012    ]
6013    for func_def in func_defs:
6014        callback_defs.append(func_def)
6015        callback_defs.append(EmptyNode())
6016
6017    text = """\
6018// Cross origin properties
6019${instance_object_template}->SetAccessCheckCallbackAndHandler(
6020    CrossOriginAccessCheckCallback,
6021    v8::NamedPropertyHandlerConfiguration(
6022        CrossOriginNamedGetterCallback,
6023        CrossOriginNamedSetterCallback,
6024        CrossOriginNamedQueryCallback,
6025        CrossOriginNamedDeleterCallback,
6026        CrossOriginNamedEnumeratorCallback,
6027        CrossOriginNamedDefinerCallback,
6028        CrossOriginNamedDescriptorCallback,
6029        v8::Local<v8::Value>(),
6030        v8::PropertyHandlerFlags::kNone),
6031    v8::IndexedPropertyHandlerConfiguration(
6032        CrossOriginIndexedGetterCallback,
6033        CrossOriginIndexedSetterCallback,
6034        nullptr,  // query
6035        CrossOriginIndexedDeleterCallback,
6036        CrossOriginIndexedEnumeratorCallback,
6037        CrossOriginIndexedDefinerCallback,
6038        CrossOriginIndexedDescriptorCallback,
6039        v8::Local<v8::Value>(),
6040        v8::PropertyHandlerFlags::kNone),
6041    v8::External::New(
6042        ${isolate},
6043        const_cast<WrapperTypeInfo*>(${class_name}::GetWrapperTypeInfo())));
6044"""
6045    install_node.append(TextNode(text))
6046    install_node.accumulate(
6047        CodeGenAccumulator.require_include_headers([
6048            "third_party/blink/renderer/bindings/core/v8/binding_security.h",
6049            "third_party/blink/renderer/platform/bindings/v8_cross_origin_property_support.h",
6050        ]))
6051
6052    if cg_context.interface.identifier != "Window":
6053        return callback_defs, install_node
6054
6055    func_defs = [
6056        make_same_origin_indexed_getter_callback(
6057            cg_context.make_copy(
6058                indexed_property_getter=(props and props.indexed_getter)),
6059            "SameOriginIndexedGetterCallback"),
6060        make_same_origin_indexed_setter_callback(
6061            cg_context, "SameOriginIndexedSetterCallback"),
6062        make_same_origin_indexed_deleter_callback(
6063            cg_context, "SameOriginIndexedDeleterCallback"),
6064        make_same_origin_indexed_definer_callback(
6065            cg_context, "SameOriginIndexedDefinerCallback"),
6066        make_same_origin_indexed_descriptor_callback(
6067            cg_context, "SameOriginIndexedDescriptorCallback"),
6068        make_same_origin_indexed_enumerator_callback(
6069            cg_context, "SameOriginIndexedEnumeratorCallback"),
6070    ]
6071    for func_def in func_defs:
6072        callback_defs.append(func_def)
6073        callback_defs.append(EmptyNode())
6074
6075    text = """\
6076// Same origin interceptors
6077${instance_object_template}->SetHandler(
6078    v8::IndexedPropertyHandlerConfiguration(
6079        SameOriginIndexedGetterCallback,
6080        SameOriginIndexedSetterCallback,
6081        nullptr,  // query
6082        SameOriginIndexedDeleterCallback,
6083        SameOriginIndexedEnumeratorCallback,
6084        SameOriginIndexedDefinerCallback,
6085        SameOriginIndexedDescriptorCallback,
6086        v8::Local<v8::Value>(),
6087        v8::PropertyHandlerFlags::kNone));
6088"""
6089    install_node.append(TextNode(text))
6090
6091    return callback_defs, install_node
6092
6093
6094def make_cross_component_init(
6095        cg_context, function_name, class_name, has_unconditional_props,
6096        has_context_independent_props, has_context_dependent_props):
6097    """
6098    Returns:
6099        A triplet of CodeNode of:
6100        - function declaration
6101        - function definition
6102        - trampoline member variable definitions
6103    """
6104    assert isinstance(cg_context, CodeGenContext)
6105    assert isinstance(function_name, str)
6106    assert isinstance(class_name, str)
6107    assert isinstance(has_unconditional_props, bool)
6108    assert isinstance(has_context_independent_props, bool)
6109    assert isinstance(has_context_dependent_props, bool)
6110
6111    T = TextNode
6112    F = lambda *args, **kwargs: T(_format(*args, **kwargs))
6113
6114    def filter_four_trampolines(nodes):
6115        assert len(nodes) == 4
6116        flags = (True, has_unconditional_props, has_context_independent_props,
6117                 has_context_dependent_props)
6118        return [node for node, flag in zip(nodes, flags) if flag]
6119
6120    trampoline_var_decls = ListNode(
6121        filter_four_trampolines([
6122            F("static InstallInterfaceTemplateFuncType {};",
6123              TP_INSTALL_INTERFACE_TEMPLATE),
6124            F("static InstallUnconditionalPropertiesFuncType {};",
6125              TP_INSTALL_UNCONDITIONAL_PROPS),
6126            F("static InstallContextIndependentPropertiesFuncType {};",
6127              TP_INSTALL_CONTEXT_INDEPENDENT_PROPS),
6128            F("static InstallContextDependentPropertiesFuncType {};",
6129              TP_INSTALL_CONTEXT_DEPENDENT_PROPS),
6130        ]))
6131
6132    trampoline_var_defs = ListNode(
6133        filter_four_trampolines([
6134            F(("${class_name}::InstallInterfaceTemplateFuncType "
6135               "${class_name}::{} = nullptr;"), TP_INSTALL_INTERFACE_TEMPLATE),
6136            F(("${class_name}::InstallUnconditionalPropertiesFuncType "
6137               "${class_name}::{} = nullptr;"),
6138              TP_INSTALL_UNCONDITIONAL_PROPS),
6139            F(("${class_name}::InstallContextIndependentPropertiesFuncType "
6140               "${class_name}::{} = nullptr;"),
6141              TP_INSTALL_CONTEXT_INDEPENDENT_PROPS),
6142            F(("${class_name}::InstallContextDependentPropertiesFuncType "
6143               "${class_name}::{} = nullptr;"),
6144              TP_INSTALL_CONTEXT_DEPENDENT_PROPS),
6145        ]))
6146    trampoline_var_defs.set_base_template_vars(cg_context.template_bindings())
6147
6148    func_decl = CxxFuncDeclNode(
6149        name=function_name, arg_decls=[], return_type="void", static=True)
6150
6151    func_def = CxxFuncDefNode(
6152        name=function_name,
6153        arg_decls=[],
6154        return_type="void",
6155        class_name=class_name)
6156    func_def.set_base_template_vars(cg_context.template_bindings())
6157
6158    body = func_def.body
6159    body.extend(
6160        filter_four_trampolines([
6161            F("${class_name}::{} = {};", TP_INSTALL_INTERFACE_TEMPLATE,
6162              FN_INSTALL_INTERFACE_TEMPLATE),
6163            F("${class_name}::{} = {};", TP_INSTALL_UNCONDITIONAL_PROPS,
6164              FN_INSTALL_UNCONDITIONAL_PROPS),
6165            F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_INDEPENDENT_PROPS,
6166              FN_INSTALL_CONTEXT_INDEPENDENT_PROPS),
6167            F("${class_name}::{} = {};", TP_INSTALL_CONTEXT_DEPENDENT_PROPS,
6168              FN_INSTALL_CONTEXT_DEPENDENT_PROPS),
6169        ]))
6170
6171    return func_decl, func_def, trampoline_var_decls, trampoline_var_defs
6172
6173
6174# ----------------------------------------------------------------------------
6175# WrapperTypeInfo
6176# ----------------------------------------------------------------------------
6177
6178
6179def make_wrapper_type_info(cg_context, function_name,
6180                           has_context_dependent_props):
6181    assert isinstance(cg_context, CodeGenContext)
6182    assert function_name == "GetWrapperTypeInfo"
6183    assert isinstance(has_context_dependent_props, bool)
6184
6185    F = lambda *args, **kwargs: TextNode(_format(*args, **kwargs))
6186
6187    func_def = CxxFuncDefNode(
6188        name=function_name,
6189        arg_decls=[],
6190        return_type="constexpr const WrapperTypeInfo*",
6191        static=True)
6192    func_def.set_base_template_vars(cg_context.template_bindings())
6193    func_def.body.append(TextNode("return &wrapper_type_info_;"))
6194
6195    member_var_def = TextNode(
6196        "static const WrapperTypeInfo wrapper_type_info_;")
6197
6198    wrapper_type_info_def = ListNode()
6199    wrapper_type_info_def.set_base_template_vars(
6200        cg_context.template_bindings())
6201
6202    pattern = """\
6203// Construction of WrapperTypeInfo may require non-trivial initialization due
6204// to cross-component address resolution in order to load the pointer to the
6205// parent interface's WrapperTypeInfo.  We ignore this issue because the issue
6206// happens only on component builds and the official release builds
6207// (statically-linked builds) are never affected by this issue.
6208#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
6209#pragma clang diagnostic push
6210#pragma clang diagnostic ignored "-Wglobal-constructors"
6211#endif
6212
6213const WrapperTypeInfo ${class_name}::wrapper_type_info_{{
6214    gin::kEmbedderBlink,
6215    ${class_name}::{install_interface_template_func},
6216    {install_context_dependent_func},
6217    "${{class_like.identifier}}",
6218    {wrapper_type_info_of_inherited},
6219    {wrapper_type_prototype},
6220    {wrapper_class_id},
6221    {active_script_wrappable_inheritance},
6222    {idl_definition_kind},
6223}};
6224
6225#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
6226#pragma clang diagnostic pop
6227#endif
6228"""
6229    class_like = cg_context.class_like
6230    if has_context_dependent_props:
6231        install_context_dependent_func = _format(
6232            "${class_name}::{}", FN_INSTALL_CONTEXT_DEPENDENT_PROPS)
6233    else:
6234        install_context_dependent_func = "nullptr"
6235    if class_like.is_interface and class_like.inherited:
6236        wrapper_type_info_of_inherited = "{}::GetWrapperTypeInfo()".format(
6237            v8_bridge_class_name(class_like.inherited))
6238    else:
6239        wrapper_type_info_of_inherited = "nullptr"
6240    if class_like.is_interface:
6241        wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeObjectPrototype"
6242    else:
6243        wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeNoPrototype"
6244    if class_like.is_interface and class_like.does_implement("Node"):
6245        wrapper_class_id = "WrapperTypeInfo::kNodeClassId"
6246    else:
6247        wrapper_class_id = "WrapperTypeInfo::kObjectClassId"
6248    if class_like.code_generator_info.is_active_script_wrappable:
6249        active_script_wrappable_inheritance = (
6250            "WrapperTypeInfo::kInheritFromActiveScriptWrappable")
6251    else:
6252        active_script_wrappable_inheritance = (
6253            "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable")
6254    if class_like.is_interface:
6255        idl_definition_kind = "WrapperTypeInfo::kIdlInterface"
6256    elif class_like.is_namespace:
6257        idl_definition_kind = "WrapperTypeInfo::kIdlNamespace"
6258    elif class_like.is_callback_interface:
6259        idl_definition_kind = "WrapperTypeInfo::kIdlCallbackInterface"
6260    wrapper_type_info_def.append(
6261        F(pattern,
6262          install_interface_template_func=FN_INSTALL_INTERFACE_TEMPLATE,
6263          install_context_dependent_func=install_context_dependent_func,
6264          wrapper_type_info_of_inherited=wrapper_type_info_of_inherited,
6265          wrapper_type_prototype=wrapper_type_prototype,
6266          wrapper_class_id=wrapper_class_id,
6267          active_script_wrappable_inheritance=(
6268              active_script_wrappable_inheritance),
6269          idl_definition_kind=idl_definition_kind))
6270
6271    if class_like.is_interface:
6272        blink_class = blink_class_name(class_like)
6273        pattern = """\
6274const WrapperTypeInfo& {blink_class}::wrapper_type_info_ =
6275    ${class_name}::wrapper_type_info_;
6276"""
6277        wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
6278
6279    if class_like.code_generator_info.is_active_script_wrappable:
6280        pattern = """\
6281// [ActiveScriptWrappable]
6282static_assert(
6283    std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value,
6284    "{blink_class} does not inherit from ActiveScriptWrappable<> despite "
6285    "the IDL has [ActiveScriptWrappable] extended attribute.");
6286static_assert(
6287    !std::is_same<decltype(&{blink_class}::HasPendingActivity),
6288                  decltype(&ScriptWrappable::HasPendingActivity)>::value,
6289    "{blink_class} is not overriding hasPendingActivity() despite "
6290    "the IDL has [ActiveScriptWrappable] extended attribute.");"""
6291    else:
6292        pattern = """\
6293// non-[ActiveScriptWrappable]
6294static_assert(
6295    !std::is_base_of<ActiveScriptWrappableBase, {blink_class}>::value,
6296    "{blink_class} inherits from ActiveScriptWrappable<> without "
6297    "[ActiveScriptWrappable] extended attribute.");
6298static_assert(
6299    std::is_same<decltype(&{blink_class}::HasPendingActivity),
6300                 decltype(&ScriptWrappable::HasPendingActivity)>::value,
6301    "{blink_class} is overriding hasPendingActivity() without "
6302    "[ActiveScriptWrappable] extended attribute.");"""
6303    if class_like.is_interface:
6304        wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
6305
6306    return func_def, member_var_def, wrapper_type_info_def
6307
6308
6309# ----------------------------------------------------------------------------
6310# V8 Context Snapshot
6311# ----------------------------------------------------------------------------
6312
6313
6314def make_v8_context_snapshot_api(cg_context, component, attribute_entries,
6315                                 constant_entries, constructor_entries,
6316                                 exposed_construct_entries, operation_entries,
6317                                 named_properties_object_callback_defs,
6318                                 cross_origin_property_callback_defs,
6319                                 install_context_independent_func_name):
6320    assert isinstance(cg_context, CodeGenContext)
6321    assert isinstance(component, web_idl.Component)
6322
6323    if not cg_context.interface:
6324        return None, None
6325
6326    derived_interfaces = cg_context.interface.deriveds
6327    derived_names = map(lambda interface: interface.identifier,
6328                        derived_interfaces)
6329    derived_names.append(cg_context.interface.identifier)
6330    if not ("Window" in derived_names or "HTMLDocument" in derived_names):
6331        return None, None
6332
6333    header_ns = CxxNamespaceNode(name_style.namespace("v8_context_snapshot"))
6334    source_ns = CxxNamespaceNode(name_style.namespace("v8_context_snapshot"))
6335
6336    export_text = component_export(component, False)
6337
6338    def add_func(func_decl, func_def):
6339        header_ns.body.extend([
6340            TextNode(export_text),
6341            func_decl,
6342            EmptyNode(),
6343        ])
6344        source_ns.body.extend([
6345            func_def,
6346            EmptyNode(),
6347        ])
6348
6349    add_func(*_make_v8_context_snapshot_get_reference_table_function(
6350        cg_context, name_style.func("GetRefTableOf",
6351                                    cg_context.class_name), attribute_entries,
6352        constant_entries, constructor_entries, exposed_construct_entries,
6353        operation_entries, named_properties_object_callback_defs,
6354        cross_origin_property_callback_defs))
6355
6356    add_func(*_make_v8_context_snapshot_install_props_per_context_function(
6357        cg_context, name_style.func("InstallPropsOf",
6358                                    cg_context.class_name), attribute_entries,
6359        constant_entries, exposed_construct_entries, operation_entries))
6360
6361    add_func(*_make_v8_context_snapshot_install_props_per_isolate_function(
6362        cg_context, name_style.func("InstallPropsOf", cg_context.class_name),
6363        install_context_independent_func_name))
6364
6365    return header_ns, source_ns
6366
6367
6368def _make_v8_context_snapshot_get_reference_table_function(
6369        cg_context, function_name, attribute_entries, constant_entries,
6370        constructor_entries, exposed_construct_entries, operation_entries,
6371        named_properties_object_callback_defs,
6372        cross_origin_property_callback_defs):
6373    callback_names = ["${class_name}::GetWrapperTypeInfo()"]
6374
6375    for entry in attribute_entries:
6376        if entry.exposure_conditional.is_always_true:
6377            callback_names.append(entry.attr_get_callback_name)
6378            callback_names.append(entry.attr_set_callback_name)
6379    for entry in constant_entries:
6380        if entry.exposure_conditional.is_always_true:
6381            callback_names.append(entry.const_callback_name)
6382    for entry in constructor_entries:
6383        if entry.exposure_conditional.is_always_true:
6384            callback_names.append(entry.ctor_callback_name)
6385    for entry in exposed_construct_entries:
6386        if entry.exposure_conditional.is_always_true:
6387            callback_names.append(entry.prop_callback_name)
6388    for entry in operation_entries:
6389        if entry.exposure_conditional.is_always_true:
6390            callback_names.append(entry.op_callback_name)
6391
6392    def collect_callbacks(node):
6393        if isinstance(node, CxxFuncDefNode):
6394            callback_names.append(node.function_name)
6395        elif hasattr(node, "__iter__"):
6396            for child_node in node:
6397                collect_callbacks(child_node)
6398
6399    collect_callbacks(named_properties_object_callback_defs)
6400    collect_callbacks(cross_origin_property_callback_defs)
6401
6402    entry_nodes = map(
6403        lambda name: TextNode("reinterpret_cast<intptr_t>({}),".format(name)),
6404        filter(None, callback_names))
6405    table_node = ListNode([
6406        TextNode("static const intptr_t kReferenceTable[] = {"),
6407        ListNode(entry_nodes),
6408        TextNode("};"),
6409    ])
6410
6411    func_decl = CxxFuncDeclNode(name=function_name,
6412                                arg_decls=[],
6413                                return_type="base::span<const intptr_t>")
6414
6415    func_def = CxxFuncDefNode(name=function_name,
6416                              arg_decls=[],
6417                              return_type="base::span<const intptr_t>")
6418    func_def.set_base_template_vars(cg_context.template_bindings())
6419    body = func_def.body
6420    body.extend([table_node, TextNode("return kReferenceTable;")])
6421
6422    return func_decl, func_def
6423
6424
6425def _make_v8_context_snapshot_install_props_per_context_function(
6426        cg_context, function_name, attribute_entries, constant_entries,
6427        exposed_construct_entries, operation_entries):
6428    def selector(entry):
6429        if entry.exposure_conditional.is_always_true:
6430            return False
6431        if entry.is_context_dependent:
6432            return False
6433        return True
6434
6435    func_decl, func_def, _ = make_install_properties(
6436        cg_context,
6437        function_name,
6438        class_name=None,
6439        prop_install_mode=PropInstallMode.V8_CONTEXT_SNAPSHOT,
6440        trampoline_var_name=None,
6441        attribute_entries=filter(selector, attribute_entries),
6442        constant_entries=filter(selector, constant_entries),
6443        exposed_construct_entries=filter(selector, exposed_construct_entries),
6444        operation_entries=filter(selector, operation_entries))
6445
6446    return func_decl, func_def
6447
6448
6449def _make_v8_context_snapshot_install_props_per_isolate_function(
6450        cg_context, function_name, install_context_independent_func_name):
6451    arg_decls = [
6452        "v8::Isolate* isolate",
6453        "const DOMWrapperWorld& world",
6454        "v8::Local<v8::Template> instance_template",
6455        "v8::Local<v8::Template> prototype_template",
6456        "v8::Local<v8::Template> interface_template",
6457    ]
6458    arg_names = [
6459        "isolate",
6460        "world",
6461        "instance_template",
6462        "prototype_template",
6463        "interface_template",
6464    ]
6465    return_type = "void"
6466
6467    func_decl = CxxFuncDeclNode(name=function_name,
6468                                arg_decls=arg_decls,
6469                                return_type=return_type)
6470    func_def = CxxFuncDefNode(name=function_name,
6471                              arg_decls=arg_decls,
6472                              return_type=return_type)
6473
6474    if not install_context_independent_func_name:
6475        return func_decl, func_def
6476
6477    func_def.set_base_template_vars(cg_context.template_bindings())
6478    body = func_def.body
6479    for arg_name in arg_names:
6480        body.add_template_var(arg_name, arg_name)
6481    pattern = """\
6482return ${class_name}::{func}(
6483    ${isolate}, ${world},
6484    ${instance_template},
6485    ${prototype_template},
6486    ${interface_template});\
6487"""
6488    body.append(
6489        TextNode(_format(pattern, func=install_context_independent_func_name)))
6490    return func_decl, func_def
6491
6492
6493# ----------------------------------------------------------------------------
6494# Main functions
6495# ----------------------------------------------------------------------------
6496
6497
6498def _collect_include_headers(class_like):
6499    assert isinstance(class_like, (web_idl.Interface, web_idl.Namespace))
6500
6501    headers = set(class_like.code_generator_info.blink_headers)
6502
6503    def collect_from_idl_type(idl_type):
6504        idl_type.apply_to_all_composing_elements(add_include_headers)
6505
6506    def add_include_headers(idl_type):
6507        # ScriptPromise doesn't require any header for the result type.
6508        if idl_type.is_promise:
6509            raise StopIteration(idl_type.syntactic_form)
6510
6511        type_def_obj = idl_type.type_definition_object
6512        if type_def_obj is not None:
6513            if (type_def_obj.identifier in (
6514                    "OnErrorEventHandlerNonNull",
6515                    "OnBeforeUnloadEventHandlerNonNull")):
6516                raise StopIteration(idl_type.syntactic_form)
6517
6518            headers.add(PathManager(type_def_obj).api_path(ext="h"))
6519            if type_def_obj.is_interface or type_def_obj.is_namespace:
6520                headers.add(PathManager(type_def_obj).blink_path(ext="h"))
6521            raise StopIteration(idl_type.syntactic_form)
6522
6523        union_def_obj = idl_type.union_definition_object
6524        if union_def_obj is not None:
6525            headers.add(PathManager(union_def_obj).api_path(ext="h"))
6526
6527    for attribute in class_like.attributes:
6528        collect_from_idl_type(attribute.idl_type)
6529    for constructor in class_like.constructors:
6530        for argument in constructor.arguments:
6531            collect_from_idl_type(argument.idl_type)
6532    for operation in class_like.operations:
6533        collect_from_idl_type(operation.return_type)
6534        for argument in operation.arguments:
6535            collect_from_idl_type(argument.idl_type)
6536
6537    if class_like.is_interface:
6538        for exposed_construct in class_like.exposed_constructs:
6539            headers.add(PathManager(exposed_construct).api_path(ext="h"))
6540        for legacy_window_alias in class_like.legacy_window_aliases:
6541            headers.add(
6542                PathManager(legacy_window_alias.original).api_path(ext="h"))
6543
6544    path_manager = PathManager(class_like)
6545    headers.discard(path_manager.api_path(ext="h"))
6546    headers.discard(path_manager.impl_path(ext="h"))
6547
6548    # TODO(yukishiino): Window interface should be
6549    # [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow], and
6550    # [CrossOrigin] properties should be implemented specifically with
6551    # DOMWindow class.  Then, we'll have less hacks.
6552    if class_like.identifier == "Window":
6553        headers.add("third_party/blink/renderer/core/frame/local_dom_window.h")
6554
6555    return headers
6556
6557
6558def generate_class_like(class_like):
6559    assert isinstance(class_like, (web_idl.Interface, web_idl.Namespace))
6560
6561    path_manager = PathManager(class_like)
6562    api_component = path_manager.api_component
6563    impl_component = path_manager.impl_component
6564    is_cross_components = path_manager.is_cross_components
6565    for_testing = class_like.code_generator_info.for_testing
6566
6567    # Class names
6568    api_class_name = v8_bridge_class_name(class_like)
6569    if is_cross_components:
6570        impl_class_name = "{}::Impl".format(api_class_name)
6571    else:
6572        impl_class_name = api_class_name
6573
6574    interface = None
6575    namespace = None
6576    if class_like.is_interface:
6577        interface = class_like
6578        cg_context = CodeGenContext(interface=interface,
6579                                    class_name=api_class_name)
6580    elif class_like.is_namespace:
6581        namespace = class_like
6582        cg_context = CodeGenContext(namespace=namespace,
6583                                    class_name=api_class_name)
6584
6585    # Filepaths
6586    api_header_path = path_manager.api_path(ext="h")
6587    api_source_path = path_manager.api_path(ext="cc")
6588    if is_cross_components:
6589        impl_header_path = path_manager.impl_path(ext="h")
6590        impl_source_path = path_manager.impl_path(ext="cc")
6591
6592    # Root nodes
6593    api_header_node = ListNode(tail="\n")
6594    api_header_node.set_accumulator(CodeGenAccumulator())
6595    api_header_node.set_renderer(MakoRenderer())
6596    api_source_node = ListNode(tail="\n")
6597    api_source_node.set_accumulator(CodeGenAccumulator())
6598    api_source_node.set_renderer(MakoRenderer())
6599    if is_cross_components:
6600        impl_header_node = ListNode(tail="\n")
6601        impl_header_node.set_accumulator(CodeGenAccumulator())
6602        impl_header_node.set_renderer(MakoRenderer())
6603        impl_source_node = ListNode(tail="\n")
6604        impl_source_node.set_accumulator(CodeGenAccumulator())
6605        impl_source_node.set_renderer(MakoRenderer())
6606    else:
6607        impl_header_node = api_header_node
6608        impl_source_node = api_source_node
6609
6610    # Namespaces
6611    api_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
6612    api_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
6613    if is_cross_components:
6614        impl_header_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
6615        impl_source_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
6616    else:
6617        impl_header_blink_ns = api_header_blink_ns
6618        impl_source_blink_ns = api_source_blink_ns
6619
6620    # Class definitions
6621    api_class_def = CxxClassDefNode(
6622        cg_context.class_name,
6623        base_class_names=[
6624            _format("bindings::V8InterfaceBridge<${class_name}, {}>",
6625                    blink_class_name(class_like)),
6626        ],
6627        final=True,
6628        export=component_export(api_component, for_testing))
6629    api_class_def.set_base_template_vars(cg_context.template_bindings())
6630    api_class_def.bottom_section.append(
6631        TextNode("friend class {};".format(blink_class_name(class_like))))
6632    if is_cross_components:
6633        impl_class_def = CxxClassDefNode(impl_class_name,
6634                                         final=True,
6635                                         export=component_export(
6636                                             impl_component, for_testing))
6637        impl_class_def.set_base_template_vars(cg_context.template_bindings())
6638        api_class_def.public_section.extend([
6639            TextNode("// Cross-component implementation class"),
6640            TextNode("class Impl;"),
6641            EmptyNode(),
6642        ])
6643    else:
6644        impl_class_def = api_class_def
6645
6646    # Constants
6647    constants_def = None
6648    if class_like.constants:
6649        constants_def = CxxClassDefNode(name="Constant", final=True)
6650        constants_def.top_section.append(TextNode("STATIC_ONLY(Constant);"))
6651        for constant in class_like.constants:
6652            cgc = cg_context.make_copy(constant=constant)
6653            constants_def.public_section.append(
6654                make_constant_constant_def(cgc, constant_name(cgc)))
6655
6656    # Custom callback implementations
6657    custom_callback_impl_decls = ListNode()
6658
6659    def add_custom_callback_impl_decl(**params):
6660        arg_decls = params.pop("arg_decls")
6661        name = params.pop("name", None)
6662        if name is None:
6663            name = custom_function_name(cg_context.make_copy(**params))
6664        custom_callback_impl_decls.append(
6665            CxxFuncDeclNode(
6666                name=name,
6667                arg_decls=arg_decls,
6668                return_type="void",
6669                static=True))
6670
6671    if class_like.identifier == "HTMLAllCollection":
6672        add_custom_callback_impl_decl(
6673            name=name_style.func("LegacyCallCustom"),
6674            arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"])
6675    for attribute in class_like.attributes:
6676        custom_values = attribute.extended_attributes.values_of("Custom")
6677        is_cross_origin = "CrossOrigin" in attribute.extended_attributes
6678        cross_origin_values = attribute.extended_attributes.values_of(
6679            "CrossOrigin")
6680        if "Getter" in custom_values:
6681            add_custom_callback_impl_decl(
6682                attribute=attribute,
6683                attribute_get=True,
6684                arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"])
6685            if is_cross_origin and (not cross_origin_values
6686                                    or "Getter" in cross_origin_values):
6687                add_custom_callback_impl_decl(
6688                    attribute=attribute,
6689                    attribute_get=True,
6690                    arg_decls=["const v8::PropertyCallbackInfo<v8::Value>&"])
6691        if "Setter" in custom_values:
6692            add_custom_callback_impl_decl(
6693                attribute=attribute,
6694                attribute_set=True,
6695                arg_decls=[
6696                    "v8::Local<v8::Value>",
6697                    "const v8::FunctionCallbackInfo<v8::Value>&",
6698                ])
6699            if is_cross_origin and (not cross_origin_values
6700                                    or "Setter" in cross_origin_values):
6701                add_custom_callback_impl_decl(
6702                    attribute=attribute,
6703                    attribute_set=True,
6704                    arg_decls=[
6705                        "v8::Local<v8::Value>",
6706                        "const v8::PropertyCallbackInfo<void>&",
6707                    ])
6708    for operation_group in class_like.operation_groups:
6709        if "Custom" in operation_group.extended_attributes:
6710            add_custom_callback_impl_decl(
6711                operation_group=operation_group,
6712                arg_decls=["const v8::FunctionCallbackInfo<v8::Value>&"])
6713    if interface and interface.indexed_and_named_properties:
6714        props = interface.indexed_and_named_properties
6715        operation = props.own_named_getter
6716        if operation and "Custom" in operation.extended_attributes:
6717            add_custom_callback_impl_decl(
6718                named_property_getter=operation,
6719                arg_decls=[
6720                    "const AtomicString& property_name",
6721                    "const v8::PropertyCallbackInfo<v8::Value>&",
6722                ])
6723        operation = props.own_named_setter
6724        if operation and "Custom" in operation.extended_attributes:
6725            add_custom_callback_impl_decl(
6726                named_property_setter=operation,
6727                arg_decls=[
6728                    "const AtomicString& property_name",
6729                    "v8::Local<v8::Value> v8_property_value",
6730                    "const v8::PropertyCallbackInfo<v8::Value>&",
6731                ])
6732        operation = props.own_named_deleter
6733        if operation and "Custom" in operation.extended_attributes:
6734            add_custom_callback_impl_decl(
6735                named_property_deleter=operation,
6736                arg_decls=[
6737                    "const AtomicString& property_name",
6738                    "const v8::PropertyCallbackInfo<v8::Value>&",
6739                ])
6740
6741    # Cross-component trampolines
6742    if is_cross_components:
6743        # tp_ = trampoline name
6744        tp_install_interface_template = TP_INSTALL_INTERFACE_TEMPLATE
6745        tp_install_unconditional_props = TP_INSTALL_UNCONDITIONAL_PROPS
6746        tp_install_context_independent_props = (
6747            TP_INSTALL_CONTEXT_INDEPENDENT_PROPS)
6748        tp_install_context_dependent_props = TP_INSTALL_CONTEXT_DEPENDENT_PROPS
6749    else:
6750        tp_install_interface_template = None
6751        tp_install_unconditional_props = None
6752        tp_install_context_independent_props = None
6753        tp_install_context_dependent_props = None
6754
6755    # Callback functions
6756    attribute_entries = []
6757    constant_entries = []
6758    constructor_entries = []
6759    exposed_construct_entries = []
6760    operation_entries = []
6761    callback_defs = make_property_entries_and_callback_defs(
6762        cg_context,
6763        attribute_entries=attribute_entries,
6764        constant_entries=constant_entries,
6765        constructor_entries=constructor_entries,
6766        exposed_construct_entries=exposed_construct_entries,
6767        operation_entries=operation_entries)
6768    supplemental_install_node = SequenceNode()
6769
6770    # Indexed and named properties
6771    # Shorten a function name to mitigate a style check error.
6772    f = make_indexed_and_named_property_callbacks_and_install_node
6773    (indexed_and_named_property_decls, indexed_and_named_property_defs,
6774     indexed_and_named_property_install_node) = f(cg_context)
6775    supplemental_install_node.append(indexed_and_named_property_install_node)
6776    supplemental_install_node.append(EmptyNode())
6777
6778    # Named properties object
6779    (named_properties_object_callback_defs,
6780     named_properties_object_install_node) = (
6781         make_named_properties_object_callbacks_and_install_node(cg_context))
6782    callback_defs.extend(named_properties_object_callback_defs)
6783    supplemental_install_node.append(named_properties_object_install_node)
6784    supplemental_install_node.append(EmptyNode())
6785
6786    # Cross origin properties
6787    (cross_origin_property_callback_defs,
6788     cross_origin_property_install_node) = (
6789         make_cross_origin_property_callbacks_and_install_node(
6790             cg_context, attribute_entries, operation_entries))
6791    callback_defs.extend(cross_origin_property_callback_defs)
6792    supplemental_install_node.append(cross_origin_property_install_node)
6793    supplemental_install_node.append(EmptyNode())
6794
6795    # Installer functions
6796    is_unconditional = lambda entry: entry.exposure_conditional.is_always_true
6797    is_context_dependent = lambda entry: entry.is_context_dependent
6798    is_context_independent = (
6799        lambda e: not is_context_dependent(e) and not is_unconditional(e))
6800    (install_unconditional_props_decl, install_unconditional_props_def,
6801     install_unconditional_props_trampoline) = make_install_properties(
6802         cg_context,
6803         FN_INSTALL_UNCONDITIONAL_PROPS,
6804         class_name=impl_class_name,
6805         prop_install_mode=PropInstallMode.UNCONDITIONAL,
6806         trampoline_var_name=tp_install_unconditional_props,
6807         attribute_entries=filter(is_unconditional, attribute_entries),
6808         constant_entries=filter(is_unconditional, constant_entries),
6809         exposed_construct_entries=filter(is_unconditional,
6810                                          exposed_construct_entries),
6811         operation_entries=filter(is_unconditional, operation_entries))
6812    (install_context_independent_props_decl,
6813     install_context_independent_props_def,
6814     install_context_independent_props_trampoline) = make_install_properties(
6815         cg_context,
6816         FN_INSTALL_CONTEXT_INDEPENDENT_PROPS,
6817         class_name=impl_class_name,
6818         prop_install_mode=PropInstallMode.CONTEXT_INDEPENDENT,
6819         trampoline_var_name=tp_install_context_independent_props,
6820         attribute_entries=filter(is_context_independent, attribute_entries),
6821         constant_entries=filter(is_context_independent, constant_entries),
6822         exposed_construct_entries=filter(is_context_independent,
6823                                          exposed_construct_entries),
6824         operation_entries=filter(is_context_independent, operation_entries))
6825    (install_context_dependent_props_decl, install_context_dependent_props_def,
6826     install_context_dependent_props_trampoline) = make_install_properties(
6827         cg_context,
6828         FN_INSTALL_CONTEXT_DEPENDENT_PROPS,
6829         class_name=impl_class_name,
6830         prop_install_mode=PropInstallMode.CONTEXT_DEPENDENT,
6831         trampoline_var_name=tp_install_context_dependent_props,
6832         attribute_entries=filter(is_context_dependent, attribute_entries),
6833         constant_entries=filter(is_context_dependent, constant_entries),
6834         exposed_construct_entries=filter(is_context_dependent,
6835                                          exposed_construct_entries),
6836         operation_entries=filter(is_context_dependent, operation_entries))
6837    (install_interface_template_decl, install_interface_template_def,
6838     install_interface_template_trampoline) = make_install_interface_template(
6839         cg_context,
6840         FN_INSTALL_INTERFACE_TEMPLATE,
6841         class_name=impl_class_name,
6842         trampoline_var_name=tp_install_interface_template,
6843         constructor_entries=constructor_entries,
6844         supplemental_install_node=supplemental_install_node,
6845         install_unconditional_func_name=(install_unconditional_props_def
6846                                          and FN_INSTALL_UNCONDITIONAL_PROPS),
6847         install_context_independent_func_name=(
6848             install_context_independent_props_def
6849             and FN_INSTALL_CONTEXT_INDEPENDENT_PROPS))
6850    installer_function_decls = ListNode([
6851        install_interface_template_decl,
6852        install_unconditional_props_decl,
6853        install_context_independent_props_decl,
6854        install_context_dependent_props_decl,
6855    ])
6856    installer_function_defs = ListNode([
6857        install_interface_template_def,
6858        EmptyNode(),
6859        install_unconditional_props_def,
6860        EmptyNode(),
6861        install_context_independent_props_def,
6862        EmptyNode(),
6863        install_context_dependent_props_def,
6864    ])
6865    installer_function_trampolines = ListNode([
6866        install_interface_template_trampoline,
6867        install_unconditional_props_trampoline,
6868        install_context_independent_props_trampoline,
6869        install_context_dependent_props_trampoline,
6870    ])
6871
6872    # WrapperTypeInfo
6873    (get_wrapper_type_info_def, wrapper_type_info_var_def,
6874     wrapper_type_info_init) = make_wrapper_type_info(
6875         cg_context,
6876         "GetWrapperTypeInfo",
6877         has_context_dependent_props=bool(
6878             install_context_dependent_props_decl))
6879
6880    # Cross-component trampolines
6881    if is_cross_components:
6882        (cross_component_init_decl, cross_component_init_def,
6883         trampoline_var_decls,
6884         trampoline_var_defs) = make_cross_component_init(
6885             cg_context,
6886             "Init",
6887             class_name=impl_class_name,
6888             has_unconditional_props=bool(install_unconditional_props_decl),
6889             has_context_independent_props=bool(
6890                 install_context_independent_props_decl),
6891             has_context_dependent_props=bool(
6892                 install_context_dependent_props_decl))
6893
6894    # V8 Context Snapshot
6895    (header_v8_context_snapshot_ns,
6896     source_v8_context_snapshot_ns) = make_v8_context_snapshot_api(
6897         cg_context, impl_component, attribute_entries, constant_entries,
6898         constructor_entries, exposed_construct_entries, operation_entries,
6899         named_properties_object_callback_defs,
6900         cross_origin_property_callback_defs,
6901         (install_context_independent_props_def
6902          and FN_INSTALL_CONTEXT_INDEPENDENT_PROPS))
6903
6904    # Header part (copyright, include directives, and forward declarations)
6905    api_header_node.extend([
6906        make_copyright_header(),
6907        EmptyNode(),
6908        enclose_with_header_guard(
6909            ListNode([
6910                make_header_include_directives(api_header_node.accumulator),
6911                EmptyNode(),
6912                api_header_blink_ns,
6913            ]), name_style.header_guard(api_header_path)),
6914    ])
6915    api_header_blink_ns.body.extend([
6916        make_forward_declarations(api_header_node.accumulator),
6917        EmptyNode(),
6918    ])
6919    api_source_node.extend([
6920        make_copyright_header(),
6921        EmptyNode(),
6922        TextNode("#include \"{}\"".format(api_header_path)),
6923        EmptyNode(),
6924        make_header_include_directives(api_source_node.accumulator),
6925        EmptyNode(),
6926        api_source_blink_ns,
6927    ])
6928    api_source_blink_ns.body.extend([
6929        make_forward_declarations(api_source_node.accumulator),
6930        EmptyNode(),
6931    ])
6932    if is_cross_components:
6933        impl_header_node.extend([
6934            make_copyright_header(),
6935            EmptyNode(),
6936            enclose_with_header_guard(
6937                ListNode([
6938                    make_header_include_directives(
6939                        impl_header_node.accumulator),
6940                    EmptyNode(),
6941                    impl_header_blink_ns,
6942                ]), name_style.header_guard(impl_header_path)),
6943        ])
6944        impl_header_blink_ns.body.extend([
6945            make_forward_declarations(impl_header_node.accumulator),
6946            EmptyNode(),
6947        ])
6948        impl_source_node.extend([
6949            make_copyright_header(),
6950            EmptyNode(),
6951            TextNode("#include \"{}\"".format(impl_header_path)),
6952            EmptyNode(),
6953            make_header_include_directives(impl_source_node.accumulator),
6954            EmptyNode(),
6955            impl_source_blink_ns,
6956        ])
6957        impl_source_blink_ns.body.extend([
6958            make_forward_declarations(impl_source_node.accumulator),
6959            EmptyNode(),
6960        ])
6961    api_header_node.accumulator.add_include_headers([
6962        class_like.code_generator_info.blink_headers[0],
6963        component_export_header(api_component, for_testing),
6964        "third_party/blink/renderer/platform/bindings/v8_interface_bridge.h",
6965    ])
6966    if interface and interface.inherited:
6967        api_source_node.accumulator.add_include_headers(
6968            [PathManager(interface.inherited).api_path(ext="h")])
6969    if is_cross_components:
6970        impl_header_node.accumulator.add_include_headers([
6971            api_header_path,
6972            component_export_header(impl_component, for_testing),
6973        ])
6974    impl_source_node.accumulator.add_include_headers([
6975        "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
6976        "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h",
6977        "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h",
6978        "third_party/blink/renderer/platform/bindings/exception_messages.h",
6979        "third_party/blink/renderer/platform/bindings/idl_member_installer.h",
6980        "third_party/blink/renderer/platform/bindings/runtime_call_stats.h",
6981        "third_party/blink/renderer/platform/bindings/v8_binding.h",
6982    ])
6983    impl_source_node.accumulator.add_include_headers(
6984        _collect_include_headers(class_like))
6985
6986    # Assemble the parts.
6987    api_header_blink_ns.body.extend([
6988        api_class_def,
6989        EmptyNode(),
6990    ])
6991    if is_cross_components:
6992        impl_header_blink_ns.body.extend([
6993            impl_class_def,
6994            EmptyNode(),
6995        ])
6996
6997    if constants_def:
6998        api_class_def.public_section.extend([
6999            TextNode("// Constants"),
7000            constants_def,
7001            EmptyNode(),
7002        ])
7003
7004    api_class_def.public_section.append(get_wrapper_type_info_def)
7005    api_class_def.public_section.append(EmptyNode())
7006    api_class_def.private_section.append(wrapper_type_info_var_def)
7007    api_class_def.private_section.append(EmptyNode())
7008    api_source_blink_ns.body.extend([
7009        wrapper_type_info_init,
7010        EmptyNode(),
7011    ])
7012
7013    if is_cross_components:
7014        api_class_def.public_section.append(installer_function_trampolines)
7015        api_class_def.public_section.append(EmptyNode())
7016        api_class_def.private_section.extend([
7017            TextNode("// Cross-component trampolines"),
7018            trampoline_var_decls,
7019            EmptyNode(),
7020        ])
7021        api_source_blink_ns.body.extend([
7022            TextNode("// Cross-component trampolines"),
7023            trampoline_var_defs,
7024            EmptyNode(),
7025        ])
7026        impl_class_def.public_section.append(cross_component_init_decl)
7027        impl_class_def.private_section.append(installer_function_decls)
7028        impl_source_blink_ns.body.extend([
7029            cross_component_init_def,
7030            EmptyNode(),
7031        ])
7032    else:
7033        api_class_def.public_section.append(installer_function_decls)
7034        api_class_def.public_section.append(EmptyNode())
7035
7036    if custom_callback_impl_decls:
7037        api_class_def.public_section.extend([
7038            TextNode("// Custom callback implementations"),
7039            custom_callback_impl_decls,
7040            EmptyNode(),
7041        ])
7042
7043    if indexed_and_named_property_decls:
7044        api_class_def.public_section.extend([
7045            TextNode("// Indexed properties and named properties"),
7046            indexed_and_named_property_decls,
7047            EmptyNode(),
7048        ])
7049        api_source_blink_ns.body.extend([
7050            indexed_and_named_property_defs,
7051            EmptyNode(),
7052        ])
7053
7054    impl_source_blink_ns.body.extend([
7055        CxxNamespaceNode(name="", body=callback_defs),
7056        EmptyNode(),
7057        installer_function_defs,
7058        EmptyNode(),
7059    ])
7060
7061    if header_v8_context_snapshot_ns:
7062        impl_header_blink_ns.body.extend([
7063            CxxNamespaceNode(name=name_style.namespace("bindings"),
7064                             body=header_v8_context_snapshot_ns),
7065            EmptyNode(),
7066        ])
7067        impl_source_blink_ns.body.extend([
7068            CxxNamespaceNode(name=name_style.namespace("bindings"),
7069                             body=source_v8_context_snapshot_ns),
7070            EmptyNode(),
7071        ])
7072
7073    # Write down to the files.
7074    write_code_node_to_file(api_header_node,
7075                            path_manager.gen_path_to(api_header_path))
7076    write_code_node_to_file(api_source_node,
7077                            path_manager.gen_path_to(api_source_path))
7078    if path_manager.is_cross_components:
7079        write_code_node_to_file(impl_header_node,
7080                                path_manager.gen_path_to(impl_header_path))
7081        write_code_node_to_file(impl_source_node,
7082                                path_manager.gen_path_to(impl_source_path))
7083
7084
7085def generate_interface(interface_identifier):
7086    assert isinstance(interface_identifier, web_idl.Identifier)
7087
7088    web_idl_database = package_initializer().web_idl_database()
7089    interface = web_idl_database.find(interface_identifier)
7090
7091    generate_class_like(interface)
7092
7093
7094def generate_install_properties_per_feature(function_name,
7095                                            filepath_basename,
7096                                            for_testing=False):
7097    assert isinstance(function_name, str)
7098    assert isinstance(filepath_basename, str)
7099    assert isinstance(for_testing, bool)
7100
7101    web_idl_database = package_initializer().web_idl_database()
7102
7103    # Filepaths
7104    header_path = PathManager.component_path("modules",
7105                                             "{}.h".format(filepath_basename))
7106    source_path = PathManager.component_path("modules",
7107                                             "{}.cc".format(filepath_basename))
7108
7109    # Root nodes
7110    header_node = ListNode(tail="\n")
7111    header_node.set_accumulator(CodeGenAccumulator())
7112    header_node.set_renderer(MakoRenderer())
7113    source_node = ListNode(tail="\n")
7114    source_node.set_accumulator(CodeGenAccumulator())
7115    source_node.set_renderer(MakoRenderer())
7116
7117    # Namespaces
7118    header_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
7119    source_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
7120    header_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings"))
7121    source_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings"))
7122    header_blink_ns.body.extend([
7123        make_forward_declarations(header_node.accumulator),
7124        EmptyNode(),
7125        header_bindings_ns,
7126    ])
7127    source_blink_ns.body.append(source_bindings_ns)
7128
7129    # Function nodes
7130    arg_decls = [
7131        "ScriptState* script_state",
7132        "OriginTrialFeature feature",
7133    ]
7134    func_decl = CxxFuncDeclNode(
7135        name=function_name, arg_decls=arg_decls, return_type="void")
7136    func_def = CxxFuncDefNode(
7137        name=function_name, arg_decls=arg_decls, return_type="void")
7138    func_def.body.add_template_vars({
7139        "script_state": "script_state",
7140        "feature": "feature",
7141    })
7142    helper_func_def = CxxFuncDefNode(
7143        name="InstallPropertiesPerFeatureInternal",
7144        arg_decls=[
7145            "ScriptState* script_state",
7146            "OriginTrialFeature feature",
7147            "base::span<const WrapperTypeInfo* const> wrapper_type_info_list",
7148        ],
7149        return_type="void")
7150
7151    # Assemble the parts.
7152    header_node.accumulator.add_class_decls(["ScriptState"])
7153    header_node.accumulator.add_include_headers([
7154        "third_party/blink/renderer/platform/runtime_enabled_features.h",
7155    ])
7156    header_node.extend([
7157        make_copyright_header(),
7158        EmptyNode(),
7159        enclose_with_header_guard(
7160            ListNode([
7161                make_header_include_directives(header_node.accumulator),
7162                EmptyNode(),
7163                header_blink_ns,
7164            ]), name_style.header_guard(header_path)),
7165    ])
7166    source_node.accumulator.add_include_headers([
7167        "base/containers/span.h",
7168        "third_party/blink/renderer/platform/bindings/script_state.h",
7169        "third_party/blink/renderer/platform/bindings/v8_per_context_data.h",
7170    ])
7171    source_node.extend([
7172        make_copyright_header(),
7173        EmptyNode(),
7174        TextNode("#include \"{}\"".format(header_path)),
7175        EmptyNode(),
7176        make_header_include_directives(source_node.accumulator),
7177        EmptyNode(),
7178        source_blink_ns,
7179    ])
7180    header_bindings_ns.body.extend([
7181        TextNode("""\
7182// Install ES properties associated with the given origin trial feature.\
7183"""),
7184        func_decl,
7185    ])
7186    source_bindings_ns.body.extend([
7187        CxxNamespaceNode(name="", body=helper_func_def),
7188        EmptyNode(),
7189        func_def,
7190    ])
7191
7192    # The public function
7193    feature_to_class_likes = {}
7194    set_of_class_likes = set()
7195    for class_like in itertools.chain(web_idl_database.interfaces,
7196                                      web_idl_database.namespaces):
7197        if class_like.code_generator_info.for_testing != for_testing:
7198            continue
7199
7200        for member in itertools.chain(class_like.attributes,
7201                                      class_like.constants,
7202                                      class_like.operation_groups,
7203                                      class_like.exposed_constructs):
7204            features = list(
7205                member.exposure.context_dependent_runtime_enabled_features)
7206            for entry in member.exposure.global_names_and_features:
7207                if entry.feature and entry.feature.is_context_dependent:
7208                    features.append(entry.feature)
7209            for feature in features:
7210                feature_to_class_likes.setdefault(feature,
7211                                                  set()).add(class_like)
7212            if features:
7213                set_of_class_likes.add(class_like)
7214
7215    switch_node = CxxSwitchNode(cond="${feature}")
7216    switch_node.append(
7217        case=None,
7218        body=[
7219            TextNode("// Ignore unknown, deprecated, and unused features."),
7220            TextNode("return;"),
7221        ],
7222        should_add_break=False)
7223    for feature, class_likes in sorted(feature_to_class_likes.items()):
7224        entries = [
7225            TextNode("{}::GetWrapperTypeInfo(), ".format(
7226                v8_bridge_class_name(class_like)))
7227            for class_like in sorted(class_likes, key=lambda x: x.identifier)
7228        ]
7229        table_def = ListNode([
7230            TextNode("static const WrapperTypeInfo* const wti_list[] = {"),
7231            ListNode(entries),
7232            TextNode("};"),
7233        ])
7234        switch_node.append(
7235            case="OriginTrialFeature::k{}".format(feature),
7236            body=[
7237                table_def,
7238                TextNode("selected_wti_list = wti_list;"),
7239            ])
7240
7241    func_def.body.extend([
7242        TextNode(
7243            "base::span<const WrapperTypeInfo* const> selected_wti_list;"),
7244        EmptyNode(),
7245        switch_node,
7246        EmptyNode(),
7247        TextNode("InstallPropertiesPerFeatureInternal"
7248                 "(${script_state}, ${feature}, selected_wti_list);"),
7249    ])
7250
7251    for class_like in set_of_class_likes:
7252        path_manager = PathManager(class_like)
7253        source_node.accumulator.add_include_headers(
7254            [path_manager.api_path(ext="h")])
7255
7256    # The helper function
7257    helper_func_def.body.append(
7258        TextNode("""\
7259V8PerContextData* per_context_data = script_state->PerContextData();
7260v8::Isolate* isolate = script_state->GetIsolate();
7261v8::Local<v8::Context> context = script_state->GetContext();
7262const DOMWrapperWorld& world = script_state->World();
7263V8InterfaceBridgeBase::FeatureSelector feature_selector(feature);
7264
7265for (const auto* wrapper_type_info : wrapper_type_info_list) {
7266  v8::Local<v8::Object> instance_object;
7267  v8::Local<v8::Object> prototype_object;
7268  v8::Local<v8::Function> interface_object;
7269  v8::Local<v8::Template> interface_template =
7270      wrapper_type_info->GetV8ClassTemplate(isolate, world);
7271
7272  switch (wrapper_type_info->idl_definition_kind) {
7273    case WrapperTypeInfo::kIdlInterface:
7274      if (!per_context_data->GetExistingConstructorAndPrototypeForType(
7275              wrapper_type_info, &prototype_object, &interface_object)) {
7276        continue;
7277      }
7278      break;
7279    case WrapperTypeInfo::kIdlNamespace:
7280      NOTIMPLEMENTED();
7281      break;
7282    default:
7283      NOTREACHED();
7284  }
7285
7286  wrapper_type_info->install_context_dependent_props_func(
7287      context, world, instance_object, prototype_object,  interface_object,
7288      interface_template, feature_selector);
7289}\
7290"""))
7291
7292    # Write down to the files.
7293    write_code_node_to_file(header_node, path_manager.gen_path_to(header_path))
7294    write_code_node_to_file(source_node, path_manager.gen_path_to(source_path))
7295
7296
7297def generate_init_idl_interfaces(function_name,
7298                                 filepath_basename,
7299                                 for_testing=False):
7300    assert isinstance(function_name, str)
7301    assert isinstance(filepath_basename, str)
7302    assert isinstance(for_testing, bool)
7303
7304    web_idl_database = package_initializer().web_idl_database()
7305
7306    # Filepaths
7307    header_path = PathManager.component_path("modules",
7308                                             "{}.h".format(filepath_basename))
7309    source_path = PathManager.component_path("modules",
7310                                             "{}.cc".format(filepath_basename))
7311
7312    # Root nodes
7313    header_node = ListNode(tail="\n")
7314    header_node.set_accumulator(CodeGenAccumulator())
7315    header_node.set_renderer(MakoRenderer())
7316    source_node = ListNode(tail="\n")
7317    source_node.set_accumulator(CodeGenAccumulator())
7318    source_node.set_renderer(MakoRenderer())
7319
7320    # Namespaces
7321    header_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
7322    source_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
7323    header_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings"))
7324    source_bindings_ns = CxxNamespaceNode(name_style.namespace("bindings"))
7325    header_blink_ns.body.append(header_bindings_ns)
7326    source_blink_ns.body.append(source_bindings_ns)
7327
7328    # Function nodes
7329    func_decl = CxxFuncDeclNode(
7330        name=function_name, arg_decls=[], return_type="void")
7331    func_def = CxxFuncDefNode(
7332        name=function_name, arg_decls=[], return_type="void")
7333    header_bindings_ns.body.extend([
7334        TextNode("""\
7335// Initializes cross-component trampolines of IDL interface / namespace.\
7336"""),
7337        func_decl,
7338    ])
7339    source_bindings_ns.body.append(func_def)
7340
7341    # Assemble the parts.
7342    header_node.extend([
7343        make_copyright_header(),
7344        EmptyNode(),
7345        enclose_with_header_guard(
7346            ListNode([
7347                make_header_include_directives(header_node.accumulator),
7348                EmptyNode(),
7349                header_blink_ns,
7350            ]), name_style.header_guard(header_path)),
7351    ])
7352    source_node.extend([
7353        make_copyright_header(),
7354        EmptyNode(),
7355        TextNode("#include \"{}\"".format(header_path)),
7356        EmptyNode(),
7357        make_header_include_directives(source_node.accumulator),
7358        EmptyNode(),
7359        source_blink_ns,
7360    ])
7361
7362    init_calls = []
7363    for class_like in itertools.chain(web_idl_database.interfaces,
7364                                      web_idl_database.namespaces):
7365        if class_like.code_generator_info.for_testing != for_testing:
7366            continue
7367
7368        path_manager = PathManager(class_like)
7369        if path_manager.is_cross_components:
7370            source_node.accumulator.add_include_headers(
7371                [path_manager.impl_path(ext="h")])
7372
7373            class_name = v8_bridge_class_name(class_like)
7374            init_calls.append(_format("{}::Impl::Init();", class_name))
7375    for init_call in sorted(init_calls):
7376        func_def.body.append(TextNode(init_call))
7377
7378    # Write down to the files.
7379    write_code_node_to_file(header_node, path_manager.gen_path_to(header_path))
7380    write_code_node_to_file(source_node, path_manager.gen_path_to(source_path))
7381
7382
7383def generate_interfaces(task_queue):
7384    assert isinstance(task_queue, TaskQueue)
7385
7386    web_idl_database = package_initializer().web_idl_database()
7387
7388    for interface in web_idl_database.interfaces:
7389        task_queue.post_task(generate_interface, interface.identifier)
7390
7391    task_queue.post_task(generate_install_properties_per_feature,
7392                         "InstallPropertiesPerFeature",
7393                         "properties_per_feature_installer")
7394    task_queue.post_task(generate_install_properties_per_feature,
7395                         "InstallPropertiesPerFeatureForTesting",
7396                         "properties_per_feature_installer_for_testing",
7397                         for_testing=True)
7398    task_queue.post_task(generate_init_idl_interfaces, "InitIDLInterfaces",
7399                         "init_idl_interfaces")
7400    task_queue.post_task(generate_init_idl_interfaces,
7401                         "InitIDLInterfacesForTesting",
7402                         "init_idl_interfaces_for_testing",
7403                         for_testing=True)
7404