11cb0ef41Sopenharmony_ci#include "main_thread_interface.h" 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci#include "env-inl.h" 41cb0ef41Sopenharmony_ci#include "simdutf.h" 51cb0ef41Sopenharmony_ci#include "v8-inspector.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <functional> 81cb0ef41Sopenharmony_ci#include <memory> 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_cinamespace node { 111cb0ef41Sopenharmony_cinamespace inspector { 121cb0ef41Sopenharmony_cinamespace { 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciusing v8_inspector::StringBuffer; 151cb0ef41Sopenharmony_ciusing v8_inspector::StringView; 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_citemplate <typename T> 181cb0ef41Sopenharmony_ciclass DeletableWrapper : public Deletable { 191cb0ef41Sopenharmony_ci public: 201cb0ef41Sopenharmony_ci explicit DeletableWrapper(std::unique_ptr<T> object) 211cb0ef41Sopenharmony_ci : object_(std::move(object)) {} 221cb0ef41Sopenharmony_ci ~DeletableWrapper() override = default; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci static T* get(MainThreadInterface* thread, int id) { 251cb0ef41Sopenharmony_ci return 261cb0ef41Sopenharmony_ci static_cast<DeletableWrapper<T>*>(thread->GetObject(id))->object_.get(); 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci private: 301cb0ef41Sopenharmony_ci std::unique_ptr<T> object_; 311cb0ef41Sopenharmony_ci}; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_citemplate <typename T> 341cb0ef41Sopenharmony_cistd::unique_ptr<Deletable> WrapInDeletable(std::unique_ptr<T> object) { 351cb0ef41Sopenharmony_ci return std::unique_ptr<DeletableWrapper<T>>( 361cb0ef41Sopenharmony_ci new DeletableWrapper<T>(std::move(object))); 371cb0ef41Sopenharmony_ci} 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_citemplate <typename Factory> 401cb0ef41Sopenharmony_ciclass CreateObjectRequest : public Request { 411cb0ef41Sopenharmony_ci public: 421cb0ef41Sopenharmony_ci CreateObjectRequest(int object_id, Factory factory) 431cb0ef41Sopenharmony_ci : object_id_(object_id), factory_(std::move(factory)) {} 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci void Call(MainThreadInterface* thread) override { 461cb0ef41Sopenharmony_ci thread->AddObject(object_id_, WrapInDeletable(factory_(thread))); 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci private: 501cb0ef41Sopenharmony_ci int object_id_; 511cb0ef41Sopenharmony_ci Factory factory_; 521cb0ef41Sopenharmony_ci}; 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_citemplate <typename Factory> 551cb0ef41Sopenharmony_cistd::unique_ptr<Request> NewCreateRequest(int object_id, Factory factory) { 561cb0ef41Sopenharmony_ci return std::unique_ptr<Request>( 571cb0ef41Sopenharmony_ci new CreateObjectRequest<Factory>(object_id, std::move(factory))); 581cb0ef41Sopenharmony_ci} 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ciclass DeleteRequest : public Request { 611cb0ef41Sopenharmony_ci public: 621cb0ef41Sopenharmony_ci explicit DeleteRequest(int object_id) : object_id_(object_id) {} 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci void Call(MainThreadInterface* thread) override { 651cb0ef41Sopenharmony_ci thread->RemoveObject(object_id_); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci private: 691cb0ef41Sopenharmony_ci int object_id_; 701cb0ef41Sopenharmony_ci}; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_citemplate <typename Target, typename Fn> 731cb0ef41Sopenharmony_ciclass CallRequest : public Request { 741cb0ef41Sopenharmony_ci public: 751cb0ef41Sopenharmony_ci CallRequest(int id, Fn fn) : id_(id), fn_(std::move(fn)) {} 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci void Call(MainThreadInterface* thread) override { 781cb0ef41Sopenharmony_ci fn_(DeletableWrapper<Target>::get(thread, id_)); 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci private: 821cb0ef41Sopenharmony_ci int id_; 831cb0ef41Sopenharmony_ci Fn fn_; 841cb0ef41Sopenharmony_ci}; 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_citemplate <typename T> 871cb0ef41Sopenharmony_ciclass AnotherThreadObjectReference { 881cb0ef41Sopenharmony_ci public: 891cb0ef41Sopenharmony_ci AnotherThreadObjectReference( 901cb0ef41Sopenharmony_ci std::shared_ptr<MainThreadHandle> thread, int object_id) 911cb0ef41Sopenharmony_ci : thread_(thread), object_id_(object_id) {} 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci template <typename Factory> 941cb0ef41Sopenharmony_ci AnotherThreadObjectReference( 951cb0ef41Sopenharmony_ci std::shared_ptr<MainThreadHandle> thread, Factory factory) 961cb0ef41Sopenharmony_ci : AnotherThreadObjectReference(thread, thread->newObjectId()) { 971cb0ef41Sopenharmony_ci thread_->Post(NewCreateRequest(object_id_, std::move(factory))); 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete; 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci ~AnotherThreadObjectReference() { 1021cb0ef41Sopenharmony_ci // Disappearing thread may cause a memory leak 1031cb0ef41Sopenharmony_ci thread_->Post(std::make_unique<DeleteRequest>(object_id_)); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci template <typename Fn> 1071cb0ef41Sopenharmony_ci void Call(Fn fn) const { 1081cb0ef41Sopenharmony_ci using Request = CallRequest<T, Fn>; 1091cb0ef41Sopenharmony_ci thread_->Post(std::unique_ptr<Request>( 1101cb0ef41Sopenharmony_ci new Request(object_id_, std::move(fn)))); 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci template <typename Arg> 1141cb0ef41Sopenharmony_ci void Call(void (T::*fn)(Arg), Arg argument) const { 1151cb0ef41Sopenharmony_ci Call(std::bind(Apply<Arg>, std::placeholders::_1, fn, std::move(argument))); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci private: 1191cb0ef41Sopenharmony_ci // This has to use non-const reference to support std::bind with non-copyable 1201cb0ef41Sopenharmony_ci // types 1211cb0ef41Sopenharmony_ci template <typename Argument> 1221cb0ef41Sopenharmony_ci static void Apply(T* target, void (T::*fn)(Argument), 1231cb0ef41Sopenharmony_ci /* NOLINT (runtime/references) */ Argument& argument) { 1241cb0ef41Sopenharmony_ci (target->*fn)(std::move(argument)); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci std::shared_ptr<MainThreadHandle> thread_; 1281cb0ef41Sopenharmony_ci const int object_id_; 1291cb0ef41Sopenharmony_ci}; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ciclass MainThreadSessionState { 1321cb0ef41Sopenharmony_ci public: 1331cb0ef41Sopenharmony_ci MainThreadSessionState(MainThreadInterface* thread, bool prevent_shutdown) 1341cb0ef41Sopenharmony_ci : thread_(thread), 1351cb0ef41Sopenharmony_ci prevent_shutdown_(prevent_shutdown) {} 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci static std::unique_ptr<MainThreadSessionState> Create( 1381cb0ef41Sopenharmony_ci MainThreadInterface* thread, bool prevent_shutdown) { 1391cb0ef41Sopenharmony_ci return std::make_unique<MainThreadSessionState>(thread, prevent_shutdown); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) { 1431cb0ef41Sopenharmony_ci Agent* agent = thread_->inspector_agent(); 1441cb0ef41Sopenharmony_ci if (agent != nullptr) 1451cb0ef41Sopenharmony_ci session_ = agent->Connect(std::move(delegate), prevent_shutdown_); 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci void Dispatch(std::unique_ptr<StringBuffer> message) { 1491cb0ef41Sopenharmony_ci session_->Dispatch(message->string()); 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci private: 1531cb0ef41Sopenharmony_ci MainThreadInterface* thread_; 1541cb0ef41Sopenharmony_ci bool prevent_shutdown_; 1551cb0ef41Sopenharmony_ci std::unique_ptr<InspectorSession> session_; 1561cb0ef41Sopenharmony_ci}; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ciclass CrossThreadInspectorSession : public InspectorSession { 1591cb0ef41Sopenharmony_ci public: 1601cb0ef41Sopenharmony_ci CrossThreadInspectorSession( 1611cb0ef41Sopenharmony_ci int id, 1621cb0ef41Sopenharmony_ci std::shared_ptr<MainThreadHandle> thread, 1631cb0ef41Sopenharmony_ci std::unique_ptr<InspectorSessionDelegate> delegate, 1641cb0ef41Sopenharmony_ci bool prevent_shutdown) 1651cb0ef41Sopenharmony_ci : state_(thread, std::bind(MainThreadSessionState::Create, 1661cb0ef41Sopenharmony_ci std::placeholders::_1, 1671cb0ef41Sopenharmony_ci prevent_shutdown)) { 1681cb0ef41Sopenharmony_ci state_.Call(&MainThreadSessionState::Connect, std::move(delegate)); 1691cb0ef41Sopenharmony_ci } 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci void Dispatch(const StringView& message) override { 1721cb0ef41Sopenharmony_ci state_.Call(&MainThreadSessionState::Dispatch, 1731cb0ef41Sopenharmony_ci StringBuffer::create(message)); 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci private: 1771cb0ef41Sopenharmony_ci AnotherThreadObjectReference<MainThreadSessionState> state_; 1781cb0ef41Sopenharmony_ci}; 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ciclass ThreadSafeDelegate : public InspectorSessionDelegate { 1811cb0ef41Sopenharmony_ci public: 1821cb0ef41Sopenharmony_ci ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread, int object_id) 1831cb0ef41Sopenharmony_ci : thread_(thread), delegate_(thread, object_id) {} 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci void SendMessageToFrontend(const v8_inspector::StringView& message) override { 1861cb0ef41Sopenharmony_ci delegate_.Call( 1871cb0ef41Sopenharmony_ci [m = StringBuffer::create(message)] 1881cb0ef41Sopenharmony_ci (InspectorSessionDelegate* delegate) { 1891cb0ef41Sopenharmony_ci delegate->SendMessageToFrontend(m->string()); 1901cb0ef41Sopenharmony_ci }); 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci private: 1941cb0ef41Sopenharmony_ci std::shared_ptr<MainThreadHandle> thread_; 1951cb0ef41Sopenharmony_ci AnotherThreadObjectReference<InspectorSessionDelegate> delegate_; 1961cb0ef41Sopenharmony_ci}; 1971cb0ef41Sopenharmony_ci} // namespace 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ciMainThreadInterface::MainThreadInterface(Agent* agent) : agent_(agent) {} 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ciMainThreadInterface::~MainThreadInterface() { 2031cb0ef41Sopenharmony_ci if (handle_) 2041cb0ef41Sopenharmony_ci handle_->Reset(); 2051cb0ef41Sopenharmony_ci} 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_civoid MainThreadInterface::Post(std::unique_ptr<Request> request) { 2081cb0ef41Sopenharmony_ci CHECK_NOT_NULL(agent_); 2091cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(requests_lock_); 2101cb0ef41Sopenharmony_ci bool needs_notify = requests_.empty(); 2111cb0ef41Sopenharmony_ci requests_.push_back(std::move(request)); 2121cb0ef41Sopenharmony_ci if (needs_notify) { 2131cb0ef41Sopenharmony_ci std::weak_ptr<MainThreadInterface> weak_self {shared_from_this()}; 2141cb0ef41Sopenharmony_ci agent_->env()->RequestInterrupt([weak_self](Environment*) { 2151cb0ef41Sopenharmony_ci if (auto iface = weak_self.lock()) iface->DispatchMessages(); 2161cb0ef41Sopenharmony_ci }); 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci incoming_message_cond_.Broadcast(scoped_lock); 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_cibool MainThreadInterface::WaitForFrontendEvent() { 2221cb0ef41Sopenharmony_ci // We allow DispatchMessages reentry as we enter the pause. This is important 2231cb0ef41Sopenharmony_ci // to support debugging the code invoked by an inspector call, such 2241cb0ef41Sopenharmony_ci // as Runtime.evaluate 2251cb0ef41Sopenharmony_ci dispatching_messages_ = false; 2261cb0ef41Sopenharmony_ci if (dispatching_message_queue_.empty()) { 2271cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(requests_lock_); 2281cb0ef41Sopenharmony_ci while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock); 2291cb0ef41Sopenharmony_ci } 2301cb0ef41Sopenharmony_ci return true; 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_civoid MainThreadInterface::DispatchMessages() { 2341cb0ef41Sopenharmony_ci if (dispatching_messages_) 2351cb0ef41Sopenharmony_ci return; 2361cb0ef41Sopenharmony_ci dispatching_messages_ = true; 2371cb0ef41Sopenharmony_ci bool had_messages = false; 2381cb0ef41Sopenharmony_ci do { 2391cb0ef41Sopenharmony_ci if (dispatching_message_queue_.empty()) { 2401cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(requests_lock_); 2411cb0ef41Sopenharmony_ci requests_.swap(dispatching_message_queue_); 2421cb0ef41Sopenharmony_ci } 2431cb0ef41Sopenharmony_ci had_messages = !dispatching_message_queue_.empty(); 2441cb0ef41Sopenharmony_ci while (!dispatching_message_queue_.empty()) { 2451cb0ef41Sopenharmony_ci MessageQueue::value_type task; 2461cb0ef41Sopenharmony_ci std::swap(dispatching_message_queue_.front(), task); 2471cb0ef41Sopenharmony_ci dispatching_message_queue_.pop_front(); 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci v8::SealHandleScope seal_handle_scope(agent_->env()->isolate()); 2501cb0ef41Sopenharmony_ci task->Call(this); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci } while (had_messages); 2531cb0ef41Sopenharmony_ci dispatching_messages_ = false; 2541cb0ef41Sopenharmony_ci} 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_cistd::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() { 2571cb0ef41Sopenharmony_ci if (handle_ == nullptr) 2581cb0ef41Sopenharmony_ci handle_ = std::make_shared<MainThreadHandle>(this); 2591cb0ef41Sopenharmony_ci return handle_; 2601cb0ef41Sopenharmony_ci} 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_civoid MainThreadInterface::AddObject(int id, 2631cb0ef41Sopenharmony_ci std::unique_ptr<Deletable> object) { 2641cb0ef41Sopenharmony_ci CHECK_NOT_NULL(object); 2651cb0ef41Sopenharmony_ci managed_objects_[id] = std::move(object); 2661cb0ef41Sopenharmony_ci} 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_civoid MainThreadInterface::RemoveObject(int id) { 2691cb0ef41Sopenharmony_ci CHECK_EQ(1, managed_objects_.erase(id)); 2701cb0ef41Sopenharmony_ci} 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ciDeletable* MainThreadInterface::GetObject(int id) { 2731cb0ef41Sopenharmony_ci Deletable* pointer = GetObjectIfExists(id); 2741cb0ef41Sopenharmony_ci // This would mean the object is requested after it was disposed, which is 2751cb0ef41Sopenharmony_ci // a coding error. 2761cb0ef41Sopenharmony_ci CHECK_NOT_NULL(pointer); 2771cb0ef41Sopenharmony_ci return pointer; 2781cb0ef41Sopenharmony_ci} 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ciDeletable* MainThreadInterface::GetObjectIfExists(int id) { 2811cb0ef41Sopenharmony_ci auto iterator = managed_objects_.find(id); 2821cb0ef41Sopenharmony_ci if (iterator == managed_objects_.end()) { 2831cb0ef41Sopenharmony_ci return nullptr; 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci return iterator->second.get(); 2861cb0ef41Sopenharmony_ci} 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_cistd::unique_ptr<StringBuffer> Utf8ToStringView(const std::string_view message) { 2891cb0ef41Sopenharmony_ci size_t expected_u16_length = 2901cb0ef41Sopenharmony_ci simdutf::utf16_length_from_utf8(message.data(), message.length()); 2911cb0ef41Sopenharmony_ci MaybeStackBuffer<char16_t> buffer(expected_u16_length); 2921cb0ef41Sopenharmony_ci size_t utf16_length = simdutf::convert_utf8_to_utf16( 2931cb0ef41Sopenharmony_ci message.data(), message.length(), buffer.out()); 2941cb0ef41Sopenharmony_ci StringView view(reinterpret_cast<uint16_t*>(buffer.out()), utf16_length); 2951cb0ef41Sopenharmony_ci return StringBuffer::create(view); 2961cb0ef41Sopenharmony_ci} 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_cistd::unique_ptr<InspectorSession> MainThreadHandle::Connect( 2991cb0ef41Sopenharmony_ci std::unique_ptr<InspectorSessionDelegate> delegate, 3001cb0ef41Sopenharmony_ci bool prevent_shutdown) { 3011cb0ef41Sopenharmony_ci return std::unique_ptr<InspectorSession>( 3021cb0ef41Sopenharmony_ci new CrossThreadInspectorSession(++next_session_id_, 3031cb0ef41Sopenharmony_ci shared_from_this(), 3041cb0ef41Sopenharmony_ci std::move(delegate), 3051cb0ef41Sopenharmony_ci prevent_shutdown)); 3061cb0ef41Sopenharmony_ci} 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_cibool MainThreadHandle::Post(std::unique_ptr<Request> request) { 3091cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(block_lock_); 3101cb0ef41Sopenharmony_ci if (!main_thread_) 3111cb0ef41Sopenharmony_ci return false; 3121cb0ef41Sopenharmony_ci main_thread_->Post(std::move(request)); 3131cb0ef41Sopenharmony_ci return true; 3141cb0ef41Sopenharmony_ci} 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_civoid MainThreadHandle::Reset() { 3171cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(block_lock_); 3181cb0ef41Sopenharmony_ci main_thread_ = nullptr; 3191cb0ef41Sopenharmony_ci} 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_cistd::unique_ptr<InspectorSessionDelegate> 3221cb0ef41Sopenharmony_ciMainThreadHandle::MakeDelegateThreadSafe( 3231cb0ef41Sopenharmony_ci std::unique_ptr<InspectorSessionDelegate> delegate) { 3241cb0ef41Sopenharmony_ci int id = newObjectId(); 3251cb0ef41Sopenharmony_ci main_thread_->AddObject(id, WrapInDeletable(std::move(delegate))); 3261cb0ef41Sopenharmony_ci return std::unique_ptr<InspectorSessionDelegate>( 3271cb0ef41Sopenharmony_ci new ThreadSafeDelegate(shared_from_this(), id)); 3281cb0ef41Sopenharmony_ci} 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_cibool MainThreadHandle::Expired() { 3311cb0ef41Sopenharmony_ci Mutex::ScopedLock scoped_lock(block_lock_); 3321cb0ef41Sopenharmony_ci return main_thread_ == nullptr; 3331cb0ef41Sopenharmony_ci} 3341cb0ef41Sopenharmony_ci} // namespace inspector 3351cb0ef41Sopenharmony_ci} // namespace node 336