diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.cc b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.cc index 75571d06b659aab105c74ad5525dc316e084af5f..7869eb81b2057c3ea18c19cd3108b29a4b0df488 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.cc +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.cc @@ -16,7 +16,29 @@ namespace dart { IMPLEMENT_WRAPPERTYPEINFO(zircon, Handle); -Handle::Handle(zx_handle_t handle) : handle_(handle) {} +Handle::Handle(zx_handle_t handle) : handle_(handle) { + tonic::DartState* state = tonic::DartState::Current(); + FML_DCHECK(state); + Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); + FML_DCHECK(!tonic::LogIfError(zircon_lib)); + + Dart_Handle on_wait_completer_type = + Dart_GetClass(zircon_lib, ToDart("_OnWaitCompleteClosure")); + FML_DCHECK(!tonic::LogIfError(on_wait_completer_type)); + on_wait_completer_type_.Set(state, on_wait_completer_type); + + Dart_Handle async_lib = Dart_LookupLibrary(ToDart("dart:async")); + FML_DCHECK(!tonic::LogIfError(async_lib)); + async_lib_.Set(state, async_lib); + + Dart_Handle closure_string = ToDart("_closure"); + FML_DCHECK(!tonic::LogIfError(closure_string)); + closure_string_.Set(state, closure_string); + + Dart_Handle schedule_microtask_string = ToDart("scheduleMicrotask"); + FML_DCHECK(!tonic::LogIfError(schedule_microtask_string)); + schedule_microtask_string_.Set(state, schedule_microtask_string); +} Handle::~Handle() { if (is_valid()) { @@ -93,6 +115,36 @@ Dart_Handle Handle::Duplicate(uint32_t rights) { return ToDart(Create(out_handle)); } +void Handle::ScheduleCallback(tonic::DartPersistentValue callback, + zx_status_t status, + const zx_packet_signal_t* signal) { + auto state = callback.dart_state().lock(); + FML_DCHECK(state); + tonic::DartState::Scope scope(state); + + // Make a new _OnWaitCompleteClosure(callback, status, signal->observed). + FML_DCHECK(!callback.is_empty()); + std::vector constructor_args{callback.Release(), ToDart(status), + ToDart(signal->observed)}; + Dart_Handle on_wait_complete_closure = + Dart_New(on_wait_completer_type_.Get(), Dart_Null(), + constructor_args.size(), constructor_args.data()); + FML_DCHECK(!tonic::LogIfError(on_wait_complete_closure)); + + // The _callback field contains the thunk: + // () => callback(status, signal->observed) + Dart_Handle closure = + Dart_GetField(on_wait_complete_closure, closure_string_.Get()); + FML_DCHECK(!tonic::LogIfError(closure)); + + // Put the thunk on the microtask queue by calling scheduleMicrotask(). + std::vector sm_args{closure}; + Dart_Handle sm_result = + Dart_Invoke(async_lib_.Get(), schedule_microtask_string_.Get(), + sm_args.size(), sm_args.data()); + FML_DCHECK(!tonic::LogIfError(sm_result)); +} + // clang-format: off #define FOR_EACH_STATIC_BINDING(V) V(Handle, CreateInvalid) diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.h b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.h index 945a567d3b225e67756b6102c9bc447b9e7f57fb..cd2b4c7740b1cc7c19281f613fd5d6f888e4bcbd 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.h +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.h @@ -60,6 +60,10 @@ class Handle : public fml::RefCountedThreadSafe, Dart_Handle Duplicate(uint32_t rights); + void ScheduleCallback(tonic::DartPersistentValue callback, + zx_status_t status, + const zx_packet_signal_t* signal); + private: explicit Handle(zx_handle_t handle); @@ -70,6 +74,13 @@ class Handle : public fml::RefCountedThreadSafe, zx_handle_t handle_; std::vector waiters_; + + // Some cached persistent handles to make running handle wait completers + // faster. + tonic::DartPersistentValue async_lib_; + tonic::DartPersistentValue closure_string_; + tonic::DartPersistentValue on_wait_completer_type_; + tonic::DartPersistentValue schedule_microtask_string_; }; } // namespace dart diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.cc b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.cc index 724c7f596750a877bf940b70f9a9d2df4a61df47..8c1be48e178893fa587c704141c6b200fffac6da 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.cc +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.cc @@ -81,21 +81,11 @@ void HandleWaiter::OnWaitComplete(async_dispatcher_t* dispatcher, // Remove this waiter from the handle. handle_->ReleaseWaiter(this); + // Schedule the callback on the microtask queue. + handle_->ScheduleCallback(std::move(callback_), status, signal); + // Clear handle_. handle_ = nullptr; - - auto state = callback_.dart_state().lock(); - FML_DCHECK(state); - DartState::Scope scope(state); - - std::vector args{ToDart(status), ToDart(signal->observed)}; - FML_DCHECK(!callback_.is_empty()); - Dart_Handle result = - Dart_InvokeClosure(callback_.Release(), args.size(), args.data()); - // If there was an uncaught error from the callback propagate it out. - if (tonic::LogIfError(result)) { - state->message_handler().UnhandledError(result); - } } } // namespace dart