| # Copyright 2020 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import web_idl |
| |
| from . import name_style |
| from .blink_v8_bridge import blink_class_name |
| from .blink_v8_bridge import blink_type_info |
| from .blink_v8_bridge import make_blink_to_v8_value |
| from .blink_v8_bridge import native_value_tag |
| from .code_node import EmptyNode |
| from .code_node import ListNode |
| from .code_node import SequenceNode |
| from .code_node import SymbolNode |
| from .code_node import SymbolScopeNode |
| from .code_node import TextNode |
| from .code_node_cxx import CxxClassDefNode |
| from .code_node_cxx import CxxForLoopNode |
| from .code_node_cxx import CxxFuncDeclNode |
| from .code_node_cxx import CxxFuncDefNode |
| from .code_node_cxx import CxxLikelyIfNode |
| from .code_node_cxx import CxxNamespaceNode |
| from .code_node_cxx import CxxUnlikelyIfNode |
| from .codegen_accumulator import CodeGenAccumulator |
| from .codegen_context import CodeGenContext |
| from .codegen_format import format_template as _format |
| from .codegen_utils import collect_forward_decls_and_include_headers |
| from .codegen_utils import component_export |
| from .codegen_utils import component_export_header |
| from .codegen_utils import enclose_with_header_guard |
| from .codegen_utils import make_copyright_header |
| from .codegen_utils import make_forward_declarations |
| from .codegen_utils import make_header_include_directives |
| from .codegen_utils import write_code_node_to_file |
| from .mako_renderer import MakoRenderer |
| from .package_initializer import package_initializer |
| from .path_manager import PathManager |
| from .task_queue import TaskQueue |
| |
| |
| def bind_local_vars(code_node, cg_context, is_construct_call=False): |
| assert isinstance(code_node, SymbolScopeNode) |
| assert isinstance(cg_context, CodeGenContext) |
| assert isinstance(is_construct_call, bool) |
| |
| S = SymbolNode |
| |
| local_vars = [] |
| |
| local_vars.extend([ |
| S("exception_state", ("ExceptionState ${exception_state}(" |
| "${isolate}, ExceptionState::kExecutionContext," |
| "${class_like_name}, ${property_name});")), |
| S("isolate", "v8::Isolate* ${isolate} = GetIsolate();"), |
| S("script_state", |
| "ScriptState* ${script_state} = CallbackRelevantScriptState();"), |
| ]) |
| |
| if cg_context.callback_function: |
| local_vars.append( |
| S("class_like_name", ("const char* const ${class_like_name} = " |
| "\"${callback_function.identifier}\";"))) |
| if is_construct_call: |
| local_vars.append( |
| S("property_name", |
| "const char* const ${property_name} = \"construct\";")) |
| else: |
| local_vars.append( |
| S("property_name", |
| "const char* const ${property_name} = \"invoke\";")) |
| elif cg_context.callback_interface: |
| local_vars.extend([ |
| S("class_like_name", ("const char* const ${class_like_name} = " |
| "\"${callback_interface.identifier}\";")), |
| S("property_name", ("const char* const ${property_name} = " |
| "\"${property.identifier}\";")), |
| ]) |
| |
| code_node.register_code_symbols(local_vars) |
| |
| |
| def _make_arg_type_and_names(func_like): |
| assert isinstance(func_like, web_idl.FunctionLike) |
| |
| arg_type_and_names = [] |
| for index, argument in enumerate(func_like.arguments): |
| type_info = blink_type_info(argument.idl_type) |
| if argument.idl_type.unwrap(variadic=False).is_interface: |
| arg_type = type_info.ref_t |
| else: |
| arg_type = type_info.const_ref_t |
| arg_name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier) |
| arg_type_and_names.append((arg_type, arg_name)) |
| return arg_type_and_names |
| |
| |
| def make_factory_methods(cg_context): |
| assert isinstance(cg_context, CodeGenContext) |
| |
| func_def = CxxFuncDefNode( |
| name="Create", |
| arg_decls=["v8::Local<v8::Object> callback_object"], |
| return_type="${class_name}*", |
| static=True) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| |
| func_def.body.append( |
| TextNode("return MakeGarbageCollected<${class_name}>(" |
| "callback_object);")) |
| |
| return func_def, None |
| |
| |
| def make_constructors(cg_context): |
| assert isinstance(cg_context, CodeGenContext) |
| |
| decls = ListNode([ |
| CxxFuncDefNode(name=cg_context.class_name, |
| arg_decls=["v8::Local<v8::Object> callback_object"], |
| return_type="", |
| explicit=True, |
| member_initializer_list=[ |
| "${base_class_name}(callback_object)", |
| ]), |
| CxxFuncDeclNode(name="~${class_name}", |
| arg_decls=[], |
| return_type="", |
| override=True, |
| default=True), |
| ]) |
| |
| return decls, None |
| |
| |
| def make_nameclient_implementation(cg_context): |
| assert isinstance(cg_context, CodeGenContext) |
| |
| func_decl = CxxFuncDeclNode(name="NameInHeapSnapshot", |
| arg_decls=[], |
| return_type="const char*", |
| const=True, |
| override=True) |
| |
| func_def = CxxFuncDefNode(name="NameInHeapSnapshot", |
| arg_decls=[], |
| return_type="const char*", |
| class_name=cg_context.class_name, |
| const=True) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| func_def.body.append(TextNode("return \"${class_name}\";")) |
| |
| return func_decl, func_def |
| |
| |
| def make_callback_invocation_function(cg_context, |
| function_name, |
| skip_runnability_check=False, |
| is_construct_call=False): |
| assert isinstance(cg_context, CodeGenContext) |
| assert isinstance(function_name, str) |
| assert isinstance(skip_runnability_check, bool) |
| assert isinstance(is_construct_call, bool) |
| |
| T = TextNode |
| F = lambda *args, **kwargs: T(_format(*args, **kwargs)) |
| |
| func_like = cg_context.function_like |
| return_type = ("void" if func_like.return_type.unwrap().is_void else |
| blink_type_info(func_like.return_type).value_t) |
| maybe_return_type = "v8::Maybe<{}>".format(return_type) |
| arg_type_and_names = _make_arg_type_and_names(func_like) |
| arg_decls = [ |
| "{} {}".format(arg_type, arg_name) |
| for arg_type, arg_name in arg_type_and_names |
| ] |
| if not is_construct_call: |
| arg_decls.insert( |
| 0, "bindings::V8ValueOrScriptWrappableAdapter arg0_receiver") |
| |
| decls = SequenceNode() |
| defs = SequenceNode() |
| |
| func_decl = CxxFuncDeclNode(name=function_name, |
| arg_decls=arg_decls, |
| return_type=maybe_return_type, |
| warn_unused_result=True) |
| if cg_context.callback_function: |
| if is_construct_call: |
| comment = T("""\ |
| // Performs "construct". |
| // https://heycam.github.io/webidl/#construct-a-callback-function\ |
| """) |
| else: |
| comment = T("""\ |
| // Performs "invoke". |
| // https://heycam.github.io/webidl/#invoke-a-callback-function\ |
| """) |
| elif cg_context.callback_interface: |
| comment = T("""\ |
| // Performs "call a user object's operation". |
| // https://heycam.github.io/webidl/#call-a-user-objects-operation\ |
| """) |
| decls.extend([ |
| comment, |
| func_decl, |
| ]) |
| |
| func_def = CxxFuncDefNode(name=function_name, |
| arg_decls=arg_decls, |
| return_type=maybe_return_type, |
| class_name=cg_context.class_name) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| defs.append(func_def) |
| body = func_def.body |
| if is_construct_call: |
| body.add_template_var("arg0_receiver", "nullptr") |
| else: |
| body.add_template_var("arg0_receiver", "arg0_receiver") |
| for arg_type, arg_name in arg_type_and_names: |
| body.add_template_var(arg_name, arg_name) |
| bind_local_vars(body, cg_context, is_construct_call) |
| |
| if func_like.return_type.unwrap(typedef=True).is_void: |
| text = "v8::JustVoid()" |
| else: |
| text = "helper.Result<{}, {}>()".format( |
| native_value_tag(func_like.return_type), return_type) |
| body.add_template_var("return_value_on_success", text) |
| text = "v8::Nothing<{}>()".format(return_type) |
| body.add_template_var("return_value_on_failure", text) |
| |
| body.append( |
| T("""\ |
| ScriptState* callback_relevant_script_state = |
| CallbackRelevantScriptStateOrThrowException( |
| ${class_like_name}, ${property_name}); |
| if (!callback_relevant_script_state) { |
| return ${return_value_on_failure}; |
| } |
| """)) |
| |
| if not skip_runnability_check: |
| body.extend([ |
| CxxUnlikelyIfNode( |
| cond=("!IsCallbackFunctionRunnable(" |
| "callback_relevant_script_state, " |
| "IncumbentScriptState())"), |
| body=[ |
| T("v8::HandleScope handle_scope(${isolate});"), |
| T("v8::Context::Scope context_scope(" |
| "CallbackObject()->CreationContext());"), |
| T("${exception_state}.ThrowException(" |
| "static_cast<ExceptionCode>(ESErrorType::kError), " |
| "\"The provided callback is no longer runnable.\");"), |
| T("return ${return_value_on_failure};"), |
| ]), |
| EmptyNode(), |
| ]) |
| |
| if cg_context.callback_function: |
| template_params = ["CallbackFunctionBase"] |
| if is_construct_call: |
| template_params.append( |
| "bindings::CallbackInvokeHelperMode::kConstructorCall") |
| elif "LegacyTreatNonObjectAsNull" in func_like.extended_attributes: |
| template_params.append( |
| "bindings::" |
| "CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull") |
| elif cg_context.callback_interface: |
| template_params = ["CallbackInterfaceBase"] |
| body.extend([ |
| F("""\ |
| bindings::CallbackInvokeHelper<{template_params}> helper( |
| this, ${class_like_name}, ${property_name});\ |
| """, |
| template_params=", ".join(template_params)), |
| CxxUnlikelyIfNode( |
| cond="UNLIKELY(!helper.PrepareForCall(${arg0_receiver}))", |
| body=[ |
| CxxLikelyIfNode(cond="helper.V8Result().IsEmpty()", |
| body=[ |
| T("return ${return_value_on_failure};"), |
| ]), |
| T("return ${return_value_on_success};"), |
| ]), |
| ]) |
| |
| arguments = func_like.arguments |
| if not arguments: |
| body.append(T("const int argc = 0;")) |
| body.append(T("v8::Local<v8::Value>* argv = nullptr;")) |
| else: |
| is_variadic = arguments[-1].is_variadic |
| if is_variadic: |
| _, variadic_arg_name = arg_type_and_names[-1] |
| body.append( |
| T("const int argc = {} + {}.size();".format( |
| len(arguments) - 1, variadic_arg_name))) |
| else: |
| body.append(T("const int argc = {};".format(len(arguments)))) |
| if is_variadic and len(arguments) == 1: |
| body.append(T("v8::Local<v8::Value> argv[std::max(1, argc)];")) |
| else: |
| body.append(T("v8::Local<v8::Value> argv[argc];")) |
| for index, arg_type_and_name in enumerate(arg_type_and_names): |
| if arguments[index].is_variadic: |
| break |
| _, arg_name = arg_type_and_name |
| v8_arg_name = name_style.local_var_f("v8_arg{}_{}", index + 1, |
| arguments[index].identifier) |
| body.register_code_symbol( |
| make_blink_to_v8_value( |
| v8_arg_name, |
| arg_name, |
| arguments[index].idl_type, |
| argument=arguments[index], |
| error_exit_return_statement=( |
| "return ${return_value_on_failure};"))) |
| body.append( |
| F("argv[{index}] = ${{{v8_arg}}};", |
| index=index, |
| v8_arg=v8_arg_name)) |
| if is_variadic: |
| v8_arg_name = name_style.local_var_f("v8_arg{}_{}", len(arguments), |
| arguments[-1].identifier) |
| body.register_code_symbol( |
| make_blink_to_v8_value( |
| v8_arg_name, |
| "{}[i]".format(variadic_arg_name), |
| arguments[-1].idl_type.unwrap(variadic=True), |
| argument=arguments[-1], |
| error_exit_return_statement=( |
| "return ${return_value_on_failure};"))) |
| body.append( |
| CxxForLoopNode( |
| cond=F("wtf_size_t i = 0; i < {var_arg}.size(); ++i", |
| var_arg=variadic_arg_name), |
| body=[ |
| F("argv[{non_var_arg_size} + i] = ${{{v8_arg}}};", |
| non_var_arg_size=len(arguments) - 1, |
| v8_arg=v8_arg_name), |
| ], |
| weak_dep_syms=["isolate", "script_state"])) |
| |
| body.extend([ |
| CxxUnlikelyIfNode(cond="!helper.Call(argc, argv)", |
| body=[ |
| T("return ${return_value_on_failure};"), |
| ]), |
| T("return ${return_value_on_success};"), |
| ]) |
| |
| return decls, defs |
| |
| |
| def make_invoke_and_report_function(cg_context, function_name, api_func_name): |
| assert isinstance(cg_context, CodeGenContext) |
| assert isinstance(function_name, str) |
| assert isinstance(api_func_name, str) |
| |
| T = TextNode |
| F = lambda *args, **kwargs: T(_format(*args, **kwargs)) |
| |
| func_like = cg_context.function_like |
| if not (func_like.return_type.unwrap().is_void |
| or func_like.identifier == "Function"): |
| return None, None |
| |
| arg_type_and_names = _make_arg_type_and_names(func_like) |
| arg_decls = ["bindings::V8ValueOrScriptWrappableAdapter arg0_receiver"] + [ |
| "{} {}".format(arg_type, arg_name) |
| for arg_type, arg_name in arg_type_and_names |
| ] |
| |
| decls = SequenceNode() |
| defs = SequenceNode() |
| |
| func_decl = CxxFuncDeclNode(name=function_name, |
| arg_decls=arg_decls, |
| return_type="void") |
| if cg_context.callback_function: |
| comment = T("""\ |
| // Performs "invoke" and then reports an exception if any to the global |
| // error handler such as DevTools console.\ |
| """) |
| elif cg_context.callback_interface: |
| comment = T("""\ |
| // Performs "call a user object's operation" and then reports an exception |
| // if any to the global error handler such as DevTools console.\ |
| """) |
| decls.extend([ |
| comment, |
| func_decl, |
| ]) |
| |
| func_def = CxxFuncDefNode(name=function_name, |
| arg_decls=arg_decls, |
| return_type="void", |
| class_name=cg_context.class_name) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| defs.append(func_def) |
| body = func_def.body |
| bind_local_vars(body, cg_context) |
| |
| arg_names = ["arg0_receiver" |
| ] + [arg_name for arg_type, arg_name in arg_type_and_names] |
| |
| body.extend([ |
| T("v8::TryCatch try_catch(${isolate});"), |
| T("try_catch.SetVerbose(true);"), |
| EmptyNode(), |
| F("ignore_result({api_func_name}({arg_names}));", |
| api_func_name=api_func_name, |
| arg_names=", ".join(arg_names)), |
| ]) |
| |
| return decls, defs |
| |
| |
| def make_is_runnable_or_throw_exception(cg_context, function_name): |
| assert isinstance(cg_context, CodeGenContext) |
| assert isinstance(function_name, str) |
| |
| T = TextNode |
| |
| decls = SequenceNode() |
| defs = SequenceNode() |
| |
| ignore_pause_def = ListNode([ |
| T("enum class IgnorePause {"), |
| T(" kDontIgnore,"), |
| T(" kIgnore,"), |
| T("};"), |
| ]) |
| func_decl = CxxFuncDeclNode(name=function_name, |
| arg_decls=["IgnorePause ignore_pause"], |
| return_type="bool") |
| decls.extend([ |
| T("""\ |
| // Returns true if the callback is runnable, otherwise returns false and |
| // throws an exception.\ |
| """), |
| ignore_pause_def, |
| func_decl, |
| ]) |
| |
| func_def = CxxFuncDefNode(name=function_name, |
| arg_decls=["IgnorePause ignore_pause"], |
| return_type="bool", |
| class_name=cg_context.class_name) |
| func_def.set_base_template_vars(cg_context.template_bindings()) |
| defs.append(func_def) |
| body = func_def.body |
| body.add_template_var("ignore_pause", "ignore_pause") |
| bind_local_vars(body, cg_context) |
| |
| body.extend([ |
| T("""\ |
| ScriptState* callback_relevant_script_state = CallbackRelevantScriptState(); |
| |
| const bool is_runnable = |
| ignore_pause == IgnorePause::kIgnore |
| ? IsCallbackFunctionRunnableIgnoringPause( |
| callback_relevant_script_state, IncumbentScriptState()) |
| : IsCallbackFunctionRunnable( |
| callback_relevant_script_state, IncumbentScriptState()); |
| if (is_runnable) |
| return true; |
| """), |
| T("ScriptState::Scope scope(callback_relevant_script_state);"), |
| T("""\ |
| ${exception_state}.ThrowException( |
| static_cast<ExceptionCode>(ESErrorType::kError), |
| "The provided callback is no longer runnable."); |
| return false;\ |
| """), |
| ]) |
| |
| return decls, defs |
| |
| |
| def generate_callback_function(callback_function_identifier): |
| assert isinstance(callback_function_identifier, web_idl.Identifier) |
| |
| web_idl_database = package_initializer().web_idl_database() |
| callback_function = web_idl_database.find(callback_function_identifier) |
| |
| path_manager = PathManager(callback_function) |
| assert path_manager.api_component == path_manager.impl_component |
| api_component = path_manager.api_component |
| for_testing = callback_function.code_generator_info.for_testing |
| |
| # Class names |
| class_name = blink_class_name(callback_function) |
| |
| cg_context = CodeGenContext(callback_function=callback_function, |
| class_name=class_name, |
| base_class_name="CallbackFunctionBase") |
| |
| # Filepaths |
| header_path = path_manager.api_path(ext="h") |
| source_path = path_manager.api_path(ext="cc") |
| |
| # Root nodes |
| header_node = ListNode(tail="\n") |
| header_node.set_accumulator(CodeGenAccumulator()) |
| header_node.set_renderer(MakoRenderer()) |
| source_node = ListNode(tail="\n") |
| source_node.set_accumulator(CodeGenAccumulator()) |
| source_node.set_renderer(MakoRenderer()) |
| |
| # Namespaces |
| header_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) |
| source_blink_ns = CxxNamespaceNode(name_style.namespace("blink")) |
| |
| # Class definition |
| class_def = CxxClassDefNode(cg_context.class_name, |
| base_class_names=["CallbackFunctionBase"], |
| final=True, |
| export=component_export( |
| api_component, for_testing)) |
| class_def.set_base_template_vars(cg_context.template_bindings()) |
| |
| # Implementation parts |
| factory_decls, factory_defs = make_factory_methods(cg_context) |
| ctor_decls, ctor_defs = make_constructors(cg_context) |
| nameclient_decls, nameclient_defs = make_nameclient_implementation( |
| cg_context) |
| |
| cgc = cg_context.make_copy(callback_function=callback_function) |
| |
| invoke_decls, invoke_defs = make_callback_invocation_function( |
| cgc, name_style.func("Invoke"), is_construct_call=False) |
| construct_decls, construct_defs = make_callback_invocation_function( |
| cgc, name_style.func("Construct"), is_construct_call=True) |
| |
| (invoke_and_report_decls, |
| invoke_and_report_defs) = make_invoke_and_report_function( |
| cgc, name_style.func("InvokeAndReportException"), |
| name_style.func("Invoke")) |
| |
| event_handler_decls, event_handler_defs = None, None |
| if callback_function.identifier == "EventHandlerNonNull": |
| event_handler_decls = SequenceNode() |
| event_handler_defs = SequenceNode() |
| (decls, defs) = make_is_runnable_or_throw_exception( |
| cgc, name_style.func("IsRunnableOrThrowException")) |
| event_handler_decls.append(decls) |
| event_handler_defs.append(defs) |
| event_handler_decls.append(EmptyNode()) |
| event_handler_defs.append(EmptyNode()) |
| (decls, defs) = make_callback_invocation_function( |
| cgc, |
| name_style.func("InvokeWithoutRunnabilityCheck"), |
| skip_runnability_check=True) |
| event_handler_decls.append(decls) |
| event_handler_defs.append(defs) |
| |
| # Header part (copyright, include directives, and forward declarations) |
| header_node.extend([ |
| make_copyright_header(), |
| EmptyNode(), |
| enclose_with_header_guard( |
| ListNode([ |
| make_header_include_directives(header_node.accumulator), |
| EmptyNode(), |
| header_blink_ns, |
| ]), name_style.header_guard(header_path)), |
| ]) |
| header_blink_ns.body.extend([ |
| make_forward_declarations(header_node.accumulator), |
| EmptyNode(), |
| ]) |
| source_node.extend([ |
| make_copyright_header(), |
| EmptyNode(), |
| TextNode("#include \"{}\"".format(header_path)), |
| EmptyNode(), |
| make_header_include_directives(source_node.accumulator), |
| EmptyNode(), |
| source_blink_ns, |
| ]) |
| source_blink_ns.body.extend([ |
| make_forward_declarations(source_node.accumulator), |
| EmptyNode(), |
| ]) |
| |
| # Assemble the parts. |
| header_node.accumulator.add_include_headers([ |
| component_export_header(api_component, for_testing), |
| "third_party/blink/renderer/platform/bindings/callback_function_base.h", |
| "third_party/blink/renderer/platform/bindings/v8_value_or_script_wrappable_adapter.h", |
| ]) |
| source_node.accumulator.add_include_headers([ |
| "third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.h", |
| "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h", |
| "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h", |
| ]) |
| (header_forward_decls, header_include_headers, source_forward_decls, |
| source_include_headers) = collect_forward_decls_and_include_headers( |
| [callback_function.return_type] + list( |
| map(lambda argument: argument.idl_type, |
| callback_function.arguments))) |
| header_node.accumulator.add_class_decls(header_forward_decls) |
| header_node.accumulator.add_include_headers(header_include_headers) |
| source_node.accumulator.add_class_decls(source_forward_decls) |
| source_node.accumulator.add_include_headers(source_include_headers) |
| |
| header_blink_ns.body.append(class_def) |
| header_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(factory_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(factory_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(ctor_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(ctor_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(TextNode("// NameClient overrides:")) |
| class_def.public_section.append(nameclient_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(nameclient_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(invoke_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(invoke_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(construct_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(construct_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(invoke_and_report_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(invoke_and_report_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| class_def.public_section.append(event_handler_decls) |
| class_def.public_section.append(EmptyNode()) |
| source_blink_ns.body.append(event_handler_defs) |
| source_blink_ns.body.append(EmptyNode()) |
| |
| # Write down to the files. |
| write_code_node_to_file(header_node, path_manager.gen_path_to(header_path)) |
| write_code_node_to_file(source_node, path_manager.gen_path_to(source_path)) |
| |
| |
| def generate_callback_functions(task_queue): |
| assert isinstance(task_queue, TaskQueue) |
| |
| web_idl_database = package_initializer().web_idl_database() |
| |
| for callback_function in web_idl_database.callback_functions: |
| if callback_function.identifier in ( |
| "OnErrorEventHandlerNonNull", |
| "OnBeforeUnloadEventHandlerNonNull"): |
| # OnErrorEventHandlerNonNull and OnBeforeUnloadEventHandlerNonNull |
| # are unified into EventHandlerNonNull, and they won't be used. |
| continue |
| task_queue.post_task(generate_callback_function, |
| callback_function.identifier) |