Commit dbe083ea authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Implement the new bindings generator of IDL callbacks

Implements the new bindings generator of IDL callback functions
and IDL callback interfaces.

Bug: 839389
Change-Id: I49af9220f63ff86f1d166408cfb79c6531d71f37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2434004Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811158}
parent c1ede5bb
...@@ -16,6 +16,8 @@ bindings_core_v8_files = ...@@ -16,6 +16,8 @@ bindings_core_v8_files =
"core/v8/binding_security.cc", "core/v8/binding_security.cc",
"core/v8/binding_security.h", "core/v8/binding_security.h",
"core/v8/boxed_v8_module.h", "core/v8/boxed_v8_module.h",
"core/v8/callback_invoke_helper.cc",
"core/v8/callback_invoke_helper.h",
"core/v8/callback_promise_adapter.h", "core/v8/callback_promise_adapter.h",
"core/v8/classic_evaluation_result.h", "core/v8/classic_evaluation_result.h",
"core/v8/custom/v8_custom_xpath_ns_resolver.cc", "core/v8/custom/v8_custom_xpath_ns_resolver.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
#include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
namespace blink {
namespace bindings {
namespace {
// These tricks will no longer be necessary once Chromium allows use of
// constexpr if statement (C++17 feature).
inline bool IsCallbackConstructor(CallbackFunctionBase* callback) {
return callback->IsConstructor();
}
inline bool IsCallbackConstructor(CallbackInterfaceBase* callback) {
NOTREACHED();
return false;
}
inline bool IsCallbackObjectCallable(CallbackFunctionBase* callback) {
NOTREACHED();
return callback->CallbackObject()->IsFunction();
}
inline bool IsCallbackObjectCallable(CallbackInterfaceBase* callback) {
return callback->IsCallbackObjectCallable();
}
} // namespace
template <class CallbackBase, CallbackInvokeHelperMode mode>
bool CallbackInvokeHelper<CallbackBase, mode>::PrepareForCall(
V8ValueOrScriptWrappableAdapter callback_this) {
if (UNLIKELY(ScriptForbiddenScope::IsScriptForbidden())) {
ScriptForbiddenScope::ThrowScriptForbiddenException(
callback_->GetIsolate());
return Abort();
}
if (mode == CallbackInvokeHelperMode::kConstructorCall) {
// step 3. If ! IsConstructor(F) is false, throw a TypeError exception.
if (!IsCallbackConstructor(callback_)) {
ExceptionState exception_state(callback_->GetIsolate(),
ExceptionState::kExecutionContext,
class_like_name_, property_name_);
exception_state.ThrowTypeError(
"The provided callback is not a constructor.");
return Abort();
}
}
if (std::is_same<CallbackBase, CallbackFunctionBase>::value) {
if (mode == CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull) {
// step 4. If ! IsCallable(F) is false:
if (!callback_->CallbackObject()->IsFunction()) {
// step 4.2. Return the result of converting undefined to the callback
// function's return type.
result_ = v8::Undefined(callback_->GetIsolate());
return false;
}
}
DCHECK(callback_->CallbackObject()->IsFunction());
function_ = callback_->CallbackObject().template As<v8::Function>();
}
if (std::is_same<CallbackBase, CallbackInterfaceBase>::value) {
if (IsCallbackObjectCallable(callback_)) {
function_ = callback_->CallbackObject().template As<v8::Function>();
} else {
// step 10. If ! IsCallable(O) is false, then:
v8::Local<v8::Value> value;
if (!callback_->CallbackObject()
->Get(callback_->CallbackRelevantScriptState()->GetContext(),
V8String(callback_->GetIsolate(), property_name_))
.ToLocal(&value)) {
return Abort();
}
if (!value->IsFunction()) {
V8ThrowException::ThrowTypeError(
callback_->GetIsolate(),
ExceptionMessages::FailedToExecute(
property_name_, class_like_name_,
"The provided callback is not callable."));
return Abort();
}
function_ = value.As<v8::Function>();
}
}
if (mode == CallbackInvokeHelperMode::kConstructorCall) {
// Do nothing.
} else if (std::is_same<CallbackBase, CallbackInterfaceBase>::value &&
!IsCallbackObjectCallable(callback_)) {
// step 10.5. Set thisArg to O (overriding the provided value).
callback_this_ = callback_->CallbackObject();
} else if (callback_this.IsEmpty()) {
// step 2. If thisArg was not given, let thisArg be undefined.
callback_this_ = v8::Undefined(callback_->GetIsolate());
} else {
callback_this_ =
callback_this.V8Value(callback_->CallbackRelevantScriptState());
}
return true;
}
template <class CallbackBase, CallbackInvokeHelperMode mode>
bool CallbackInvokeHelper<CallbackBase, mode>::Call(
int argc,
v8::Local<v8::Value>* argv) {
if (mode == CallbackInvokeHelperMode::kConstructorCall) {
// step 10. Let callResult be Construct(F, esArgs).
if (!V8ScriptRunner::CallAsConstructor(
callback_->GetIsolate(), function_,
ExecutionContext::From(callback_->CallbackRelevantScriptState()),
argc, argv)
.ToLocal(&result_)) {
return Abort();
}
} else {
// step 12. Let callResult be Call(X, thisArg, esArgs).
// or
// step 11. Let callResult be Call(F, thisArg, esArgs).
if (!V8ScriptRunner::CallFunction(
function_,
ExecutionContext::From(callback_->CallbackRelevantScriptState()),
callback_this_, argc, argv, callback_->GetIsolate())
.ToLocal(&result_)) {
return Abort();
}
}
return true;
}
template class CORE_TEMPLATE_EXPORT CallbackInvokeHelper<CallbackFunctionBase>;
template class CORE_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackFunctionBase,
CallbackInvokeHelperMode::kConstructorCall>;
template class CORE_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackFunctionBase,
CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull>;
template class CORE_TEMPLATE_EXPORT CallbackInvokeHelper<CallbackInterfaceBase>;
} // namespace bindings
} // namespace blink
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CALLBACK_INVOKE_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CALLBACK_INVOKE_HELPER_H_
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_value_or_script_wrappable_adapter.h"
#include "v8/include/v8.h"
namespace blink {
class CallbackFunctionBase;
class CallbackInterfaceBase;
namespace bindings {
enum class CallbackInvokeHelperMode {
kDefault,
kConstructorCall,
kLegacyTreatNonObjectAsNull,
};
// This class helps implement the generated Blink-V8 bindings of IDL callback
// functions and IDL callback interfaces. This class implements the following
// algorithms of Web IDL.
//
// https://heycam.github.io/webidl/#call-a-user-objects-operation
// 3.11. Callback interfaces
// To call a user object's operation
//
// https://heycam.github.io/webidl/#invoke-a-callback-function
// 3.12. Invoking callback functions
// To invoke a callback function type value
//
// https://heycam.github.io/webidl/#construct-a-callback-function
// 3.12. Invoking callback functions
// To construct a callback functions type value
template <class CallbackBase,
CallbackInvokeHelperMode mode = CallbackInvokeHelperMode::kDefault>
class CallbackInvokeHelper final {
STACK_ALLOCATED();
public:
CallbackInvokeHelper(CallbackBase* callback,
const char* class_like_name,
const char* property_name)
: callback_(callback),
class_like_name_(class_like_name),
property_name_(property_name),
// step: Prepare to run script with relevant settings.
callback_relevant_context_scope_(
callback->CallbackRelevantScriptState()),
// step: Prepare to run a callback with stored settings.
backup_incumbent_scope_(
callback->IncumbentScriptState()->GetContext()) {}
~CallbackInvokeHelper() = default;
bool PrepareForCall(V8ValueOrScriptWrappableAdapter callback_this);
bool Call(int argc, v8::Local<v8::Value>* argv);
v8::Local<v8::Value> V8Result() { return result_; }
template <typename IDLReturnType, typename ReturnType>
v8::Maybe<ReturnType> Result() {
DCHECK(!aborted_);
ExceptionState exception_state(callback_->GetIsolate(),
ExceptionState::kExecutionContext,
class_like_name_, property_name_);
auto&& result = NativeValueTraits<IDLReturnType>::NativeValue(
callback_->GetIsolate(), result_, exception_state);
if (exception_state.HadException())
return v8::Nothing<ReturnType>();
return v8::Just<ReturnType>(result);
}
private:
bool Abort() {
aborted_ = true;
return false;
}
CallbackBase* callback_;
const char* class_like_name_;
const char* property_name_;
v8::Local<v8::Function> function_;
v8::Local<v8::Value> callback_this_;
v8::Local<v8::Value> result_;
bool aborted_ = false;
ScriptState::Scope callback_relevant_context_scope_;
v8::Context::BackupIncumbentScope backup_incumbent_scope_;
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackFunctionBase>;
extern template class CORE_EXTERN_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackFunctionBase,
CallbackInvokeHelperMode::kConstructorCall>;
extern template class CORE_EXTERN_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackFunctionBase,
CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull>;
extern template class CORE_EXTERN_TEMPLATE_EXPORT
CallbackInvokeHelper<CallbackInterfaceBase>;
} // namespace bindings
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CALLBACK_INVOKE_HELPER_H_
...@@ -33,6 +33,8 @@ def _setup_sys_path(): ...@@ -33,6 +33,8 @@ def _setup_sys_path():
_setup_sys_path() _setup_sys_path()
from .callback_function import generate_callback_functions
from .callback_interface import generate_callback_interfaces
from .dictionary import generate_dictionaries from .dictionary import generate_dictionaries
from .enumeration import generate_enumerations from .enumeration import generate_enumerations
from .interface import generate_interfaces from .interface import generate_interfaces
......
...@@ -56,6 +56,8 @@ def main(): ...@@ -56,6 +56,8 @@ def main():
options, tasks = parse_options() options, tasks = parse_options()
dispatch_table = { dispatch_table = {
'callback_function': bind_gen.generate_callback_functions,
'callback_interface': bind_gen.generate_callback_interfaces,
'dictionary': bind_gen.generate_dictionaries, 'dictionary': bind_gen.generate_dictionaries,
'enumeration': bind_gen.generate_enumerations, 'enumeration': bind_gen.generate_enumerations,
'interface': bind_gen.generate_interfaces, 'interface': bind_gen.generate_interfaces,
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
../../build/scripts/blinkbuild/name_style_converter.py ../../build/scripts/blinkbuild/name_style_converter.py
bind_gen/__init__.py bind_gen/__init__.py
bind_gen/blink_v8_bridge.py bind_gen/blink_v8_bridge.py
bind_gen/callback_function.py
bind_gen/callback_interface.py
bind_gen/code_node.py bind_gen/code_node.py
bind_gen/code_node_cxx.py bind_gen/code_node_cxx.py
bind_gen/codegen_accumulator.py bind_gen/codegen_accumulator.py
......
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