| {% 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 %} |