blob: 5f31a7077cef1b15a5a41b96fcda5a6e79f6426d [file] [log] [blame]
{% from 'utilities.cpp.tmpl' import declare_enum_validation_variable, v8_value_to_local_cpp_value %}
{##############################################################################}
{% macro runtime_timer_scope(counter) %}
RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), RuntimeCallStats::CounterId::{{counter}});
{% endmacro %}
{% macro runtime_timer_scope_disabled_by_default(counter) %}
RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "{{counter}}");
{% endmacro %}
{% macro generate_method(method, world_suffix) %}
static void {{method.name}}{{method.overload_index}}Method{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info) {
{% filter format_remove_duplicates([
'ExceptionState exceptionState',
'ScriptState* scriptState = ']) %}
{% set define_exception_state -%}
ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "{{interface_name}}", "{{method.name}}");
{%- endset %}
{% if method.is_ce_reactions %}
CEReactionsScope ceReactionsScope;
{% endif %}
{% set function_call = func_call_with_prep_of_args(method, world_suffix) %}
{% if 'exceptionState' in function_call or
(method.returns_promise and not method.is_static) %}
{{define_exception_state}}
{% if method.returns_promise %}
ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
{% endif %}
{% endif %}
{% if not method.is_static %}
{% if method.returns_promise %}
// V8DOMConfiguration::kDoNotCheckHolder
// Make sure that info.Holder() really points to an instance of the type.
if (!{{v8_class}}::hasInstance(info.Holder(), info.GetIsolate())) {
{{throw_type_error(method, '"Illegal invocation"')}}
return;
}
{% endif %}
{% if interface_name == 'Window' and not method.is_cross_origin %}
// Same-origin methods are never exposed via the cross-origin interceptors.
// Since same-origin access requires a LocalDOMWindow, it is safe to downcast
// here.
LocalDOMWindow* impl = ToLocalDOMWindow({{v8_class}}::ToImpl(info.Holder()));
{% else %}
{{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder());
{% endif %}{# interface_name == 'Window' and not method.is_cross_origin #}
{% endif %}{# not method.is_static #}
{# Security checks #}
{% if method.is_check_security_for_return_value %}
{{define_exception_state}}
if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), {{method.cpp_value}}, BindingSecurity::ErrorReportOption::kDoNotReport)) {
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()),
WebFeature::kCrossOrigin{{interface_name}}{{method.name|blink_capitalize}});
V8SetReturnValueNull(info);
return;
}
{% endif %}
{% if 'scriptState' in function_call %}
{% if method.is_static %}
ScriptState* scriptState = ScriptState::ForCurrentRealm(info);
{% else %}
ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
{% endif %}
{% endif %}
{% if method.is_custom_element_callbacks %}
V0CustomElementProcessingStack::CallbackDeliveryScope deliveryScope;
{% endif %}
{{function_call | trim | indent(2)}}
}
{% endfilter %}
{% endmacro %}
{######################################}
{% macro func_call_with_prep_of_args(method, world_suffix) %}
{{generate_arguments(method, world_suffix)}}
{% if world_suffix %}
{{cpp_method_call(method, method.v8_set_return_value_for_main_world, method.cpp_value)}}
{% else %}
{{cpp_method_call(method, method.v8_set_return_value, method.cpp_value)}}
{% endif %}
{% endmacro %}
{######################################}
{% macro generate_arguments(method, world_suffix) %}
{% if method.arguments %}
{# Overloaded methods/constructors have length checked during overload resolution #}
{% if method.number_of_required_arguments and not method.overload_index %}
if (UNLIKELY(info.Length() < {{method.number_of_required_arguments}})) {
{{throw_type_error(method,
'ExceptionMessages::NotEnoughArguments(%(expected)d, info.Length())'
| format(expected=method.number_of_required_arguments))}}
return;
}
{% endif %}
{% for argument in method.arguments %}
{{argument.cpp_type}} {{argument.name}};
{% endfor %}
{% if method.has_optional_argument_without_default_value %}
{# Count the effective number of arguments. (arg1, arg2, undefined) is
interpreted as two arguments are passed and (arg1, undefined, arg3) is
interpreted as three arguments are passed. #}
int numArgsPassed = info.Length();
while (numArgsPassed > 0) {
if (!info[numArgsPassed - 1]->IsUndefined())
break;
--numArgsPassed;
}
{% endif %}
{% for argument in method.arguments %}
{% if argument.set_default_value %}
if (!info[{{argument.index}}]->IsUndefined()) {
{{generate_argument(method, argument, world_suffix) | trim | indent(2)}}
} else {
{{argument.set_default_value | trim | indent(2)}};
}
{% else %}
{{generate_argument(method, argument, world_suffix)}}
{% endif %}
{% endfor %}
{% endif %}{# method.arguments #}
{% endmacro %}
{######################################}
{% macro generate_argument(method, argument, world_suffix) %}
{% if argument.is_optional_without_default_value %}
{# Optional arguments without a default value generate an early call with
fewer arguments if they are omitted.
Optional Dictionary arguments default to empty dictionary. #}
if (UNLIKELY(numArgsPassed <= {{argument.index}})) {
{% if world_suffix %}
{{cpp_method_call(method, argument.v8_set_return_value_for_main_world, argument.cpp_value) | trim | indent(2)}}
{% else %}
{{cpp_method_call(method, argument.v8_set_return_value, argument.cpp_value) | trim | indent(2)}}
{% endif %}
return;
}
{% endif %}
{% if argument.is_callback_interface %}
{# FIXME: remove EventListener special case. crbug.com/630986 #}
{% if argument.idl_type == 'EventListener' %}
if (!IsUndefinedOrNull(info[{{argument.index}}]) && !info[{{argument.index}}]->IsObject()) {
{{throw_argument_error(method, argument, "The callback provided as parameter %(index)d is not an object.")}}
return;
}
{% if method.name == 'removeEventListener' or method.name == 'removeListener' %}
{{argument.name}} = V8EventListenerHelper::GetEventListener(ScriptState::Current(info.GetIsolate()), info[{{argument.index}}], false, kListenerFindOnly);
{% else %}{# method.name == 'AddEventListener' #}
{{argument.name}} = V8EventListenerHelper::GetEventListener(ScriptState::Current(info.GetIsolate()), info[{{argument.index}}], false, kListenerFindOrCreate);
{% endif %}{# method.name #}
{% else %}{# argument.idl_type == 'EventListener' #}
if (info[{{argument.index}}]->IsObject()) {
{{argument.name}} = V8{{argument.idl_type}}::Create(info[{{argument.index}}].As<v8::Object>());
{% if argument.is_nullable %}
} else if (info[{{argument.index}}]->IsNullOrUndefined()) {
{{argument.name}} = nullptr;
{% elif argument.is_optional %}
} else if (info[{{argument.index}}]->IsUndefined()) {
{{argument.name}} = nullptr;
{% endif %}
} else {
{{throw_argument_error(method, argument, "The callback provided as parameter %(index)d is not an object.")}}
return;
}
{% endif %}{# argument.idl_type == 'EventListener' #}
{% elif argument.is_callback_function %}
if (info[{{argument.index}}]->IsFunction()) {
{{v8_value_to_local_cpp_value(argument)}}
{% if argument.is_nullable %}
} else if (info[{{argument.index}}]->IsNullOrUndefined()) {
{{argument.name}} = nullptr;
{% elif argument.is_optional %}
} else if (info[{{argument.index}}]->IsUndefined()) {
{{argument.name}} = nullptr;
{% endif %}
} else {
{{throw_argument_error(method, argument, "The callback provided as parameter %(index)d is not a function.")}}
return;
}
{% elif argument.is_variadic_wrapper_type %}
for (int i = {{argument.index}}; i < info.Length(); ++i) {
if (!V8{{argument.idl_type}}::hasInstance(info[i], info.GetIsolate())) {
{{throw_argument_error(method, argument, "parameter %(index)d is not of type '%(type)s'.")}}
return;
}
{{argument.name}}.push_back(V8{{argument.idl_type}}::ToImpl(v8::Local<v8::Object>::Cast(info[i])));
}
{% elif argument.is_dictionary %}
{% if not argument.use_permissive_dictionary_conversion %}
{# Dictionaries must have type Undefined, Null or Object:
http://heycam.github.io/webidl/#es-dictionary #}
if (!info[{{argument.index}}]->IsNullOrUndefined() && !info[{{argument.index}}]->IsObject()) {
{{throw_argument_error(method, argument, "parameter %(index)d ('%(name)s') is not an object.")}}
return;
}
{% endif %}{# not argument.use_permissive_dictionary_conversion #}
{{v8_value_to_local_cpp_value(argument)}}
{% elif argument.is_explicit_nullable %}
if (!info[{{argument.index}}]->IsNullOrUndefined()) {
{{v8_value_to_local_cpp_value(argument) | trim | indent(2)}}
}
{% else %}{# argument is something else #}
{{v8_value_to_local_cpp_value(argument)}}
{% endif %}{# end of the dispatch by the argument type #}
{# Type checking, possibly throw a TypeError, per:
http://www.w3.org/TR/WebIDL/#es-type-mapping #}
{% if argument.has_type_checking_interface and not argument.is_variadic_wrapper_type %}
{# Type checking for wrapper interface types (if interface not implemented,
throw a TypeError), per http://www.w3.org/TR/WebIDL/#es-interface
Note: for variadic arguments, the type checking is done for each matched
argument instead; see argument.is_variadic_wrapper_type code-path above. #}
if (!{{argument.name}}{% if argument.is_nullable %} && !IsUndefinedOrNull(info[{{argument.index}}]){% endif %}) {
{{throw_argument_error(method, argument, "parameter %(index)d is not of type '%(type)s'.")}}
return;
}
{% elif argument.enum_values %}
{# Invalid enum values: http://www.w3.org/TR/WebIDL/#idl-enums #}
{% set enum_variable = 'valid' + argument.name[0].upper() + argument.name[1:] + 'Values' %}
{{declare_enum_validation_variable(argument.enum_values, enum_variable)}}
if (!IsValidEnum({{argument.name}}, {{enum_variable}}, base::size({{enum_variable}}), "{{argument.enum_type}}", exceptionState)) {
return;
}
{% elif argument.idl_type == 'Promise' %}
{# We require this for our implementation of promises, though not in spec:
http://heycam.github.io/webidl/#es-promise #}
if (!{{argument.name}}.IsUndefinedOrNull() && !{{argument.name}}.IsObject()) {
{{throw_argument_error(method, argument, "parameter %(index)d ('%(name)s') is not an object.")}}
return;
}
{% endif %}
{% endmacro %}
{######################################}
{% macro cpp_method_call(method, v8_set_return_value, cpp_value) %}
{% if method.is_custom_call_prologue %}
{{v8_class}}::{{method.name}}MethodPrologueCustom(info, impl);
{% endif %}
{# Local variables #}
{% if method.is_call_with_execution_context %}
{# [ConstructorCallWith=ExecutionContext] or [CallWith=ExecutionContext] #}
{% if method.is_constructor %}
ExecutionContext* executionContext = ToExecutionContext(
info.NewTarget().As<v8::Object>()->CreationContext());
{% elif method.is_static %}
ExecutionContext* executionContext = ExecutionContext::ForCurrentRealm(info);
{% else %}
ExecutionContext* executionContext = ExecutionContext::ForRelevantRealm(info);
{% endif %}
{% endif %}
{% if method.is_call_with_script_arguments %}
{# [CallWith=ScriptArguments] #}
ScriptArguments* scriptArguments(ScriptArguments::Create(scriptState, info, {{method.number_of_arguments}}));
{% endif %}
{% if method.is_call_with_document %}
{# [ConstructorCallWith=Document] #}
Document& document = *ToDocument(ToExecutionContext(
info.NewTarget().As<v8::Object>()->CreationContext()));
{% endif %}
{# Call #}
{% if method.idl_type == 'void' %}
{{cpp_value}};
{% elif method.use_output_parameter_for_result %}
{{method.cpp_type}} result;
{{cpp_value}};
{% elif method.is_constructor %}
{{method.cpp_type}} impl = {{cpp_value}};
{% elif method.use_local_result %}
{{method.cpp_type}} result = {{cpp_value}};
{% endif %}
{# Post-call #}
{% if method.is_raises_exception %}
if (exceptionState.HadException()) {
return;
}
{% endif %}
{# Set return value #}
{% if method.is_new_object and not method.do_not_test_new_object %}
{% if not method.returns_promise %}
{# We currently only add the DCHECK for IDL interfaces. Even though #}
{# [NewObject] also applies to promises, there is nothing for us to check at #}
{# the moment. #}
// [NewObject] must always create a new wrapper. Check that a wrapper
// does not exist yet.
DCHECK(!result || DOMDataStore::GetWrapper(result, info.GetIsolate()).IsEmpty());
{% endif %}{# not method.returns_promise #}
{% endif %}
{% if method.is_constructor %}
{{generate_constructor_wrapper(method)}}
{%- elif v8_set_return_value %}
{% if method.is_explicit_nullable %}
if (!result)
V8SetReturnValueNull(info);
else
{{v8_set_return_value}};
{% else %}
{{v8_set_return_value}};
{% endif %}
{%- endif %}{# None for void #}
{% if method.is_custom_call_epilogue %}
{{v8_class}}::{{method.name}}MethodEpilogueCustom(info, impl);
{% endif %}
{% endmacro %}
{##############################################################################}
{% macro throw_type_error(method, error_message) %}
{% if method.has_exception_state or method.returns_promise %}
exceptionState.ThrowTypeError({{error_message}});
{%- elif method.is_constructor %}
V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToConstruct("{{interface_name}}", {{error_message}}));
{%- else %}
V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("{{method.name}}", "{{interface_name}}", {{error_message}}));
{%- endif %}
{%- endmacro %}
{##############################################################################}
{% macro throw_argument_error(method, argument, error_message) %}
{% set quoted_message = '"%s"' % (error_message | replace('\"', '\\\"')) %}
{{throw_type_error(method, quoted_message | format(index=(argument.index + 1), name=argument.name, type=argument.idl_type))}}
{%- endmacro %}
{##############################################################################}
{% macro runtime_determined_length_method(overloads) %}
static int {{overloads.name}}MethodLength() {
{% for length, runtime_enabled_features in overloads.runtime_determined_lengths %}
{% for runtime_enabled_feature in runtime_enabled_features %}
{% filter runtime_enabled(runtime_enabled_feature) %}
return {{length}};
{% endfilter %}
{% endfor %}
{% endfor %}
}
{% endmacro %}
{##############################################################################}
{% macro runtime_determined_maxarg_method(overloads) %}
static int {{overloads.name}}MethodMaxArg() {
{% for length, runtime_enabled_features in overloads.runtime_determined_maxargs %}
{% for name in runtime_enabled_features %}
{% filter runtime_enabled(name) %}
return {{length}};
{% endfilter %}
{% endfor %}
{% endfor %}
}
{% endmacro %}
{##############################################################################}
{% macro overload_resolution_method(overloads, world_suffix) %}
static void {{overloads.name}}Method{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info) {
{% set fall_through_to_partial_overloads = not is_partial and overloads.has_partial_overloads %}
{% if overloads.measure_all_as %}
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{overloads.measure_all_as}});
{% endif %}
{% if overloads.deprecate_all_as %}
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{overloads.deprecate_all_as}});
{% endif %}
{# First resolve by length #}
{% if not fall_through_to_partial_overloads %}
bool isArityError = false;
{% endif %}
{# This follows the overload resolution algorithm. #}
{# https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm #}
{# 3. Initialize argcount to be min(maxarg, n). #}
switch (std::min({{overloads.maxarg}}, info.Length())) {
{# 4. Remove from S all entries whose type list is not of length argcount. #}
{% for length, tests_methods in overloads.length_tests_methods %}
{# 12. If i = d, then: #}
case {{length}}:
{# Then resolve by testing argument #}
{% for test, method in tests_methods %}
{% if method.visible %}
{% filter runtime_enabled(not overloads.runtime_enabled_all and method.runtime_enabled_feature_name) %}
{% if "exceptionState" in test %}
{
ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext,
"{{interface_name}}", "{{overloads.name}}");
{{ test_and_call_overloaded_method(test, method, overloads, world_suffix) | trim | indent(8) }}
if (exceptionState.HadException()) {
exceptionState.RethrowV8Exception(exceptionState.GetException());
return;
}
}
{% else %}{# exceptionState #}
{{ test_and_call_overloaded_method(test, method, overloads, world_suffix) | trim | indent(6) }}
{% endif %}{# exceptionState #}
{% endfilter %}
{% endif %}
{% endfor %}
break;
{% endfor %}{# length, tests_methods #}
{% if not fall_through_to_partial_overloads %}
default:
{# 12.19. Otherwise: throw a TypeError. #}
isArityError = true;
{% endif %}
}
{% if fall_through_to_partial_overloads %}
DCHECK({{overloads.name}}MethodForPartialInterface);
({{overloads.name}}MethodForPartialInterface)(info);
{% else %}{# fall_through_to_partial_overloads #}
ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "{{interface_name}}", "{{overloads.name}}");
{% if overloads.returns_promise_all %}
ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
{% endif %}
if (isArityError) {
{% if overloads.length != 0 %}
if (info.Length() < {{overloads.length}}) {
exceptionState.ThrowTypeError(ExceptionMessages::NotEnoughArguments({{overloads.length}}, info.Length()));
return;
}
{% endif %}
{% if overloads.valid_arities %}
if (info.Length() >= {{overloads.length}}) {
exceptionState.ThrowTypeError(ExceptionMessages::InvalidArity("{{overloads.valid_arities}}", info.Length()));
return;
}
{% endif %}
}
exceptionState.ThrowTypeError("No function was found that matched the signature provided.");
{% endif %}{# fall_through_to_partial_overloads #}
}
{% endmacro %}
{% macro test_and_call_overloaded_method(test, method, overloads, world_suffix) %}
if ({{test}}) {
{% if method.measure_as and not overloads.measure_all_as %}
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.measure_as('Method')}});
{% endif %}
{% if method.deprecate_as and not overloads.deprecate_all_as %}
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.deprecate_as}});
{% endif %}
{{method.name}}{{method.overload_index}}Method{{world_suffix}}(info);
return;
}
{% endmacro %}
{##############################################################################}
{% macro generate_post_message_impl(method) %}
static void postMessageImpl(const char* interfaceName, {{cpp_class}}* instance, const v8::FunctionCallbackInfo<v8::Value>& info) {
ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, interfaceName, "postMessage");
if (UNLIKELY(info.Length() < {{method.number_of_required_arguments}})) {
exceptionState.ThrowTypeError(ExceptionMessages::NotEnoughArguments({{method.number_of_required_arguments}}, info.Length()));
return;
}
Transferables transferables;
if (info.Length() > 1) {
const int transferablesArgIndex = 1;
if (!SerializedScriptValue::ExtractTransferables(info.GetIsolate(), info[transferablesArgIndex], transferablesArgIndex, transferables, exceptionState)) {
return;
}
}
scoped_refptr<SerializedScriptValue> message;
if (instance->CanTransferArrayBuffersAndImageBitmaps()) {
// This instance supports sending array buffers by move semantics.
SerializedScriptValue::SerializeOptions options;
options.transferables = &transferables;
message = SerializedScriptValue::Serialize(info.GetIsolate(), info[0], options, exceptionState);
if (exceptionState.HadException())
return;
} else {
// This instance doesn't support sending array buffers and image bitmaps
// by move semantics. Emulate it by copy-and-neuter semantics that sends
// array buffers and image bitmaps via structured clone and then neuters
// the original objects
// Clear references to array buffers and image bitmaps from transferables
// so that the serializer can consider the array buffers as
// non-transferable and serialize them into the message.
ArrayBufferArray transferableArrayBuffers = SerializedScriptValue::ExtractNonSharedArrayBuffers(transferables);
ImageBitmapArray transferableImageBitmaps = transferables.image_bitmaps;
transferables.image_bitmaps.clear();
SerializedScriptValue::SerializeOptions options;
options.transferables = &transferables;
message = SerializedScriptValue::Serialize(info.GetIsolate(), info[0], options, exceptionState);
if (exceptionState.HadException())
return;
// Neuter the original array buffers on the sender context.
SerializedScriptValue::TransferArrayBufferContents(info.GetIsolate(), transferableArrayBuffers, exceptionState);
if (exceptionState.HadException())
return;
// Neuter the original image bitmaps on the sender context.
SerializedScriptValue::TransferImageBitmapContents(info.GetIsolate(), transferableImageBitmaps, exceptionState);
if (exceptionState.HadException())
return;
}
// FIXME: Only pass scriptState/exceptionState if instance really requires it.
ScriptState* scriptState = ScriptState::Current(info.GetIsolate());
message->UnregisterMemoryAllocatedWithCurrentScriptContext();
instance->postMessage(scriptState, std::move(message), transferables.message_ports, exceptionState);
}
{% endmacro %}
{##############################################################################}
{% macro method_callback(method, world_suffix) %}
void {{v8_class_or_partial}}::{{method.name}}MethodCallback{{world_suffix}}(const v8::FunctionCallbackInfo<v8::Value>& info) {
{% if method.runtime_call_stats.extended_attribute_defined %}
{{ runtime_timer_scope(method.runtime_call_stats.method_counter) | trim | indent(2) }}
{% else %}
{{ runtime_timer_scope_disabled_by_default(method.runtime_call_stats.method_counter) }}
{% endif %}
{% if not method.overloads %}{# Overloaded methods are measured in overload_resolution_method() #}
{% if method.measure_as %}
UseCounter::Count(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.measure_as('Method')}});
{% endif %}
{% if method.deprecate_as %}
Deprecation::CountDeprecation(CurrentExecutionContext(info.GetIsolate()), WebFeature::k{{method.deprecate_as}});
{% endif %}
{% endif %}{# not method.overloads #}
{% if world_suffix in method.activity_logging_world_list %}
{% if method.is_static %}
ScriptState* scriptState = ScriptState::ForCurrentRealm(info);
{% else %}
ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
{% endif %}
V8PerContextData* contextData = scriptState->PerContextData();
if (contextData && contextData->ActivityLogger()) {
contextData->ActivityLogger()->LogMethod("{{interface_name}}.{{method.name}}", info);
}
{% endif %}
{% if method.is_custom %}
{{v8_class}}::{{method.name}}MethodCustom(info);
{% elif method.is_post_message %}
{{cpp_class_or_partial}}V8Internal::postMessageImpl("{{interface_name}}", {{v8_class}}::ToImpl(info.Holder()), info);
{% else %}
{{cpp_class_or_partial}}V8Internal::{{method.name}}Method{{world_suffix}}(info);
{% endif %}
}
{% endmacro %}
{##############################################################################}
{% macro origin_safe_method_getter(method, world_suffix) %}
{# TODO(dcheng): Currently, bindings must create a function object for each
realm as a hack to support the incumbent realm. Clean this up when Blink
properly supports the incumbent realm. #}
static void {{method.name}}OriginSafeMethodGetter{{world_suffix}}(const v8::PropertyCallbackInfo<v8::Value>& info) {
static int domTemplateKey; // This address is used for a key to look up the dom template.
V8PerIsolateData* data = V8PerIsolateData::From(info.GetIsolate());
const DOMWrapperWorld& world = DOMWrapperWorld::World(info.GetIsolate()->GetCurrentContext());
v8::Local<v8::FunctionTemplate> interfaceTemplate = data->FindInterfaceTemplate(world, &{{v8_class}}::wrapperTypeInfo);
v8::Local<v8::Signature> signature = v8::Signature::New(info.GetIsolate(), interfaceTemplate);
v8::Local<v8::FunctionTemplate> methodTemplate = data->FindOrCreateOperationTemplate(world, &domTemplateKey, {{v8_class_or_partial}}::{{method.name}}MethodCallback{{world_suffix}}, V8Undefined(), signature, {{method.length}});
// Return the function by default, unless the user script has overwritten it.
V8SetReturnValue(info, methodTemplate->GetFunction(info.GetIsolate()->GetCurrentContext()).ToLocalChecked());
{{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder());
if (!BindingSecurity::ShouldAllowAccessTo(CurrentDOMWindow(info.GetIsolate()), impl, BindingSecurity::ErrorReportOption::kDoNotReport)) {
return;
}
{% raw %}
// {{method.name}} must be same with |methodName| (=name) in
// {{cpp_class}}OriginSafeMethodSetter defined in interface.cpp.tmpl.
{% endraw %}
V8PrivateProperty::Symbol propertySymbol =
V8PrivateProperty::GetSymbol(info.GetIsolate(), "{{method.name}}");
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast(info.Holder());
if (propertySymbol.HasValue(holder)) {
V8SetReturnValue(info, propertySymbol.GetOrUndefined(holder));
}
}
{% endmacro %}
{% macro origin_safe_method_getter_callback(method, world_suffix) %}
void {{v8_class_or_partial}}::{{method.name}}OriginSafeMethodGetterCallback{{world_suffix}}(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
{{ runtime_timer_scope_disabled_by_default(method.runtime_call_stats.origin_safe_method_getter_counter) }}
{{cpp_class}}V8Internal::{{method.name}}OriginSafeMethodGetter{{world_suffix}}(info);
}
{% endmacro %}
{##############################################################################}
{% macro generate_constructor(constructor) %}
{% set name = '%sConstructorCallback' % v8_class
if constructor.is_named_constructor else
'constructor%s' % (constructor.overload_index or '') %}
static void {{name}}(const v8::FunctionCallbackInfo<v8::Value>& info) {
{{ runtime_timer_scope_disabled_by_default(constructor.rcs_counter) }}
{% set function_call = func_call_with_prep_of_args(constructor) %}
{% if constructor.is_named_constructor %}
if (!info.IsConstructCall()) {
V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::ConstructorNotCallableAsFunction("{{constructor.name}}"));
return;
}
if (ConstructorMode::Current(info.GetIsolate()) == ConstructorMode::kWrapExistingObject) {
V8SetReturnValue(info, info.Holder());
return;
}
{% endif %}
{% if 'exceptionState' in function_call %}
ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kConstructionContext, "{{interface_name}}");
{% endif %}
{% if 'scriptState' in function_call %}
ScriptState* scriptState = ScriptState::From(
info.NewTarget().As<v8::Object>()->CreationContext());
{% endif %}
{{function_call | trim | indent(2)}}
}
{% endmacro %}
{##############################################################################}
{% macro generate_constructor_wrapper(constructor) %}
{% set constructor_class = v8_class + ('Constructor'
if constructor.is_named_constructor else
'') %}
v8::Local<v8::Object> wrapper = info.Holder();
wrapper = impl->AssociateWithWrapper(info.GetIsolate(), &{{constructor_class}}::wrapperTypeInfo, wrapper);
V8SetReturnValue(info, wrapper);
{% endmacro %}
{##############################################################################}
{% macro method_configuration(method) %}
{% from 'utilities.cpp.tmpl' import property_location %}
{% set method_callback =
'%s::%sMethodCallback' % (v8_class_or_partial, method.name) %}
{% set method_callback_for_main_world =
'%s::%sMethodCallbackForMainWorld' % (v8_class_or_partial, method.name)
if method.is_per_world_bindings else 'nullptr' %}
{% set property_attribute =
'static_cast<v8::PropertyAttribute>(%s)' % ' | '.join(method.property_attributes)
if method.property_attributes else 'v8::None' %}
{% set holder_check = 'V8DOMConfiguration::kDoNotCheckHolder'
if method.returns_promise else 'V8DOMConfiguration::kCheckHolder' %}
{% set access_check = 'V8DOMConfiguration::kCheckAccess'
if method.is_check_security_for_receiver else 'V8DOMConfiguration::kDoNotCheckAccess' %}
{% if method.is_per_world_bindings %}
{% set method_callback_for_main_world =
'%s::%sMethodCallbackForMainWorld' % (v8_class_or_partial, method.name) %}
{"{{method.name}}", {{method_callback_for_main_world}}, {{method.length}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, {{access_check}}, {{method.side_effect_type}}, V8DOMConfiguration::kMainWorld},
{"{{method.name}}", {{method_callback}}, {{method.length}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, {{access_check}}, {{method.side_effect_type}}, V8DOMConfiguration::kNonMainWorlds}
{%- else %}
{"{{method.name}}", {{method_callback}}, {{method.length}}, {{property_attribute}}, {{property_location(method)}}, {{holder_check}}, {{access_check}}, {{method.side_effect_type}}, V8DOMConfiguration::kAllWorlds}
{%- endif %}
{%- endmacro %}
{######################################}
{% macro install_custom_signature(method, instance_template, prototype_template, interface_template, signature) %}
const V8DOMConfiguration::MethodConfiguration {{method.name}}MethodConfiguration[] = {
{{method_configuration(method) | trim | indent(2)}}
};
for (const auto& methodConfig : {{method.name}}MethodConfiguration)
V8DOMConfiguration::InstallMethod(isolate, world, {{instance_template}}, {{prototype_template}}, {{interface_template}}, {{signature}}, methodConfig);
{%- endmacro %}
{######################################}
{% macro install_conditional_methods() %}
{% for method in conditional_methods %}
{% filter secure_context(method.overloads.secure_context_test_all
if method.overloads else
method.secure_context_test) %}
{% filter exposed(method.overloads.exposed_test_all
if method.overloads else
method.exposed_test) %}
{% filter runtime_enabled(method.overloads.runtime_enabled_all
if method.overloads else
method.runtime_enabled_feature_name) %}
const V8DOMConfiguration::MethodConfiguration {{method.name}}MethodConfiguration[] = {
{{method_configuration(method) | trim | indent(2)}}
};
for (const auto& methodConfig : {{method.name}}MethodConfiguration)
V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
{% endfilter %}{# runtime_enabled() #}
{% endfilter %}{# exposed() #}
{% endfilter %}{# secure_context() #}
{% endfor %}
{%- endmacro %}