Commit 65fc95ff authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Implement/improve blink_api_call to support optional args

Implements support of optional arguments.

Bug: 839389
Change-Id: I1e35774a52fc18786eb712b2dcc6d9456faea5d8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1942895Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720831}
parent e59d30f9
...@@ -100,6 +100,7 @@ def blink_type_info(idl_type): ...@@ -100,6 +100,7 @@ def blink_type_info(idl_type):
blink_impl_type, blink_impl_type,
member_fmt="Member<{}>", member_fmt="Member<{}>",
ref_fmt="{}*", ref_fmt="{}*",
value_fmt="{}*",
is_nullable=True) is_nullable=True)
if (real_type.is_sequence or real_type.is_frozen_array if (real_type.is_sequence or real_type.is_frozen_array
...@@ -168,13 +169,18 @@ def native_value_tag(idl_type): ...@@ -168,13 +169,18 @@ def native_value_tag(idl_type):
return "IDLNullable<{}>".format(native_value_tag(real_type.inner_type)) return "IDLNullable<{}>".format(native_value_tag(real_type.inner_type))
def make_v8_to_blink_value(blink_var_name, v8_value_expr, idl_type): def make_v8_to_blink_value(blink_var_name,
v8_value_expr,
idl_type,
default_value=None):
""" """
Returns a SymbolNode whose definition converts a v8::Value to a Blink value. Returns a SymbolNode whose definition converts a v8::Value to a Blink value.
""" """
assert isinstance(blink_var_name, str) assert isinstance(blink_var_name, str)
assert isinstance(v8_value_expr, str) assert isinstance(v8_value_expr, str)
assert isinstance(idl_type, web_idl.IdlType) assert isinstance(idl_type, web_idl.IdlType)
assert (default_value is None
or isinstance(default_value, web_idl.LiteralConstant))
pattern = ( pattern = (
"const auto& ${{{_1}}} = NativeValueTraits<{_2}>::NativeValue({_3});") "const auto& ${{{_1}}} = NativeValueTraits<{_2}>::NativeValue({_3});")
......
...@@ -58,58 +58,8 @@ def bind_blink_api_arguments(code_node, cg_context): ...@@ -58,58 +58,8 @@ def bind_blink_api_arguments(code_node, cg_context):
else: else:
v8_value = "${{info}}[{}]".format(argument.index) v8_value = "${{info}}[{}]".format(argument.index)
code_node.register_code_symbol( code_node.register_code_symbol(
make_v8_to_blink_value(name, v8_value, argument.idl_type)) make_v8_to_blink_value(name, v8_value, argument.idl_type,
argument.default_value))
def bind_blink_api_call(code_node, cg_context):
assert isinstance(code_node, SymbolScopeNode)
assert isinstance(cg_context, CodeGenContext)
property_implemented_as = (
cg_context.member_like.code_generator_info.property_implemented_as)
func_name = (property_implemented_as
or name_style.api_func(cg_context.member_like.identifier))
if cg_context.attribute_set:
func_name = name_style.api_func("set", func_name)
if cg_context.member_like.is_static:
receiver_implemented_as = (
cg_context.member_like.code_generator_info.receiver_implemented_as)
class_name = (receiver_implemented_as
or name_style.class_(cg_context.class_like.identifier))
func_name = "{}::{}".format(class_name, func_name)
arguments = []
ext_attrs = cg_context.member_like.extended_attributes
values = ext_attrs.values_of("CallWith") + (
ext_attrs.values_of("SetterCallWith") if cg_context.attribute_set else
())
if "Isolate" in values:
arguments.append("${isolate}")
if "ScriptState" in values:
arguments.append("${script_state}")
if "ExecutionContext" in values:
arguments.append("${execution_context}")
if cg_context.attribute_get:
pass
elif cg_context.attribute_set:
arguments.append("${arg1_value}")
else:
for index, argument in enumerate(cg_context.function_like.arguments,
1):
name = name_style.arg_f("arg{}_{}", index, argument.identifier)
arguments.append(_format("${{{}}}", name))
if cg_context.is_return_by_argument:
arguments.append("${return_value}")
if cg_context.may_throw_exception:
arguments.append("${exception_state}")
text = _format("{_1}({_2})", _1=func_name, _2=", ".join(arguments))
code_node.add_template_var("blink_api_call", TextNode(text))
def bind_callback_local_vars(code_node, cg_context): def bind_callback_local_vars(code_node, cg_context):
...@@ -141,9 +91,10 @@ def bind_callback_local_vars(code_node, cg_context): ...@@ -141,9 +91,10 @@ def bind_callback_local_vars(code_node, cg_context):
"V8PerIsolateData::From(${isolate});")), "V8PerIsolateData::From(${isolate});")),
S("property_name", S("property_name",
"const char* const ${property_name} = \"${property.identifier}\";"), "const char* const ${property_name} = \"${property.identifier}\";"),
S("receiver", "v8::Local<v8::Object> ${receiver} = ${info}.This();"), S("v8_receiver",
"v8::Local<v8::Object> ${v8_receiver} = ${info}.This();"),
S("receiver_context", ("v8::Local<v8::Context> ${receiver_context} = " S("receiver_context", ("v8::Local<v8::Context> ${receiver_context} = "
"${receiver}->CreationContext();")), "${v8_receiver}->CreationContext();")),
S("receiver_script_state", S("receiver_script_state",
("ScriptState* ${receiver_script_state} = " ("ScriptState* ${receiver_script_state} = "
"ScriptState::From(${receiver_context});")), "ScriptState::From(${receiver_context});")),
...@@ -158,7 +109,7 @@ def bind_callback_local_vars(code_node, cg_context): ...@@ -158,7 +109,7 @@ def bind_callback_local_vars(code_node, cg_context):
local_vars.append(S("creation_context", _format(pattern, _1=_1))) local_vars.append(S("creation_context", _format(pattern, _1=_1)))
# creation_context_object # creation_context_object
text = ("${receiver}" text = ("${v8_receiver}"
if is_receiver_context else "${current_context}->Global()") if is_receiver_context else "${current_context}->Global()")
template_vars["creation_context_object"] = T(text) template_vars["creation_context_object"] = T(text)
...@@ -197,30 +148,145 @@ def bind_callback_local_vars(code_node, cg_context): ...@@ -197,30 +148,145 @@ def bind_callback_local_vars(code_node, cg_context):
local_vars.append( local_vars.append(
S("exception_state", _format(pattern, _1=", ".join(_1), _2=_2))) S("exception_state", _format(pattern, _1=", ".join(_1), _2=_2)))
# blink_receiver
if cg_context.class_like.identifier == "Window":
# TODO(yukishiino): Window interface should be
# [ImplementedAs=LocalDOMWindow] instead of [ImplementedAs=DOMWindow],
# and [CrossOrigin] properties should be implemented specifically with
# DOMWindow class. Then, we'll have less hacks.
if "CrossOrigin" in cg_context.member_like.extended_attributes:
text = ("DOMWindow* ${blink_receiver} = "
"${v8_class}::ToBlinkUnsafe(${v8_receiver});")
else:
text = ("LocalDOMWindow* ${blink_receiver} = To<LocalDOMWindow>("
"${v8_class}::ToBlinkUnsafe(${v8_receiver}));")
else:
pattern = ("{_1}* ${blink_receiver} = "
"${v8_class}::ToBlinkUnsafe(${v8_receiver});")
_1 = blink_class_name(cg_context.class_like)
text = _format(pattern, _1=_1)
local_vars.append(S("blink_receiver", text))
code_node.register_code_symbols(local_vars) code_node.register_code_symbols(local_vars)
code_node.add_template_vars(template_vars) code_node.add_template_vars(template_vars)
def _make_blink_api_call(cg_context, num_of_args=None):
assert isinstance(cg_context, CodeGenContext)
assert num_of_args is None or isinstance(num_of_args, (int, long))
arguments = []
ext_attrs = cg_context.member_like.extended_attributes
values = ext_attrs.values_of("CallWith") + (
ext_attrs.values_of("SetterCallWith") if cg_context.attribute_set else
())
if "Isolate" in values:
arguments.append("${isolate}")
if "ScriptState" in values:
arguments.append("${script_state}")
if "ExecutionContext" in values:
arguments.append("${execution_context}")
if cg_context.attribute_get:
pass
elif cg_context.attribute_set:
arguments.append("${arg1_value}")
else:
for index, argument in enumerate(cg_context.function_like.arguments):
if num_of_args is not None and index == num_of_args:
break
name = name_style.arg_f("arg{}_{}", index + 1, argument.identifier)
arguments.append(_format("${{{}}}", name))
if cg_context.is_return_by_argument:
arguments.append("${return_value}")
if cg_context.may_throw_exception:
arguments.append("${exception_state}")
code_generator_info = cg_context.member_like.code_generator_info
func_name = (code_generator_info.property_implemented_as
or name_style.api_func(cg_context.member_like.identifier))
if cg_context.attribute_set:
func_name = name_style.api_func("set", func_name)
is_partial_or_mixin = (code_generator_info.defined_in_partial
or code_generator_info.defined_in_mixin)
if cg_context.member_like.is_static or is_partial_or_mixin:
class_like = cg_context.member_like.owner_mixin or cg_context.class_like
class_name = (code_generator_info.receiver_implemented_as
or name_style.class_(class_like.identifier))
func_designator = "{}::{}".format(class_name, func_name)
if not cg_context.member_like.is_static:
arguments.insert(0, "*${blink_receiver}")
else:
func_designator = _format("${blink_receiver}->{}", func_name)
return _format("{_1}({_2})", _1=func_designator, _2=", ".join(arguments))
def bind_return_value(code_node, cg_context): def bind_return_value(code_node, cg_context):
assert isinstance(code_node, SymbolScopeNode) assert isinstance(code_node, SymbolScopeNode)
assert isinstance(cg_context, CodeGenContext) assert isinstance(cg_context, CodeGenContext)
T = TextNode
def create_definition(symbol_node): def create_definition(symbol_node):
if cg_context.return_type.unwrap().is_void: api_calls = []
text = "${blink_api_call};" arguments = (cg_context.function_like.arguments
elif cg_context.is_return_by_argument: if cg_context.function_like else [])
pattern = "{_1} ${return_value};\n${blink_api_call};" for index, arg in enumerate(arguments):
_1 = blink_type_info(cg_context.return_type).value_t if arg.is_optional and not arg.default_value:
text = _format(pattern, _1=_1) api_calls.append((index, _make_blink_api_call(
cg_context, index)))
api_calls.append((None, _make_blink_api_call(cg_context)))
nodes = []
is_return_type_void = cg_context.return_type.unwrap().is_void
if not is_return_type_void:
return_type = blink_type_info(cg_context.return_type).value_t
if len(api_calls) == 1:
_, api_call = api_calls[0]
if is_return_type_void:
nodes.append(T(_format("{};", api_call)))
elif cg_context.is_return_by_argument:
nodes.append(T(_format("{} ${return_value};", return_type)))
nodes.append(T(_format("{};", api_call)))
else:
nodes.append(
T(_format("const auto& ${return_value} = {};", api_call)))
else: else:
text = "const auto& ${return_value} = ${blink_api_call};" branches = SymbolScopeNode()
node = SymbolDefinitionNode(symbol_node, [TextNode(text)]) for index, api_call in api_calls:
if is_return_type_void or cg_context.is_return_by_argument:
assignment = api_call
else:
assignment = _format("${return_value} = {}", api_call)
if index is not None:
pattern = ("if (${info}[{index}]->IsUndefined()) {{\n"
" {assignment};\n"
" break;\n"
"}}")
else:
pattern = "{assignment};"
text = _format(pattern, index=index, assignment=assignment)
branches.append(T(text))
if not is_return_type_void:
nodes.append(T(_format("{} ${return_value};", return_type)))
nodes.append(T("do { // Dummy loop for use of 'break'"))
nodes.append(branches)
nodes.append(T("} while (false);"))
if cg_context.may_throw_exception: if cg_context.may_throw_exception:
node.append( nodes.append(
UnlikelyExitNode( UnlikelyExitNode(
cond=TextNode("${exception_state}.HadException()"), cond=T("${exception_state}.HadException()"),
body=SymbolScopeNode([TextNode("return;")]))) body=SymbolScopeNode([T("return;")])))
return node
return SymbolDefinitionNode(symbol_node, nodes)
code_node.register_code_symbol( code_node.register_code_symbol(
SymbolNode("return_value", definition_constructor=create_definition)) SymbolNode("return_value", definition_constructor=create_definition))
...@@ -251,7 +317,6 @@ def bind_v8_set_return_value(code_node, cg_context): ...@@ -251,7 +317,6 @@ def bind_v8_set_return_value(code_node, cg_context):
_callback_common_binders = ( _callback_common_binders = (
bind_blink_api_arguments, bind_blink_api_arguments,
bind_blink_api_call,
bind_callback_local_vars, bind_callback_local_vars,
bind_return_value, bind_return_value,
bind_v8_set_return_value, bind_v8_set_return_value,
...@@ -268,7 +333,8 @@ def make_check_receiver(cg_context): ...@@ -268,7 +333,8 @@ def make_check_receiver(cg_context):
return SequenceNode([ return SequenceNode([
T("// [LenientThis]"), T("// [LenientThis]"),
UnlikelyExitNode( UnlikelyExitNode(
cond=T("!${v8_class}::HasInstance(${receiver}, ${isolate})"), cond=T(
"!${v8_class}::HasInstance(${v8_receiver}, ${isolate})"),
body=SymbolScopeNode([T("return;")])), body=SymbolScopeNode([T("return;")])),
]) ])
...@@ -277,7 +343,8 @@ def make_check_receiver(cg_context): ...@@ -277,7 +343,8 @@ def make_check_receiver(cg_context):
T("// Promise returning function: " T("// Promise returning function: "
"Convert a TypeError to a reject promise."), "Convert a TypeError to a reject promise."),
UnlikelyExitNode( UnlikelyExitNode(
cond=T("!${v8_class}::HasInstance(${receiver}, ${isolate})"), cond=T(
"!${v8_class}::HasInstance(${v8_receiver}, ${isolate})"),
body=SymbolScopeNode([ body=SymbolScopeNode([
T("${exception_state}.ThrowTypeError(" T("${exception_state}.ThrowTypeError("
"\"Illegal invocation\");"), "\"Illegal invocation\");"),
...@@ -723,8 +790,8 @@ auto v8_private_cached_attribute = ...@@ -723,8 +790,8 @@ auto v8_private_cached_attribute =
V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyCachedAttribute); V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertyCachedAttribute);
if (!impl->""" + pred + """()) { if (!impl->""" + pred + """()) {
v8::Local<v8::Value> v8_value; v8::Local<v8::Value> v8_value;
if (v8_private_cached_attribute.GetOrUndefined(${receiver}).ToLocal(&v8_value) if (v8_private_cached_attribute.GetOrUndefined(${v8_receiver})
&& !v8_value->IsUndefined()) { .ToLocal(&v8_value) && !v8_value->IsUndefined()) {
V8SetReturnValue(${info}, v8_value); V8SetReturnValue(${info}, v8_value);
return; return;
} }
...@@ -738,8 +805,8 @@ auto v8_private_save_same_object = ...@@ -738,8 +805,8 @@ auto v8_private_save_same_object =
V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertySaveSameObject); V8PrivateProperty::GetSymbol(${isolate}, kPrivatePropertySaveSameObject);
{ {
v8::Local<v8::Value> v8_value; v8::Local<v8::Value> v8_value;
if (v8_private_save_same_object.GetOrUndefined(${receiver}).ToLocal(&v8_value) if (v8_private_save_same_object.GetOrUndefined(${v8_receiver})
&& !v8_value->IsUndefined()) { .ToLocal(&v8_value) && !v8_value->IsUndefined()) {
V8SetReturnValue(${info}, v8_value); V8SetReturnValue(${info}, v8_value);
return; return;
} }
...@@ -752,12 +819,12 @@ def make_return_value_cache_update_value(cg_context): ...@@ -752,12 +819,12 @@ def make_return_value_cache_update_value(cg_context):
if "CachedAttribute" in cg_context.member_like.extended_attributes: if "CachedAttribute" in cg_context.member_like.extended_attributes:
return TextNode("// [CachedAttribute]\n" return TextNode("// [CachedAttribute]\n"
"v8_private_cached_attribute.Set" "v8_private_cached_attribute.Set"
"(${receiver}, ${info}.GetReturnValue().Get());") "(${v8_receiver}, ${info}.GetReturnValue().Get());")
if "SaveSameObject" in cg_context.member_like.extended_attributes: if "SaveSameObject" in cg_context.member_like.extended_attributes:
return TextNode("// [SaveSameObject]\n" return TextNode("// [SaveSameObject]\n"
"v8_private_save_same_object.Set" "v8_private_save_same_object.Set"
"(${receiver}, ${info}.GetReturnValue().Get());") "(${v8_receiver}, ${info}.GetReturnValue().Get());")
def make_runtime_call_timer_scope(cg_context): def make_runtime_call_timer_scope(cg_context):
......
...@@ -47,6 +47,7 @@ from .function_like import FunctionLike ...@@ -47,6 +47,7 @@ from .function_like import FunctionLike
from .function_like import OverloadGroup from .function_like import OverloadGroup
from .idl_type import IdlType from .idl_type import IdlType
from .interface import Interface from .interface import Interface
from .literal_constant import LiteralConstant
from .namespace import Namespace from .namespace import Namespace
from .operation import Operation from .operation import Operation
from .operation import OperationGroup from .operation import OperationGroup
......
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