1#include "node_main_instance.h"
2#include <memory>
3#if HAVE_OPENSSL
4#include "crypto/crypto_util.h"
5#endif  // HAVE_OPENSSL
6#include "debug_utils-inl.h"
7#include "node_builtins.h"
8#include "node_external_reference.h"
9#include "node_internals.h"
10#include "node_options-inl.h"
11#include "node_realm.h"
12#include "node_snapshot_builder.h"
13#include "node_snapshotable.h"
14#include "node_v8_platform-inl.h"
15#include "util-inl.h"
16#if defined(LEAK_SANITIZER)
17#include <sanitizer/lsan_interface.h>
18#endif
19
20#if HAVE_INSPECTOR
21#include "inspector/worker_inspector.h"  // ParentInspectorHandle
22#endif
23
24namespace node {
25
26using v8::Context;
27using v8::HandleScope;
28using v8::Isolate;
29using v8::Local;
30using v8::Locker;
31
32NodeMainInstance::NodeMainInstance(Isolate* isolate,
33                                   uv_loop_t* event_loop,
34                                   MultiIsolatePlatform* platform,
35                                   const std::vector<std::string>& args,
36                                   const std::vector<std::string>& exec_args)
37    : args_(args),
38      exec_args_(exec_args),
39      array_buffer_allocator_(nullptr),
40      isolate_(isolate),
41      platform_(platform),
42      isolate_data_(nullptr),
43      snapshot_data_(nullptr) {
44  isolate_data_ =
45      std::make_unique<IsolateData>(isolate_, event_loop, platform, nullptr);
46
47  SetIsolateMiscHandlers(isolate_, {});
48}
49
50std::unique_ptr<NodeMainInstance> NodeMainInstance::Create(
51    Isolate* isolate,
52    uv_loop_t* event_loop,
53    MultiIsolatePlatform* platform,
54    const std::vector<std::string>& args,
55    const std::vector<std::string>& exec_args) {
56  return std::unique_ptr<NodeMainInstance>(
57      new NodeMainInstance(isolate, event_loop, platform, args, exec_args));
58}
59
60NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
61                                   uv_loop_t* event_loop,
62                                   MultiIsolatePlatform* platform,
63                                   const std::vector<std::string>& args,
64                                   const std::vector<std::string>& exec_args)
65    : args_(args),
66      exec_args_(exec_args),
67      array_buffer_allocator_(ArrayBufferAllocator::Create()),
68      isolate_(nullptr),
69      platform_(platform),
70      isolate_data_(),
71      isolate_params_(std::make_unique<Isolate::CreateParams>()),
72      snapshot_data_(snapshot_data) {
73  isolate_params_->array_buffer_allocator = array_buffer_allocator_.get();
74  if (snapshot_data != nullptr) {
75    SnapshotBuilder::InitializeIsolateParams(snapshot_data,
76                                             isolate_params_.get());
77  }
78
79  isolate_ = NewIsolate(
80      isolate_params_.get(), event_loop, platform, snapshot_data != nullptr);
81  CHECK_NOT_NULL(isolate_);
82
83  // If the indexes are not nullptr, we are not deserializing
84  isolate_data_ = std::make_unique<IsolateData>(
85      isolate_,
86      event_loop,
87      platform,
88      array_buffer_allocator_.get(),
89      snapshot_data == nullptr ? nullptr : &(snapshot_data->isolate_data_info));
90
91  isolate_data_->max_young_gen_size =
92      isolate_params_->constraints.max_young_generation_size_in_bytes();
93}
94
95void NodeMainInstance::Dispose() {
96  // This should only be called on a main instance that does not own its
97  // isolate.
98  CHECK_NULL(isolate_params_);
99  platform_->DrainTasks(isolate_);
100}
101
102NodeMainInstance::~NodeMainInstance() {
103  if (isolate_params_ == nullptr) {
104    return;
105  }
106  // This should only be done on a main instance that owns its isolate.
107  platform_->UnregisterIsolate(isolate_);
108  isolate_->Dispose();
109}
110
111int NodeMainInstance::Run() {
112  Locker locker(isolate_);
113  Isolate::Scope isolate_scope(isolate_);
114  HandleScope handle_scope(isolate_);
115
116  int exit_code = 0;
117  DeleteFnPtr<Environment, FreeEnvironment> env =
118      CreateMainEnvironment(&exit_code);
119  CHECK_NOT_NULL(env);
120
121  Context::Scope context_scope(env->context());
122  Run(&exit_code, env.get());
123  return exit_code;
124}
125
126void NodeMainInstance::Run(int* exit_code, Environment* env) {
127  if (*exit_code == 0) {
128    LoadEnvironment(env, StartExecutionCallback{});
129
130    *exit_code = SpinEventLoop(env).FromMaybe(1);
131  }
132
133#if defined(LEAK_SANITIZER)
134  __lsan_do_leak_check();
135#endif
136}
137
138DeleteFnPtr<Environment, FreeEnvironment>
139NodeMainInstance::CreateMainEnvironment(int* exit_code) {
140  *exit_code = 0;  // Reset the exit code to 0
141
142  HandleScope handle_scope(isolate_);
143
144  // TODO(addaleax): This should load a real per-Isolate option, currently
145  // this is still effectively per-process.
146  if (isolate_data_->options()->track_heap_objects) {
147    isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
148  }
149
150  Local<Context> context;
151  DeleteFnPtr<Environment, FreeEnvironment> env;
152
153  if (snapshot_data_ != nullptr) {
154    env.reset(new Environment(isolate_data_.get(),
155                              isolate_,
156                              args_,
157                              exec_args_,
158                              &(snapshot_data_->env_info),
159                              EnvironmentFlags::kDefaultFlags,
160                              {}));
161#ifdef NODE_V8_SHARED_RO_HEAP
162    // TODO(addaleax): Do this as part of creating the Environment
163    // once we store the SnapshotData* itself on IsolateData.
164    env->builtin_loader()->RefreshCodeCache(snapshot_data_->code_cache);
165#endif
166    context = Context::FromSnapshot(isolate_,
167                                    SnapshotData::kNodeMainContextIndex,
168                                    {DeserializeNodeInternalFields, env.get()})
169                  .ToLocalChecked();
170
171    CHECK(!context.IsEmpty());
172    Context::Scope context_scope(context);
173
174    CHECK(InitializeContextRuntime(context).IsJust());
175    SetIsolateErrorHandlers(isolate_, {});
176    env->InitializeMainContext(context, &(snapshot_data_->env_info));
177#if HAVE_INSPECTOR
178    env->InitializeInspector({});
179#endif
180
181#if HAVE_OPENSSL
182    crypto::InitCryptoOnce(isolate_);
183#endif  // HAVE_OPENSSL
184  } else {
185    context = NewContext(isolate_);
186    CHECK(!context.IsEmpty());
187    Context::Scope context_scope(context);
188    env.reset(
189        CreateEnvironment(isolate_data_.get(), context, args_, exec_args_));
190  }
191
192  return env;
193}
194
195}  // namespace node
196