blob: 06eb5fe9a07036bc3a550e6c7686987f571784cf [file] [log] [blame]
{##############################################################################}
{# FIXME: We should return a rejected Promise if an error occurs in this
function when ALL methods in this overload return Promise. In order to do so,
we must ensure either ALL or NO methods in this overload return Promise #}
{% macro overload_resolution_method(method) %}
{% set overloads = method.overloads %}
{% if method.is_static %}
{% set offset = 0 %}
{% else %}
{% set offset = 1 %}
{% endif %}
static void {{static_method_name(overloads.name)}}Dispatcher(Dart_NativeArguments args)
{
Dart_Handle exception = nullptr;
const int argOffset = {{offset}};
int argCount = Dart_GetNativeArgumentCount(args) - argOffset;
{# First resolve by length #}
{# 2. Initialize argcount to be min(maxarg, n). #}
switch (std::min({{overloads.maxarg}}, argCount)) {
{# 3. Remove from S all entries whose type list is not of length argcount. #}
{% for length, tests_methods in overloads.length_tests_methods %}
{# 10. If i = d, then: #}
case {{length}}:
{# Then resolve by testing argument #}
{% for test, method in tests_methods %}
if ({{test}}) {
{% if method.is_custom %}
{{static_method_name(method.name)}}(args);
{% else %}
{{static_method_name(method.name, method.overload_index)}}(args);
{% endif %}
return;
}
{% endfor %}
break;
{% endfor %}
default:
{# Invalid arity, throw error #}
{# Report full list of valid arities if gaps and above minimum #}
{% if overloads.valid_arities %}
if (argCount >= {{overloads.minarg}}) {
const String message = "Wrong arity, expected one of {{overloads.valid_arities}}";
// TODO(dart): exception = DartUtilities::coreArgumentErrorException(message);
goto fail;
}
{% endif %}
{# Otherwise just report "not enough arguments" #}
{
const String message = "Not enough arguments (at least {{overloads.minarg}} required)";
// TODO(dart): exception = DartUtilities::coreArgumentErrorException(message);
goto fail;
}
return;
}
{
const String message = "No function was found that matched the signature provided.";
// TODO(dart): exception = DartUtilities::coreArgumentErrorException(message);
goto fail;
}
return;
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
}
{% endmacro %}
{##############################################################################}
{# arguments_count is normal method.number_of_arguments however for optional #}
{# arguments then number_of_required_arguments is passed (sans optional). #}
{# overload in the index if overloaded. #}
{# interface is specified signals that it's a constructor being called the #}
{# delegation to the create is emitted.
{##############################################################################}
{% macro generate_method(method, arguments_count) %}
{% set overload_index = method.overload_index %}
static void {{static_method_name(method.name, overload_index)}}(Dart_NativeArguments args)
{
{% if not method.is_static %}
{{cpp_class}}* /* FIXME(vsm): Remove this. */ ALLOW_UNUSED receiver = GetReceiver<{{cpp_class}}>(args);
{% endif %}
{% if method.is_custom_element_callbacks %}
CustomElementCallbackScope deliveryScope;
{% endif %}
{% if arguments_count > 0 or
method.has_exception_state or
method.is_call_with_script_state or
method.is_call_with_execution_context or
method.is_call_with_script_arguments %}
Dart_Handle exception = nullptr;
{% endif %}
{
{% if method.is_call_with_script_state %}
ScriptState* state = DartUtilities::currentScriptState();
if (!state) {
exception = ToDart("Failed to retrieve a script state");
goto fail;
}
{% endif %}
{% if method.is_call_with_execution_context %}
ExecutionContext* context = DOMDartState::CurrentDocument();
if (!context) {
exception = ToDart("Failed to retrieve a context");
goto fail;
}
{% endif %}
{% if method.is_call_with_script_arguments %}
{# Last parameter is the customArgument #}
Dart_Handle customArgument = Dart_GetNativeArgument(args, Dart_GetNativeArgumentCount(args) - 1);
RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));
if (!scriptArguments)
goto fail;
{% endif %}
{% if method.number_of_arguments != method.number_of_required_arguments %}
int argCount /* FIXME(vsm): Remove this. */ ALLOW_UNUSED = Dart_GetNativeArgumentCount(args);
{% endif %}
{% if method.has_exception_state %}
ExceptionState es;
{% endif %}
{{generate_arguments(method) | indent(8)}}
{{callback_return(method, method.dart_set_return_value, method.cpp_value)}}
{% if method.has_exception_state %}
if (es.had_exception()) {
exception = es.GetDartException(args, {{method.auto_scope}});
goto fail;
}
{% endif %}
return;
}
{% if arguments_count > 0 or method.has_exception_state or method.is_call_with_script_state or method.is_call_with_execution_context or method.is_call_with_script_arguments %}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
{% endif %}
}
{% endmacro %}
{##############################################################################}
{% macro callback_return(method, dart_set_return_value, cpp_value) %}
{%- if method.union_arguments -%}
{{callback_union_return(method) | indent(8)}}
{%- elif method.idl_type == 'void' -%}
{{cpp_value}};
{%- elif method.is_constructor -%}
DartConverter<{{cpp_class}}*>::SetReturnValue(args, WTF::getPtr({{cpp_value}}), {{method.auto_scope}});
{%- else -%}
{{dart_set_return_value}};
{%- endif -%}
{% endmacro %}
{##############################################################################}
{% macro callback_union_return(method, argument_count) %}
{% set type_index = 0 %}
{% for union_argument in method.union_arguments %}
{{method.cpp_type[type_index]}} {{union_argument}};
{% set type_index = type_index + 1 %}
{% endfor %}
{{method.cpp_value}};
{% set union_set_result_index = 0 %}
{% for union_argument in method.union_arguments %}
if ({{union_argument}}) {
{{method.dart_set_return_value[union_set_result_index]}};
return;
}
{% set union_set_result_index = union_set_result_index + 1 %}
{% endfor %}
{% endmacro %}
{##############################################################################}
{% macro generate_argument(method, argument) %}
{# If sequence result is passed as an argument not as function return value. #}
{% if argument.is_optional and
not argument.has_default and
not argument.is_callback_interface %}
{# Optional arguments without a default value generate an early call with
fewer arguments if they are omitted. #}
if (UNLIKELY(argCount <= {{argument.arg_index}})) {
{{callback_return(method, argument.dart_set_return_value, argument.cpp_value)}}
if (exception)
goto fail;
return;
}
{% endif %}
{% if argument.is_callback_interface %}
{# Callback functions must be functions:
http://www.w3.org/TR/WebIDL/#es-callback-function #}
{% if argument.is_optional %}
{{argument.local_cpp_type}} {{argument.name}};
if (argCount > {{argument.arg_index}}) {
{{argument.name}} = DartConverter<{{argument.implemented_as}}*>::FromArgumentsWithNullCheck(args, {{argument.arg_index}}, exception);
}
{% else %}{# argument.is_optional #}
{{argument.local_cpp_type}} {{argument.name}} = DartConverter<{{argument.implemented_as}}*>::FromArgumentsWithNullCheck(args, {{argument.arg_index}}, exception);
{% endif %}{# argument.is_optional #}
{% else %}{# argument.is_callback_interface #}
{% if argument.is_optional and argument.has_default -%}
{{argument.local_cpp_type}} {{argument.name}} =
(argCount <= {{argument.arg_index}}) ? ({{argument.default_value}}) : {{argument.dart_value_to_local_cpp_value}};
{% elif argument.is_array_or_sequence_type %}
{{argument.local_cpp_type}} {{argument.name}};
{{argument.dart_value_to_local_cpp_value}};
{% else %}
{{argument.local_cpp_type}} {{argument.name}} = {{argument.dart_value_to_local_cpp_value}};
{% endif %}
{% endif %}{# argument.is_callback_interface #}
if (exception)
goto fail;
{% endmacro %}
{######################################}
{% macro generate_arguments(method) %}
{%- for argument in method.arguments -%}
{{generate_argument(method, argument)}}
{%- endfor -%}
{% endmacro %}
{##############################################################################}
{% macro static_method_name(name, overload_index) %}
{% set name = 'constructor' if not name else name -%}
{% if overload_index -%}
{{name}}Callback_{{overload_index}}
{%- else -%}
{{name}}Callback
{%- endif %}
{% endmacro -%}
{##############################################################################}
{% macro generate_resolver_body(dart_class, class_name, method) %}
{% for native_entry_group in method.native_entries|groupby('resolver_string') %}
{% set uses_script_args = method.is_call_with_script_arguments %}
{% if method.overload_index %}
{% set method_name = static_method_name(method.name) + "Dispatcher" %}
{% else %}
{% set method_name = static_method_name(method.name) %}
{% endif %}
{% set resolver_string = native_entry_group.grouper %}
{% if method.is_custom %}
// FIXME: we are missing changes from dart.idl so we don't always know how many
// args custom methods will take so we ignore that check which could hurt perf
// and security but lets us get everything running quicker.
if (name == "{{resolver_string}}") {
*autoSetupScope = {{method.auto_scope}};
return {{dart_class}}Internal::{{method_name}};
}
{% else %}
{% set args_one_based = method.number_of_arguments %}
{% set args_required_one_based = method.number_of_required_arguments %}
{% if not method.is_static %}
{% set args_one_based = args_one_based + 1 %}
{% set args_required_one_based = args_required_one_based + 1 %}
{% endif %}
{% if uses_script_args %}
{# FIXME(vsm): At least one script argument is expected. Generalize? #}
{% set args_one_based = args_one_based + 1 %}
{% set args_required_one_based = args_required_one_based + 1 %}
{% endif %}
{% if args_one_based == args_required_one_based %}
if (argumentCount == {{args_one_based}} && name == "{{resolver_string}}") {
*autoSetupScope = {{method.auto_scope}};
return {{dart_class}}Internal::{{method_name}};
}
{% else %}
if (argumentCount >= {{args_required_one_based}} && argumentCount <= {{args_one_based}} && name == "{{resolver_string}}") {
*autoSetupScope = {{method.auto_scope}};
return {{dart_class}}Internal::{{method_name}};
}
{% endif %}
{% endif %}
{% endfor %}
{% endmacro %}
{##############################################################################}
{% macro generate_symbolizer_body(dart_class, class_name, method) %}
{% for native_entry_group in method.native_entries|groupby('resolver_string') %}
{% set uses_script_args = method.is_call_with_script_arguments %}
{% if method.overload_index %}
{% set method_name = static_method_name(method.name) + "Dispatcher" %}
{% else %}
{% set method_name = static_method_name(method.name) %}
{% endif %}
{% set resolver_string = native_entry_group.grouper %}
if (native_function == {{dart_class}}Internal::{{method_name}}) {
return reinterpret_cast<const uint8_t*>("{{resolver_string}}");
}
{% endfor %}
{% endmacro %}
{##############################################################################}
{% macro generate_constructor(constructor, arguments_count, overload='') %}
{% if overload == '' %}
{% set overload_index = constructor.overload_index %}
{% else %}
{% set overload_index = overload %}
{% endif %}
static void {{static_method_name(constructor.name, overload_index)}}(Dart_NativeArguments args)
{
{% if arguments_count > 0 or
constructor.has_exception_state or
is_constructor_call_with_execution_context or
is_constructor_call_with_document or
(constructor == named_constructor) %}
Dart_Handle exception = nullptr;
{% endif %}
{
{% if is_constructor_call_with_execution_context %}
ExecutionContext* context = DOMDartState::CurrentDocument();
if (!context) {
exception = ToDart("Failed to retrieve a context");
goto fail;
}
{% endif %}
{% if is_constructor_call_with_document or (constructor == named_constructor) %}
LocalDOMWindow* domWindow = DOMDartState::CurrentWindow();
if (!domWindow) {
exception = ToDart("Failed to fetch domWindow");
goto fail;
}
Document& document = *domWindow->document();
{% endif %}
int argCount /* FIXME(vsm): Remove this. */ ALLOW_UNUSED = Dart_GetNativeArgumentCount(args);
{% if constructor.has_exception_state %}
ExceptionState es;
{% endif %}
{{generate_arguments(constructor) | indent(8)}}
{{constructor.cpp_value}}->AssociateWithDartWrapper(args);
{% if constructor.has_exception_state %}
if (es.had_exception()) {
exception = es.GetDartException(args, {{constructor.auto_scope}});
goto fail;
}
{% endif %}
return;
}
{% if arguments_count > 0 or constructor.has_exception_state or is_constructor_call_with_execution_context or is_constructor_call_with_document or (constructor == named_constructor) %}
fail:
Dart_ThrowException(exception);
ASSERT_NOT_REACHED();
{% endif %}
}
{% endmacro %}
{##############################################################################}
{% macro generate_event_constructor() %}
static void eventConstructorCallback(Dart_NativeArguments args)
{
Dart_SetReturnValue(args, Dart_Null());
}
{% endmacro %}
,
{##############################################################################}
{% macro generate_resolver_constructor(dart_class, class_name, constructor) %}
{% for native_entry in constructor.native_entries %}
{% set resolver_string = native_entry.resolver_string %}
{% set args_one_based = constructor.number_of_arguments + 1 %}
{% set args_required_one_based = constructor.number_of_required_arguments + 1 %}
{% if constructor.overload_index %}
{% set constructor_name = static_method_name(constructor.name) + "Dispatcher" %}
{% else %}
{% set constructor_name = static_method_name(constructor.name) %}
{% endif %}
{% if has_custom_constructor %}
if (name == "{{resolver_string}}") {
{% elif constructor.number_of_arguments == constructor.number_of_required_arguments %}
if (argumentCount == {{args_one_based}} && name == "{{resolver_string}}") {
{% else %}
if (argumentCount >= {{args_required_one_based}} && argumentCount <= {{args_one_based}} && name == "{{resolver_string}}") {
{% endif %}
*autoSetupScope = {{constructor.auto_scope}};
return {{dart_class}}Internal::{{constructor_name}};
}
{% endfor %}
{% endmacro %}
{##############################################################################}
{% macro generate_resolver_event_constructor(dart_class, class_name) %}
{% set resolver_string = interface_name + "_constructorCallback" %}
if (argumentCount == 2 && name == "{{resolver_string}}") {
*autoSetupScope = 1;
return {{dart_class}}Internal::eventConstructorCallback;
}
{% endmacro %}
{##############################################################################}
{% macro generate_symbolizer_constructor(dart_class, class_name, constructor) %}
{% for native_entry in constructor.native_entries %}
{% set resolver_string = native_entry.resolver_string %}
if (native_function == {{dart_class}}Internal::{{static_method_name(constructor.name, constructor.overload_index)}}) {
return reinterpret_cast<const uint8_t*>("{{resolver_string}}");
}
{% endfor %}
{% endmacro %}