Skip to content

Commit

Permalink
TaskAttribution: Refactor V8 interface (yield API 2/n)
Browse files Browse the repository at this point in the history
Refactor the interface between V8 and task attribution to support
inheritance in the yield() API. In a future dependent CL, the task
state object will include self.scheduler state and be set for
postTask() tasks.

In this CL:
 - The wrapper class is renamed ScriptWrappableTaskState and is
   composed of a task attribution ID rather than being one
 - Attribution scopes store the previous object rather than ID.
   Note: there's a slight perf improvement here since we don't need to
   create a new object when restoring the previous state.
 - The integration with V8 continuation preserved embedder data is
   refactored into ScriptWrappableTaskState static methods, which will
   also be used by DOMScheduler and related classes. Rather than making
   the adapter virtual for testing, the relevant methods are virtual,
   with the default delegating to the new static methods.

Bug: 979020
Change-Id: I9e9bf2e239e79ac0fd7c416667b44143c34c15a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4117451
Commit-Queue: Scott Haseley <shaseley@chromium.org>
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1105848}
  • Loading branch information
shaseley authored and Chromium LUCI CQ committed Feb 15, 2023
1 parent 4a1424d commit 49c348a
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 164 deletions.
4 changes: 2 additions & 2 deletions third_party/blink/renderer/bindings/generated_in_modules.gni
Original file line number Diff line number Diff line change
Expand Up @@ -2313,8 +2313,8 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_screen_orientation.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_processor_node.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_processor_node.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_state.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_state.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor_error_event.cc",
Expand Down
2 changes: 1 addition & 1 deletion third_party/blink/renderer/bindings/idl_in_modules.gni
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/scheduler/scheduler.idl",
"//third_party/blink/renderer/modules/scheduler/scheduler_post_task_callback.idl",
"//third_party/blink/renderer/modules/scheduler/scheduler_post_task_options.idl",
"//third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.idl",
"//third_party/blink/renderer/modules/scheduler/script_wrappable_task_state.idl",
"//third_party/blink/renderer/modules/scheduler/task_controller.idl",
"//third_party/blink/renderer/modules/scheduler/task_controller_init.idl",
"//third_party/blink/renderer/modules/scheduler/task_priority_change_event.idl",
Expand Down
3 changes: 2 additions & 1 deletion third_party/blink/renderer/modules/scheduler/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ blink_modules_sources("scheduler") {
"dom_task_controller.h",
"dom_task_signal.cc",
"dom_task_signal.h",
"script_wrappable_task_attribution_id.h",
"script_wrappable_task_state.cc",
"script_wrappable_task_state.h",
"task_attribution_tracker_impl.cc",
"task_attribution_tracker_impl.h",
"task_priority_change_event.cc",
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2023 The Chromium Authors
// 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/modules/scheduler/script_wrappable_task_state.h"

#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/modules/scheduler/script_wrappable_task_state.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"

namespace blink {

ScriptWrappableTaskState::ScriptWrappableTaskState(
scheduler::TaskAttributionId id)
: task_attribution_id_(id) {}

// static
ScriptWrappableTaskState* ScriptWrappableTaskState::GetCurrent(
ScriptState* script_state) {
DCHECK(script_state);
if (!script_state->ContextIsValid()) {
return nullptr;
}

ScriptState::Scope scope(script_state);
v8::Local<v8::Context> context = script_state->GetContext();
DCHECK(!context.IsEmpty());
v8::Local<v8::Value> v8_value =
context->GetContinuationPreservedEmbedderData();
if (v8_value->IsNullOrUndefined()) {
return nullptr;
}
v8::Isolate* isolate = script_state->GetIsolate();
DCHECK(isolate);
if (isolate->IsExecutionTerminating()) {
return nullptr;
}
// If not empty, the value must be a `ScriptWrappableTaskState`.
NonThrowableExceptionState exception_state;
ScriptWrappableTaskState* task_state =
NativeValueTraits<ScriptWrappableTaskState>::NativeValue(
isolate, v8_value, exception_state);
DCHECK(task_state);
return task_state;
}

// static
void ScriptWrappableTaskState::SetCurrent(
ScriptState* script_state,
ScriptWrappableTaskState* task_state) {
DCHECK(script_state);
if (!script_state->ContextIsValid()) {
return;
}
CHECK(!ScriptForbiddenScope::IsScriptForbidden());
ScriptState::Scope scope(script_state);
v8::Isolate* isolate = script_state->GetIsolate();
DCHECK(isolate);
if (isolate->IsExecutionTerminating()) {
return;
}
v8::Local<v8::Context> context = script_state->GetContext();
DCHECK(!context.IsEmpty());

if (task_state) {
context->SetContinuationPreservedEmbedderData(
ToV8Traits<ScriptWrappableTaskState>::ToV8(script_state, task_state)
.ToLocalChecked());
} else {
context->SetContinuationPreservedEmbedderData(v8::Local<v8::Value>());
}
}

} // namespace blink
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2023 The Chromium Authors
// 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_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_STATE_H_

#include "third_party/blink/public/common/scheduler/task_attribution_id.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/member.h"

namespace blink {

// The scheduler uses `ScriptWrappableTaskState` objects to store continuation
// preserved embedder data, which is data stored on V8 promise reactions at
// creation time and restored at run time.
class MODULES_EXPORT ScriptWrappableTaskState final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();

public:
// Get the `ScriptWrappableTaskState` currently stored as continuation
// preserved embedder data.
static ScriptWrappableTaskState* GetCurrent(ScriptState*);

// Set the given `ScriptWrappableTaskState` as the current continuation
// preserved embedder data.
static void SetCurrent(ScriptState*, ScriptWrappableTaskState*);

explicit ScriptWrappableTaskState(scheduler::TaskAttributionId id);

scheduler::TaskAttributionId GetTaskAttributionId() const {
return task_attribution_id_;
}

private:
const scheduler::TaskAttributionId task_attribution_id_;
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SCHEDULER_SCRIPT_WRAPPABLE_TASK_STATE_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This interface is not web-exposed. It is used to generate a ScriptWrappable
// object used to store task state as continuation embedder data.
interface ScriptWrappableTaskState {
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@

#include "base/trace_event/trace_event.h"
#include "base/trace_event/typed_macros.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_script_wrappable_task_attribution_id.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/scheduler/script_wrappable_task_attribution_id.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
#include "third_party/blink/renderer/modules/scheduler/script_wrappable_task_state.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"

namespace blink::scheduler {
Expand Down Expand Up @@ -52,19 +47,16 @@ int64_t TaskAttributionIdToInt(absl::optional<TaskAttributionId> id) {

} // namespace

TaskAttributionTrackerImpl::TaskAttributionTrackerImpl()
: next_task_id_(0), v8_adapter_(std::make_unique<V8Adapter>()) {}
TaskAttributionTrackerImpl::TaskAttributionTrackerImpl() : next_task_id_(0) {}

absl::optional<TaskAttributionId>
TaskAttributionTrackerImpl::RunningTaskAttributionId(
ScriptState* script_state) const {
DCHECK(v8_adapter_);
absl::optional<TaskAttributionId> task_id =
v8_adapter_->GetValue(script_state);

ScriptWrappableTaskState* task_state =
GetCurrentTaskContinuationData(script_state);
// V8 embedder state may have no value in the case of a JSPromise that wasn't
// yet resolved.
return task_id ? task_id : running_task_id_;
return task_state ? task_state->GetTaskAttributionId() : running_task_id_;
}

void TaskAttributionTrackerImpl::InsertTaskAttributionIdPair(
Expand Down Expand Up @@ -158,9 +150,8 @@ TaskAttributionTrackerImpl::CreateTaskScope(
TaskScopeType type) {
absl::optional<TaskAttributionId> running_task_id_to_be_restored =
running_task_id_;
DCHECK(v8_adapter_);
absl::optional<TaskAttributionId> continuation_task_id_to_be_restored =
v8_adapter_->GetValue(script_state);
ScriptWrappableTaskState* continuation_task_state_to_be_restored =
GetCurrentTaskContinuationData(script_state);

next_task_id_ = next_task_id_.NextId();
running_task_id_ = next_task_id_;
Expand All @@ -173,25 +164,34 @@ TaskAttributionTrackerImpl::CreateTaskScope(
}
}

SaveTaskIdStateInV8(script_state, next_task_id_);
SetCurrentTaskContinuationData(
script_state,
MakeGarbageCollected<ScriptWrappableTaskState>(next_task_id_));

return std::make_unique<TaskScopeImpl>(
script_state, this, next_task_id_, running_task_id_to_be_restored,
continuation_task_id_to_be_restored, type, parent_task_id);
continuation_task_state_to_be_restored, type, parent_task_id);
}

void TaskAttributionTrackerImpl::TaskScopeCompleted(
const TaskScopeImpl& task_scope) {
DCHECK(running_task_id_ == task_scope.GetTaskId());
running_task_id_ = task_scope.RunningTaskIdToBeRestored();
SaveTaskIdStateInV8(task_scope.GetScriptState(),
task_scope.ContinuationTaskIdToBeRestored());
SetCurrentTaskContinuationData(
task_scope.GetScriptState(),
task_scope.ContinuationTaskStateToBeRestored());
}

void TaskAttributionTrackerImpl::SaveTaskIdStateInV8(
void TaskAttributionTrackerImpl::SetCurrentTaskContinuationData(
ScriptState* script_state,
absl::optional<TaskAttributionId> task_id) {
DCHECK(v8_adapter_);
v8_adapter_->SetValue(script_state, task_id);
ScriptWrappableTaskState* task_state) {
ScriptWrappableTaskState::SetCurrent(script_state, task_state);
}

ScriptWrappableTaskState*
TaskAttributionTrackerImpl::GetCurrentTaskContinuationData(
ScriptState* script_state) const {
return ScriptWrappableTaskState::GetCurrent(script_state);
}

// TaskScope's implementation
Expand All @@ -201,13 +201,13 @@ TaskAttributionTrackerImpl::TaskScopeImpl::TaskScopeImpl(
TaskAttributionTrackerImpl* task_tracker,
TaskAttributionId scope_task_id,
absl::optional<TaskAttributionId> running_task_id,
absl::optional<TaskAttributionId> continuation_task_id,
ScriptWrappableTaskState* continuation_task_state,
TaskScopeType type,
absl::optional<TaskAttributionId> parent_task_id)
: task_tracker_(task_tracker),
scope_task_id_(scope_task_id),
running_task_id_to_be_restored_(running_task_id),
continuation_task_id_to_be_restored_(continuation_task_id),
continuation_state_to_be_restored_(continuation_task_state),
script_state_(script_state) {
TRACE_EVENT_BEGIN(
"scheduler", "BlinkTaskScope", [&](perfetto::EventContext ctx) {
Expand All @@ -217,8 +217,11 @@ TaskAttributionTrackerImpl::TaskScopeImpl::TaskScopeImpl(
data->set_scope_task_id(scope_task_id_.value());
data->set_running_task_id_to_be_restored(
TaskAttributionIdToInt(running_task_id_to_be_restored_));
data->set_continuation_task_id_to_be_restored(
TaskAttributionIdToInt(continuation_task_id_to_be_restored_));
data->set_continuation_task_id_to_be_restored(TaskAttributionIdToInt(
continuation_state_to_be_restored_
? absl::make_optional(continuation_state_to_be_restored_
->GetTaskAttributionId())
: absl::nullopt));
data->set_parent_task_id(TaskAttributionIdToInt(parent_task_id));
});
}
Expand All @@ -228,64 +231,4 @@ TaskAttributionTrackerImpl::TaskScopeImpl::~TaskScopeImpl() {
TRACE_EVENT_END("scheduler");
}

// V8Adapter's implementation
//////////////////////////////////////
absl::optional<TaskAttributionId>
TaskAttributionTrackerImpl::V8Adapter::GetValue(ScriptState* script_state) {
DCHECK(script_state);
if (!script_state->ContextIsValid()) {
return absl::nullopt;
}

ScriptState::Scope scope(script_state);
v8::Local<v8::Context> context = script_state->GetContext();
DCHECK(!context.IsEmpty());
v8::Local<v8::Value> v8_value =
context->GetContinuationPreservedEmbedderData();
if (v8_value->IsNullOrUndefined()) {
return absl::nullopt;
}
v8::Isolate* isolate = script_state->GetIsolate();
DCHECK(isolate);
if (isolate->IsExecutionTerminating()) {
return absl::nullopt;
}
// If not empty, the value must be a ScriptWrappableTaskAttributionId.
NonThrowableExceptionState exception_state;
ScriptWrappableTaskAttributionId* script_wrappable_task_id =
NativeValueTraits<ScriptWrappableTaskAttributionId>::NativeValue(
isolate, v8_value, exception_state);
DCHECK(script_wrappable_task_id);
return *script_wrappable_task_id;
}

void TaskAttributionTrackerImpl::V8Adapter::SetValue(
ScriptState* script_state,
absl::optional<TaskAttributionId> task_id) {
DCHECK(script_state);
if (!script_state->ContextIsValid()) {
return;
}
CHECK(!ScriptForbiddenScope::IsScriptForbidden());
ScriptState::Scope scope(script_state);
v8::Isolate* isolate = script_state->GetIsolate();
DCHECK(isolate);
if (isolate->IsExecutionTerminating()) {
return;
}
v8::Local<v8::Context> context = script_state->GetContext();
DCHECK(!context.IsEmpty());

if (task_id) {
ScriptWrappableTaskAttributionId* script_wrappable_task_id =
MakeGarbageCollected<ScriptWrappableTaskAttributionId>(task_id.value());
context->SetContinuationPreservedEmbedderData(
ToV8Traits<ScriptWrappableTaskAttributionId>::ToV8(
script_state, script_wrappable_task_id)
.ToLocalChecked());
} else {
context->SetContinuationPreservedEmbedderData(v8::Local<v8::Value>());
}
}

} // namespace blink::scheduler

0 comments on commit 49c348a

Please sign in to comment.