/src/node/src/node_main_instance.cc
Line | Count | Source |
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_sea.h" |
13 | | #include "node_snapshot_builder.h" |
14 | | #include "node_snapshotable.h" |
15 | | #include "node_v8_platform-inl.h" |
16 | | #include "util-inl.h" |
17 | | #if defined(LEAK_SANITIZER) |
18 | | #include <sanitizer/lsan_interface.h> |
19 | | #endif |
20 | | |
21 | | #if HAVE_INSPECTOR |
22 | | #include "inspector/worker_inspector.h" // ParentInspectorHandle |
23 | | #endif |
24 | | |
25 | | namespace node { |
26 | | |
27 | | using v8::Context; |
28 | | using v8::HandleScope; |
29 | | using v8::Isolate; |
30 | | using v8::Local; |
31 | | using v8::Locker; |
32 | | |
33 | | NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data, |
34 | | uv_loop_t* event_loop, |
35 | | MultiIsolatePlatform* platform, |
36 | | const std::vector<std::string>& args, |
37 | | const std::vector<std::string>& exec_args) |
38 | 0 | : args_(args), |
39 | 0 | exec_args_(exec_args), |
40 | 0 | array_buffer_allocator_(ArrayBufferAllocator::Create()), |
41 | 0 | isolate_(nullptr), |
42 | 0 | platform_(platform), |
43 | 0 | isolate_data_(), |
44 | 0 | isolate_params_(std::make_unique<Isolate::CreateParams>()), |
45 | 0 | snapshot_data_(snapshot_data) { |
46 | 0 | isolate_params_->array_buffer_allocator = array_buffer_allocator_.get(); |
47 | |
|
48 | 0 | isolate_ = |
49 | 0 | NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data); |
50 | 0 | CHECK_NOT_NULL(isolate_); |
51 | | |
52 | | // If the indexes are not nullptr, we are not deserializing |
53 | 0 | isolate_data_.reset( |
54 | 0 | CreateIsolateData(isolate_, |
55 | 0 | event_loop, |
56 | 0 | platform, |
57 | 0 | array_buffer_allocator_.get(), |
58 | 0 | snapshot_data->AsEmbedderWrapper().get())); |
59 | |
|
60 | 0 | isolate_data_->max_young_gen_size = |
61 | 0 | isolate_params_->constraints.max_young_generation_size_in_bytes(); |
62 | 0 | } |
63 | | |
64 | 0 | NodeMainInstance::~NodeMainInstance() { |
65 | 0 | if (isolate_params_ == nullptr) { |
66 | 0 | return; |
67 | 0 | } |
68 | | |
69 | 0 | { |
70 | | #ifdef DEBUG |
71 | | // node::Environment has been disposed and no JavaScript Execution is |
72 | | // allowed at this point. |
73 | | // Create a scope to check that no JavaScript is executed in debug build |
74 | | // and proactively crash the process in the case JavaScript is being |
75 | | // executed. |
76 | | // Isolate::Dispose() must be invoked outside of this scope to avoid |
77 | | // use-after-free. |
78 | | Isolate::DisallowJavascriptExecutionScope disallow_js( |
79 | | isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); |
80 | | #endif |
81 | | // This should only be done on a main instance that owns its isolate. |
82 | | // IsolateData must be freed before UnregisterIsolate() is called. |
83 | 0 | isolate_data_.reset(); |
84 | 0 | } |
85 | 0 | platform_->DisposeIsolate(isolate_); |
86 | 0 | } |
87 | | |
88 | 0 | ExitCode NodeMainInstance::Run() { |
89 | 0 | Locker locker(isolate_); |
90 | 0 | Isolate::Scope isolate_scope(isolate_); |
91 | 0 | HandleScope handle_scope(isolate_); |
92 | |
|
93 | 0 | ExitCode exit_code = ExitCode::kNoFailure; |
94 | 0 | DeleteFnPtr<Environment, FreeEnvironment> env = |
95 | 0 | CreateMainEnvironment(&exit_code); |
96 | 0 | CHECK_NOT_NULL(env); |
97 | | |
98 | 0 | Context::Scope context_scope(env->context()); |
99 | 0 | Run(&exit_code, env.get()); |
100 | 0 | return exit_code; |
101 | 0 | } |
102 | | |
103 | 0 | void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) { |
104 | 0 | if (*exit_code == ExitCode::kNoFailure) { |
105 | 0 | if (!sea::MaybeLoadSingleExecutableApplication(env)) { |
106 | 0 | LoadEnvironment(env, StartExecutionCallback{}); |
107 | 0 | } |
108 | |
|
109 | 0 | *exit_code = |
110 | 0 | SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError); |
111 | 0 | } |
112 | |
|
113 | | #if defined(LEAK_SANITIZER) |
114 | | __lsan_do_leak_check(); |
115 | | #endif |
116 | 0 | } |
117 | | |
118 | | DeleteFnPtr<Environment, FreeEnvironment> |
119 | 0 | NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) { |
120 | 0 | *exit_code = ExitCode::kNoFailure; // Reset the exit code to 0 |
121 | |
|
122 | 0 | HandleScope handle_scope(isolate_); |
123 | | |
124 | | // TODO(addaleax): This should load a real per-Isolate option, currently |
125 | | // this is still effectively per-process. |
126 | 0 | if (isolate_data_->options()->track_heap_objects) { |
127 | 0 | isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true); |
128 | 0 | } |
129 | |
|
130 | 0 | Local<Context> context; |
131 | 0 | DeleteFnPtr<Environment, FreeEnvironment> env; |
132 | |
|
133 | 0 | if (snapshot_data_ != nullptr) { |
134 | 0 | env.reset(CreateEnvironment(isolate_data_.get(), |
135 | 0 | Local<Context>(), // read from snapshot |
136 | 0 | args_, |
137 | 0 | exec_args_)); |
138 | 0 | #if HAVE_OPENSSL |
139 | 0 | crypto::InitCryptoOnce(isolate_); |
140 | 0 | #endif // HAVE_OPENSSL |
141 | 0 | } else { |
142 | 0 | context = NewContext(isolate_); |
143 | 0 | CHECK(!context.IsEmpty()); |
144 | 0 | Context::Scope context_scope(context); |
145 | 0 | env.reset( |
146 | 0 | CreateEnvironment(isolate_data_.get(), context, args_, exec_args_)); |
147 | 0 | } |
148 | | |
149 | 0 | return env; |
150 | 0 | } |
151 | | |
152 | | } // namespace node |