11cb0ef41Sopenharmony_ci#include "node.h"
21cb0ef41Sopenharmony_ci#include "env-inl.h"
31cb0ef41Sopenharmony_ci#include "debug_utils-inl.h"
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciusing v8::Context;
61cb0ef41Sopenharmony_ciusing v8::Function;
71cb0ef41Sopenharmony_ciusing v8::Global;
81cb0ef41Sopenharmony_ciusing v8::HandleScope;
91cb0ef41Sopenharmony_ciusing v8::Isolate;
101cb0ef41Sopenharmony_ciusing v8::Local;
111cb0ef41Sopenharmony_ciusing v8::Locker;
121cb0ef41Sopenharmony_ciusing v8::Maybe;
131cb0ef41Sopenharmony_ciusing v8::Nothing;
141cb0ef41Sopenharmony_ciusing v8::SealHandleScope;
151cb0ef41Sopenharmony_ciusing v8::TryCatch;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cinamespace node {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciMaybe<int> SpinEventLoop(Environment* env) {
201cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(env);
211cb0ef41Sopenharmony_ci  MultiIsolatePlatform* platform = GetMultiIsolatePlatform(env);
221cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(platform);
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
251cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
261cb0ef41Sopenharmony_ci  Context::Scope context_scope(env->context());
271cb0ef41Sopenharmony_ci  SealHandleScope seal(isolate);
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  if (env->is_stopping()) return Nothing<int>();
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  env->set_trace_sync_io(env->options()->trace_sync_io);
321cb0ef41Sopenharmony_ci  {
331cb0ef41Sopenharmony_ci    bool more;
341cb0ef41Sopenharmony_ci    env->performance_state()->Mark(
351cb0ef41Sopenharmony_ci        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
361cb0ef41Sopenharmony_ci    do {
371cb0ef41Sopenharmony_ci      if (env->is_stopping()) break;
381cb0ef41Sopenharmony_ci      uv_run(env->event_loop(), UV_RUN_DEFAULT);
391cb0ef41Sopenharmony_ci      if (env->is_stopping()) break;
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci      platform->DrainTasks(isolate);
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci      more = uv_loop_alive(env->event_loop());
441cb0ef41Sopenharmony_ci      if (more && !env->is_stopping()) continue;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci      if (EmitProcessBeforeExit(env).IsNothing())
471cb0ef41Sopenharmony_ci        break;
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci      {
501cb0ef41Sopenharmony_ci        HandleScope handle_scope(isolate);
511cb0ef41Sopenharmony_ci        if (env->RunSnapshotSerializeCallback().IsEmpty()) {
521cb0ef41Sopenharmony_ci          break;
531cb0ef41Sopenharmony_ci        }
541cb0ef41Sopenharmony_ci      }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci      // Emit `beforeExit` if the loop became alive either after emitting
571cb0ef41Sopenharmony_ci      // event, or after running some callbacks.
581cb0ef41Sopenharmony_ci      more = uv_loop_alive(env->event_loop());
591cb0ef41Sopenharmony_ci    } while (more == true && !env->is_stopping());
601cb0ef41Sopenharmony_ci    env->performance_state()->Mark(
611cb0ef41Sopenharmony_ci        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
621cb0ef41Sopenharmony_ci  }
631cb0ef41Sopenharmony_ci  if (env->is_stopping()) return Nothing<int>();
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  env->set_trace_sync_io(false);
661cb0ef41Sopenharmony_ci  // Clear the serialize callback even though the JS-land queue should
671cb0ef41Sopenharmony_ci  // be empty this point so that the deserialized instance won't
681cb0ef41Sopenharmony_ci  // attempt to call into JS again.
691cb0ef41Sopenharmony_ci  env->set_snapshot_serialize_callback(Local<Function>());
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  env->PrintInfoForSnapshotIfDebug();
721cb0ef41Sopenharmony_ci  env->ForEachRealm([](Realm* realm) { realm->VerifyNoStrongBaseObjects(); });
731cb0ef41Sopenharmony_ci  return EmitProcessExit(env);
741cb0ef41Sopenharmony_ci}
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_cistruct CommonEnvironmentSetup::Impl {
771cb0ef41Sopenharmony_ci  MultiIsolatePlatform* platform = nullptr;
781cb0ef41Sopenharmony_ci  uv_loop_t loop;
791cb0ef41Sopenharmony_ci  std::shared_ptr<ArrayBufferAllocator> allocator;
801cb0ef41Sopenharmony_ci  Isolate* isolate = nullptr;
811cb0ef41Sopenharmony_ci  DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data;
821cb0ef41Sopenharmony_ci  DeleteFnPtr<Environment, FreeEnvironment> env;
831cb0ef41Sopenharmony_ci  Global<Context> context;
841cb0ef41Sopenharmony_ci};
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ciCommonEnvironmentSetup::CommonEnvironmentSetup(
871cb0ef41Sopenharmony_ci    MultiIsolatePlatform* platform,
881cb0ef41Sopenharmony_ci    std::vector<std::string>* errors,
891cb0ef41Sopenharmony_ci    std::function<Environment*(const CommonEnvironmentSetup*)> make_env)
901cb0ef41Sopenharmony_ci  : impl_(new Impl()) {
911cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(platform);
921cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(errors);
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  impl_->platform = platform;
951cb0ef41Sopenharmony_ci  uv_loop_t* loop = &impl_->loop;
961cb0ef41Sopenharmony_ci  // Use `data` to tell the destructor whether the loop was initialized or not.
971cb0ef41Sopenharmony_ci  loop->data = nullptr;
981cb0ef41Sopenharmony_ci  int ret = uv_loop_init(loop);
991cb0ef41Sopenharmony_ci  if (ret != 0) {
1001cb0ef41Sopenharmony_ci    errors->push_back(
1011cb0ef41Sopenharmony_ci        SPrintF("Failed to initialize loop: %s", uv_err_name(ret)));
1021cb0ef41Sopenharmony_ci    return;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci  loop->data = this;
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  impl_->allocator = ArrayBufferAllocator::Create();
1071cb0ef41Sopenharmony_ci  impl_->isolate = NewIsolate(impl_->allocator, &impl_->loop, platform);
1081cb0ef41Sopenharmony_ci  Isolate* isolate = impl_->isolate;
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  {
1111cb0ef41Sopenharmony_ci    Locker locker(isolate);
1121cb0ef41Sopenharmony_ci    Isolate::Scope isolate_scope(isolate);
1131cb0ef41Sopenharmony_ci    HandleScope handle_scope(isolate);
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    TryCatch bootstrapCatch(isolate);
1161cb0ef41Sopenharmony_ci    auto print_Exception = OnScopeLeave([&]() {
1171cb0ef41Sopenharmony_ci      if (bootstrapCatch.HasCaught()) {
1181cb0ef41Sopenharmony_ci        errors->push_back(FormatCaughtException(
1191cb0ef41Sopenharmony_ci            isolate, isolate->GetCurrentContext(), bootstrapCatch));
1201cb0ef41Sopenharmony_ci      }
1211cb0ef41Sopenharmony_ci    });
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci    impl_->isolate_data.reset(CreateIsolateData(
1241cb0ef41Sopenharmony_ci        isolate, loop, platform, impl_->allocator.get()));
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci    Local<Context> context = NewContext(isolate);
1271cb0ef41Sopenharmony_ci    impl_->context.Reset(isolate, context);
1281cb0ef41Sopenharmony_ci    if (context.IsEmpty()) {
1291cb0ef41Sopenharmony_ci      errors->push_back("Failed to initialize V8 Context");
1301cb0ef41Sopenharmony_ci      return;
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci    Context::Scope context_scope(context);
1341cb0ef41Sopenharmony_ci    impl_->env.reset(make_env(this));
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci}
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ciCommonEnvironmentSetup::~CommonEnvironmentSetup() {
1391cb0ef41Sopenharmony_ci  if (impl_->isolate != nullptr) {
1401cb0ef41Sopenharmony_ci    Isolate* isolate = impl_->isolate;
1411cb0ef41Sopenharmony_ci    {
1421cb0ef41Sopenharmony_ci      Locker locker(isolate);
1431cb0ef41Sopenharmony_ci      Isolate::Scope isolate_scope(isolate);
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci      impl_->context.Reset();
1461cb0ef41Sopenharmony_ci      impl_->env.reset();
1471cb0ef41Sopenharmony_ci      impl_->isolate_data.reset();
1481cb0ef41Sopenharmony_ci    }
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci    bool platform_finished = false;
1511cb0ef41Sopenharmony_ci    impl_->platform->AddIsolateFinishedCallback(isolate, [](void* data) {
1521cb0ef41Sopenharmony_ci      *static_cast<bool*>(data) = true;
1531cb0ef41Sopenharmony_ci    }, &platform_finished);
1541cb0ef41Sopenharmony_ci    impl_->platform->UnregisterIsolate(isolate);
1551cb0ef41Sopenharmony_ci    isolate->Dispose();
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    // Wait until the platform has cleaned up all relevant resources.
1581cb0ef41Sopenharmony_ci    while (!platform_finished)
1591cb0ef41Sopenharmony_ci      uv_run(&impl_->loop, UV_RUN_ONCE);
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  if (impl_->isolate || impl_->loop.data != nullptr)
1631cb0ef41Sopenharmony_ci    CheckedUvLoopClose(&impl_->loop);
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci  delete impl_;
1661cb0ef41Sopenharmony_ci}
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ciuv_loop_t* CommonEnvironmentSetup::event_loop() const {
1701cb0ef41Sopenharmony_ci  return &impl_->loop;
1711cb0ef41Sopenharmony_ci}
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_cistd::shared_ptr<ArrayBufferAllocator>
1741cb0ef41Sopenharmony_ciCommonEnvironmentSetup::array_buffer_allocator() const {
1751cb0ef41Sopenharmony_ci  return impl_->allocator;
1761cb0ef41Sopenharmony_ci}
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ciIsolate* CommonEnvironmentSetup::isolate() const {
1791cb0ef41Sopenharmony_ci  return impl_->isolate;
1801cb0ef41Sopenharmony_ci}
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ciIsolateData* CommonEnvironmentSetup::isolate_data() const {
1831cb0ef41Sopenharmony_ci  return impl_->isolate_data.get();
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ciEnvironment* CommonEnvironmentSetup::env() const {
1871cb0ef41Sopenharmony_ci  return impl_->env.get();
1881cb0ef41Sopenharmony_ci}
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_civ8::Local<v8::Context> CommonEnvironmentSetup::context() const {
1911cb0ef41Sopenharmony_ci  return impl_->context.Get(impl_->isolate);
1921cb0ef41Sopenharmony_ci}
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci}  // namespace node
195