Commit 51b79729 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Refactor the new binding gentor to support IDL callbacks

Refactors bind_gen/ to support IDL callback functions and IDL
callback interfaces in https://crrev.com/c/2434004

Bug: 839389
Change-Id: Ie58f15269efe7c80f0157c4296f0cb37465deab0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2432708Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811132}
parent 26e5926b
......@@ -151,12 +151,10 @@ def blink_type_info(idl_type):
if real_type.is_void:
assert False, "Blink does not support/accept IDL void type."
if real_type.is_enumeration:
blink_impl_type = blink_class_name(real_type.type_definition_object)
return TypeInfo(blink_impl_type)
if real_type.type_definition_object is not None:
blink_impl_type = blink_class_name(real_type.type_definition_object)
if real_type.is_enumeration:
return TypeInfo(blink_impl_type)
return TypeInfo(
blink_impl_type,
member_fmt="Member<{}>",
......@@ -280,6 +278,39 @@ def native_value_tag(idl_type):
assert False, "Unknown type: {}".format(idl_type.syntactic_form)
def make_blink_to_v8_value(v8_var_name, blink_value_expr, idl_type,
v8_creation_context):
"""
Returns a SymbolNode whose definition converts a Blink value to a v8::Value.
"""
assert isinstance(v8_var_name, str)
assert isinstance(blink_value_expr, str)
assert isinstance(idl_type, web_idl.IdlType)
assert isinstance(v8_creation_context, str)
def create_definition(symbol_node):
if (idl_type.unwrap(typedef=True).is_nullable
and idl_type.unwrap().is_string):
pattern = ("v8::Local<v8::Value> {v8_var_name} = "
"{blink_value_expr}.IsNull() "
"? v8::Null(${isolate}).As<v8::Value>() "
": ToV8("
"{blink_value_expr}, {v8_creation_context}, ${isolate})"
".As<v8::Value>();")
else:
pattern = (
"auto&& {v8_var_name} = ToV8("
"{blink_value_expr}, {v8_creation_context}, ${isolate});")
node = TextNode(
_format(pattern,
v8_var_name=v8_var_name,
blink_value_expr=blink_value_expr,
v8_creation_context=v8_creation_context))
return SymbolDefinitionNode(symbol_node, [node])
return SymbolNode(v8_var_name, definition_constructor=create_definition)
def make_default_value_expr(idl_type, default_value):
"""
Returns a set of C++ expressions to be used for initialization with default
......
......@@ -8,10 +8,12 @@ code_node.CodeNode.
from .code_node import CodeNode
from .code_node import CompositeNode
from .code_node import EmptyNode
from .code_node import Likeliness
from .code_node import ListNode
from .code_node import SymbolScopeNode
from .code_node import TextNode
from .code_node import WeakDependencyNode
from .codegen_expr import CodeGenExpr
from .codegen_format import format_template
......@@ -210,6 +212,30 @@ switch (${{{cond}}}) {{
self._Clause(case, body, should_add_break))
class CxxForLoopNode(CompositeNode):
def __init__(self, cond, body, weak_dep_syms=None):
assert weak_dep_syms is None or isinstance(weak_dep_syms,
(list, tuple))
if weak_dep_syms is None:
weak_deps = EmptyNode()
else:
weak_deps = WeakDependencyNode(weak_dep_syms)
template_format = (
"{weak_deps}" #
"for ({cond}) {{\n"
" {body}\n"
"}}\n")
CompositeNode.__init__(self,
template_format,
weak_deps=weak_deps,
cond=_to_conditional_node(cond),
body=_to_symbol_scope_node(
body, Likeliness.LIKELY))
class CxxBreakableBlockNode(CompositeNode):
def __init__(self, body, likeliness=Likeliness.LIKELY):
template_format = ("do {{ // Dummy loop for use of 'break'.\n"
......@@ -234,7 +260,8 @@ class CxxFuncDeclNode(CompositeNode):
const=False,
override=False,
default=False,
delete=False):
delete=False,
warn_unused_result=False):
"""
Args:
name: Function name.
......@@ -248,6 +275,7 @@ class CxxFuncDeclNode(CompositeNode):
override: True makes this an overriding function.
default: True makes this have the default implementation.
delete: True makes this function be deleted.
warn_unused_result: True adds WARN_UNUSED_RESULT annotation.
"""
assert isinstance(name, str)
assert isinstance(static, bool)
......@@ -258,6 +286,7 @@ class CxxFuncDeclNode(CompositeNode):
assert isinstance(default, bool)
assert isinstance(delete, bool)
assert not (default and delete)
assert isinstance(warn_unused_result, bool)
template_format = ("{template}"
"{static}{explicit}{constexpr}"
......@@ -266,40 +295,42 @@ class CxxFuncDeclNode(CompositeNode):
"{const}"
"{override}"
"{default_or_delete}"
"{warn_unused_result}"
";")
if template_params is None:
template = ""
else:
template = "template <{}>\n".format(", ".join(template_params))
static = "static " if static else ""
explicit = "explicit " if explicit else ""
constexpr = "constexpr " if constexpr else ""
const = " const" if const else ""
override = " override" if override else ""
if default:
default_or_delete = " = default"
elif delete:
default_or_delete = " = delete"
else:
default_or_delete = ""
CompositeNode.__init__(
self,
template_format,
name=_to_maybe_text_node(name),
arg_decls=ListNode(
map(_to_maybe_text_node, arg_decls), separator=", "),
return_type=_to_maybe_text_node(return_type),
template=template,
static=static,
explicit=explicit,
constexpr=constexpr,
const=const,
override=override,
default_or_delete=default_or_delete)
warn_unused_result = (" WARN_UNUSED_RESULT"
if warn_unused_result else "")
CompositeNode.__init__(self,
template_format,
name=_to_maybe_text_node(name),
arg_decls=ListNode(map(_to_maybe_text_node,
arg_decls),
separator=", "),
return_type=_to_maybe_text_node(return_type),
template=template,
static=static,
explicit=explicit,
constexpr=constexpr,
const=const,
override=override,
default_or_delete=default_or_delete,
warn_unused_result=warn_unused_result)
class CxxFuncDefNode(CompositeNode):
......
......@@ -7,6 +7,7 @@ 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 make_default_value_expr
from .blink_v8_bridge import make_v8_to_blink_value
from .blink_v8_bridge import native_value_tag
......@@ -59,7 +60,7 @@ def _blink_member_name(member):
# C++ data member that shows the presence of the IDL member.
self.presence_var = name_style.member_var("has", blink_name)
# C++ data member that holds the value of the IDL member.
self.value_var = name_style.member_var(blink_name)
self.value_var = name_style.member_var_f("member_{}", blink_name)
# Migration Adapters
self.get_non_null_api = name_style.api_func(blink_name, "non_null")
self.has_non_null_api = name_style.api_func(
......@@ -97,7 +98,7 @@ def bind_member_iteration_local_vars(code_node):
"current_context", "v8::Local<v8::Context> ${current_context} = "
"${isolate}->GetCurrentContext();"),
SymbolNode(
"member_names", "const auto* ${member_names} = "
"v8_member_names", "const auto* ${v8_member_names} = "
"GetV8MemberNames(${isolate}).data();"),
SymbolNode(
"is_in_secure_context", "const bool ${is_in_secure_context} = "
......@@ -776,43 +777,32 @@ def make_fill_with_own_dict_members_func(cg_context):
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
body.add_template_var("isolate", "isolate")
body.add_template_var("creation_context", "creation_context")
body.add_template_var("v8_dictionary", "v8_dictionary")
bind_member_iteration_local_vars(body)
def to_v8_expr(member):
get_api = _blink_member_name(member).get_api
member_type = member.idl_type.unwrap(typedef=True)
expr = _format("ToV8({}(), creation_context, isolate)", get_api)
if member_type.is_nullable and member_type.unwrap().is_string:
expr = _format(
"({get_api}().IsNull() ? v8::Null(isolate).As<v8::Value>() "
": {to_v8})",
get_api=get_api,
to_v8=expr)
return expr
for key_index, member in enumerate(own_members):
pattern = """\
if ({has_api}()) {{
if (!v8_dictionary
->CreateDataProperty(
${current_context},
${member_names}[{index}].Get(isolate),
{to_v8_expr})
.ToChecked()) {{
return false;
}}
}}\
"""
node = TextNode(
_format(pattern,
has_api=_blink_member_name(member).has_api,
index=key_index,
to_v8_expr=to_v8_expr(member)))
for index, member in enumerate(own_members):
member_name = _blink_member_name(member)
v8_member_name = name_style.local_var_f("v8_member_{}",
member.identifier)
body.register_code_symbol(
make_blink_to_v8_value(v8_member_name,
"{}()".format(member_name.get_api),
member.idl_type, "${creation_context}"))
node = CxxLikelyIfNode(
cond="{}()".format(member_name.has_api),
body=TextNode(
_format(
"${v8_dictionary}->CreateDataProperty("
"${current_context}, "
"${v8_member_names}[{index}].Get(${isolate}), "
"${{{v8_member_name}}}"
").ToChecked();",
index=index,
v8_member_name=v8_member_name)))
conditional = expr_from_exposure(member.exposure)
if not conditional.is_always_true:
node = CxxLikelyIfNode(cond=conditional, body=node)
body.append(node)
body.append(TextNode("return true;"))
......@@ -944,7 +934,7 @@ if (!bindings::ConvertDictionaryMember<{nvt_tag}, {is_required}>(
${isolate},
${current_context},
v8_dictionary,
${member_names}[{key_index}].Get(${isolate}),
${v8_member_names}[{key_index}].Get(${isolate}),
"${{dictionary.identifier}}",
"{member_name}",
{value_var},
......
......@@ -317,13 +317,14 @@ def generate_enumeration(enumeration_identifier):
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/bindings/core/v8/generated_code_helper.h",
"third_party/blink/renderer/platform/bindings/enumeration_base.h",
])
# Assemble the parts.
header_blink_ns.body.append(class_def)
header_blink_ns.body.append(EmptyNode())
......
......@@ -4671,9 +4671,11 @@ class _PropEntryOperationGroup(_PropEntryBase):
self.no_alloc_direct_callback_name = no_alloc_direct_callback_name
def _make_property_entries_and_callback_defs(
cg_context, attribute_entries, constant_entries, constructor_entries,
exposed_construct_entries, operation_entries):
def make_property_entries_and_callback_defs(cg_context, attribute_entries,
constant_entries,
constructor_entries,
exposed_construct_entries,
operation_entries):
"""
Creates intermediate objects to help property installation and also makes
code nodes of callback functions.
......@@ -4692,8 +4694,9 @@ def _make_property_entries_and_callback_defs(
assert isinstance(exposed_construct_entries, list)
assert isinstance(operation_entries, list)
class_like = cg_context.class_like
interface = cg_context.interface
global_names = interface.extended_attributes.values_of("Global")
global_names = class_like.extended_attributes.values_of("Global")
callback_def_nodes = ListNode()
......@@ -4911,22 +4914,24 @@ def _make_property_entries_and_callback_defs(
op_callback_name=op_callback_name,
op_func_length=0))
iterate(interface.attributes, process_attribute)
iterate(interface.constants, process_constant)
iterate(interface.constructor_groups, process_constructor_group)
iterate(interface.exposed_constructs, process_exposed_construct)
iterate(interface.legacy_window_aliases, process_exposed_construct)
named_constructor_groups = [
group for construct in interface.exposed_constructs
for group in construct.named_constructor_groups
if construct.named_constructor_groups
]
iterate(named_constructor_groups, process_named_constructor_group)
iterate(interface.operation_groups, process_operation_group)
if interface.stringifier:
iterate(class_like.attributes, process_attribute)
iterate(class_like.constants, process_constant)
if interface:
iterate(interface.constructor_groups, process_constructor_group)
iterate(interface.exposed_constructs, process_exposed_construct)
iterate(interface.legacy_window_aliases, process_exposed_construct)
named_constructor_groups = [
group for construct in interface.exposed_constructs
for group in construct.named_constructor_groups
if construct.named_constructor_groups
]
iterate(named_constructor_groups, process_named_constructor_group)
if not class_like.is_callback_interface:
iterate(class_like.operation_groups, process_operation_group)
if interface and interface.stringifier:
iterate([interface.stringifier.operation], process_stringifier)
collectionlike = (interface.iterable or interface.maplike
or interface.setlike)
collectionlike = interface and (interface.iterable or interface.maplike
or interface.setlike)
if collectionlike:
def should_define(target):
......@@ -5150,6 +5155,12 @@ def make_install_interface_template(cg_context, function_name, class_name,
assert False
body.append(EmptyNode())
if cg_context.callback_interface:
body.extend([
T("${interface_template}->RemovePrototype();"),
EmptyNode(),
])
body.extend([
supplemental_install_node,
EmptyNode(),
......@@ -5301,8 +5312,8 @@ ${prototype_template}->SetIntrinsicDataProperty(
${instance_template}->SetImmutableProto();
${prototype_template}->SetImmutableProto();
"""))
elif any("Global" in derived.extended_attributes
for derived in class_like.deriveds):
elif interface and any("Global" in derived.extended_attributes
for derived in interface.deriveds):
body.append(
TextNode("""\
// [Global] - prototype object in the prototype chain of global objects
......@@ -6219,16 +6230,17 @@ const WrapperTypeInfo ${class_name}::wrapper_type_info_{{
"InstallContextDependentPropertiesAdapter")
else:
install_context_dependent_func = "nullptr"
if class_like.inherited:
if class_like.is_interface and class_like.inherited:
wrapper_type_info_of_inherited = "{}::GetWrapperTypeInfo()".format(
v8_bridge_class_name(class_like.inherited))
else:
wrapper_type_info_of_inherited = "nullptr"
wrapper_type_prototype = ("WrapperTypeInfo::kWrapperTypeObjectPrototype"
if isinstance(class_like, web_idl.Interface) else
if class_like.is_interface else
"WrapperTypeInfo::kWrapperTypeNoPrototype")
wrapper_class_id = ("WrapperTypeInfo::kNodeClassId"
if class_like.does_implement("Node") else
if class_like.is_interface
and class_like.does_implement("Node") else
"WrapperTypeInfo::kObjectClassId")
active_script_wrappable_inheritance = (
"WrapperTypeInfo::kInheritFromActiveScriptWrappable"
......@@ -6243,12 +6255,13 @@ const WrapperTypeInfo ${class_name}::wrapper_type_info_{{
active_script_wrappable_inheritance=(
active_script_wrappable_inheritance)))
blink_class = blink_class_name(class_like)
pattern = """\
if class_like.is_interface:
blink_class = blink_class_name(class_like)
pattern = """\
const WrapperTypeInfo& {blink_class}::wrapper_type_info_ =
${class_name}::wrapper_type_info_;
"""
wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
if class_like.code_generator_info.is_active_script_wrappable:
pattern = """\
......@@ -6274,7 +6287,8 @@ static_assert(
decltype(&ScriptWrappable::HasPendingActivity)>::value,
"{blink_class} is overriding hasPendingActivity() without "
"[ActiveScriptWrappable] extended attribute.");"""
wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
if class_like.is_interface:
wrapper_type_info_def.append(F(pattern, blink_class=blink_class))
return func_def, member_var_def, wrapper_type_info_def
......@@ -6721,7 +6735,7 @@ def generate_interface(interface_identifier):
constructor_entries = []
exposed_construct_entries = []
operation_entries = []
callback_defs = _make_property_entries_and_callback_defs(
callback_defs = make_property_entries_and_callback_defs(
cg_context,
attribute_entries=attribute_entries,
constant_entries=constant_entries,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment