1 |
|
|
// Copyright Joyent, Inc. and other Node contributors. |
2 |
|
|
// |
3 |
|
|
// Permission is hereby granted, free of charge, to any person obtaining a |
4 |
|
|
// copy of this software and associated documentation files (the |
5 |
|
|
// "Software"), to deal in the Software without restriction, including |
6 |
|
|
// without limitation the rights to use, copy, modify, merge, publish, |
7 |
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
8 |
|
|
// persons to whom the Software is furnished to do so, subject to the |
9 |
|
|
// following conditions: |
10 |
|
|
// |
11 |
|
|
// The above copyright notice and this permission notice shall be included |
12 |
|
|
// in all copies or substantial portions of the Software. |
13 |
|
|
// |
14 |
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
15 |
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
16 |
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
17 |
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
18 |
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
19 |
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
20 |
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
21 |
|
|
|
22 |
|
|
#ifndef SRC_NODE_INTERNALS_H_ |
23 |
|
|
#define SRC_NODE_INTERNALS_H_ |
24 |
|
|
|
25 |
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
26 |
|
|
|
27 |
|
|
#include "env.h" |
28 |
|
|
#include "node.h" |
29 |
|
|
#include "node_binding.h" |
30 |
|
|
#include "node_mutex.h" |
31 |
|
|
#include "tracing/trace_event.h" |
32 |
|
|
#include "util.h" |
33 |
|
|
#include "uv.h" |
34 |
|
|
#include "v8.h" |
35 |
|
|
|
36 |
|
|
#include <cstdint> |
37 |
|
|
#include <cstdlib> |
38 |
|
|
|
39 |
|
|
#include <string> |
40 |
|
|
#include <vector> |
41 |
|
|
|
42 |
|
|
struct sockaddr; |
43 |
|
|
|
44 |
|
|
namespace node { |
45 |
|
|
|
46 |
|
|
namespace native_module { |
47 |
|
|
class NativeModuleLoader; |
48 |
|
|
} |
49 |
|
|
|
50 |
|
|
namespace per_process { |
51 |
|
|
extern Mutex env_var_mutex; |
52 |
|
|
extern uint64_t node_start_time; |
53 |
|
|
} // namespace per_process |
54 |
|
|
|
55 |
|
|
// Forward declaration |
56 |
|
|
class Environment; |
57 |
|
|
|
58 |
|
|
// Convert a struct sockaddr to a { address: '1.2.3.4', port: 1234 } JS object. |
59 |
|
|
// Sets address and port properties on the info object and returns it. |
60 |
|
|
// If |info| is omitted, a new object is returned. |
61 |
|
|
v8::MaybeLocal<v8::Object> AddressToJS( |
62 |
|
|
Environment* env, |
63 |
|
|
const sockaddr* addr, |
64 |
|
|
v8::Local<v8::Object> info = v8::Local<v8::Object>()); |
65 |
|
|
|
66 |
|
|
template <typename T, int (*F)(const typename T::HandleType*, sockaddr*, int*)> |
67 |
|
4583 |
void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>& args) { |
68 |
|
|
T* wrap; |
69 |
✗✓ |
4583 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, |
70 |
|
|
args.Holder(), |
71 |
|
|
args.GetReturnValue().Set(UV_EBADF)); |
72 |
✗✓ |
4583 |
CHECK(args[0]->IsObject()); |
73 |
|
|
sockaddr_storage storage; |
74 |
|
4583 |
int addrlen = sizeof(storage); |
75 |
|
4583 |
sockaddr* const addr = reinterpret_cast<sockaddr*>(&storage); |
76 |
|
4583 |
const int err = F(&wrap->handle_, addr, &addrlen); |
77 |
✓✓ |
4583 |
if (err == 0) |
78 |
|
9160 |
AddressToJS(wrap->env(), addr, args[0].As<v8::Object>()); |
79 |
|
9166 |
args.GetReturnValue().Set(err); |
80 |
|
|
} |
81 |
|
|
|
82 |
|
|
void PrintStackTrace(v8::Isolate* isolate, v8::Local<v8::StackTrace> stack); |
83 |
|
|
void PrintCaughtException(v8::Isolate* isolate, |
84 |
|
|
v8::Local<v8::Context> context, |
85 |
|
|
const v8::TryCatch& try_catch); |
86 |
|
|
|
87 |
|
|
void ResetStdio(); // Safe to call more than once and from signal handlers. |
88 |
|
|
#ifdef __POSIX__ |
89 |
|
|
void SignalExit(int signal, siginfo_t* info, void* ucontext); |
90 |
|
|
#endif |
91 |
|
|
|
92 |
|
|
std::string GetProcessTitle(const char* default_title); |
93 |
|
|
std::string GetHumanReadableProcessName(); |
94 |
|
|
|
95 |
|
|
v8::Maybe<bool> InitializeContextRuntime(v8::Local<v8::Context> context); |
96 |
|
|
v8::Maybe<bool> InitializePrimordials(v8::Local<v8::Context> context); |
97 |
|
|
|
98 |
|
|
class NodeArrayBufferAllocator : public ArrayBufferAllocator { |
99 |
|
|
public: |
100 |
|
219934 |
inline uint32_t* zero_fill_field() { return &zero_fill_field_; } |
101 |
|
|
|
102 |
|
|
void* Allocate(size_t size) override; // Defined in src/node.cc |
103 |
|
|
void* AllocateUninitialized(size_t size) override; |
104 |
|
|
void Free(void* data, size_t size) override; |
105 |
|
|
void* Reallocate(void* data, size_t old_size, size_t size) override; |
106 |
|
|
virtual void RegisterPointer(void* data, size_t size) { |
107 |
|
|
total_mem_usage_.fetch_add(size, std::memory_order_relaxed); |
108 |
|
|
} |
109 |
|
|
virtual void UnregisterPointer(void* data, size_t size) { |
110 |
|
|
total_mem_usage_.fetch_sub(size, std::memory_order_relaxed); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
5988 |
NodeArrayBufferAllocator* GetImpl() final { return this; } |
114 |
|
522 |
inline uint64_t total_mem_usage() const { |
115 |
|
1044 |
return total_mem_usage_.load(std::memory_order_relaxed); |
116 |
|
|
} |
117 |
|
|
|
118 |
|
|
private: |
119 |
|
|
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land. |
120 |
|
|
std::atomic<size_t> total_mem_usage_ {0}; |
121 |
|
|
}; |
122 |
|
|
|
123 |
|
|
class DebuggingArrayBufferAllocator final : public NodeArrayBufferAllocator { |
124 |
|
|
public: |
125 |
|
|
~DebuggingArrayBufferAllocator() override; |
126 |
|
|
void* Allocate(size_t size) override; |
127 |
|
|
void* AllocateUninitialized(size_t size) override; |
128 |
|
|
void Free(void* data, size_t size) override; |
129 |
|
|
void* Reallocate(void* data, size_t old_size, size_t size) override; |
130 |
|
|
void RegisterPointer(void* data, size_t size) override; |
131 |
|
|
void UnregisterPointer(void* data, size_t size) override; |
132 |
|
|
|
133 |
|
|
private: |
134 |
|
|
void RegisterPointerInternal(void* data, size_t size); |
135 |
|
|
void UnregisterPointerInternal(void* data, size_t size); |
136 |
|
|
Mutex mutex_; |
137 |
|
|
std::unordered_map<void*, size_t> allocations_; |
138 |
|
|
}; |
139 |
|
|
|
140 |
|
|
namespace Buffer { |
141 |
|
|
v8::MaybeLocal<v8::Object> Copy(Environment* env, const char* data, size_t len); |
142 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, size_t size); |
143 |
|
|
// Takes ownership of |data|. |
144 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, |
145 |
|
|
char* data, |
146 |
|
|
size_t length, |
147 |
|
|
void (*callback)(char* data, void* hint), |
148 |
|
|
void* hint); |
149 |
|
|
// Takes ownership of |data|. Must allocate |data| with the current Isolate's |
150 |
|
|
// ArrayBuffer::Allocator(). |
151 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, |
152 |
|
|
char* data, |
153 |
|
|
size_t length); |
154 |
|
|
// Creates a Buffer instance over an existing ArrayBuffer. |
155 |
|
|
v8::MaybeLocal<v8::Uint8Array> New(Environment* env, |
156 |
|
|
v8::Local<v8::ArrayBuffer> ab, |
157 |
|
|
size_t byte_offset, |
158 |
|
|
size_t length); |
159 |
|
|
// Construct a Buffer from a MaybeStackBuffer (and also its subclasses like |
160 |
|
|
// Utf8Value and TwoByteValue). |
161 |
|
|
// If |buf| is invalidated, an empty MaybeLocal is returned, and nothing is |
162 |
|
|
// changed. |
163 |
|
|
// If |buf| contains actual data, this method takes ownership of |buf|'s |
164 |
|
|
// underlying buffer. However, |buf| itself can be reused even after this call, |
165 |
|
|
// but its capacity, if increased through AllocateSufficientStorage, is not |
166 |
|
|
// guaranteed to stay the same. |
167 |
|
|
template <typename T> |
168 |
|
2046 |
static v8::MaybeLocal<v8::Object> New(Environment* env, |
169 |
|
|
MaybeStackBuffer<T>* buf) { |
170 |
|
|
v8::MaybeLocal<v8::Object> ret; |
171 |
|
2046 |
char* src = reinterpret_cast<char*>(buf->out()); |
172 |
|
2046 |
const size_t len_in_bytes = buf->length() * sizeof(buf->out()[0]); |
173 |
|
|
|
174 |
|
2046 |
if (buf->IsAllocated()) |
175 |
|
313 |
ret = New(env, src, len_in_bytes); |
176 |
|
1733 |
else if (!buf->IsInvalidated()) |
177 |
|
1733 |
ret = Copy(env, src, len_in_bytes); |
178 |
|
|
|
179 |
|
2046 |
if (ret.IsEmpty()) |
180 |
|
|
return ret; |
181 |
|
|
|
182 |
|
2046 |
if (buf->IsAllocated()) |
183 |
|
313 |
buf->Release(); |
184 |
|
|
|
185 |
|
2046 |
return ret; |
186 |
|
|
} |
187 |
|
|
} // namespace Buffer |
188 |
|
|
|
189 |
|
|
v8::MaybeLocal<v8::Value> InternalMakeCallback( |
190 |
|
|
Environment* env, |
191 |
|
|
v8::Local<v8::Object> resource, |
192 |
|
|
v8::Local<v8::Object> recv, |
193 |
|
|
const v8::Local<v8::Function> callback, |
194 |
|
|
int argc, |
195 |
|
|
v8::Local<v8::Value> argv[], |
196 |
|
|
async_context asyncContext); |
197 |
|
|
|
198 |
|
|
v8::MaybeLocal<v8::Value> MakeSyncCallback(v8::Isolate* isolate, |
199 |
|
|
v8::Local<v8::Object> recv, |
200 |
|
|
v8::Local<v8::Function> callback, |
201 |
|
|
int argc, |
202 |
|
|
v8::Local<v8::Value> argv[]); |
203 |
|
|
|
204 |
|
|
class InternalCallbackScope { |
205 |
|
|
public: |
206 |
|
|
enum Flags { |
207 |
|
|
kNoFlags = 0, |
208 |
|
|
// Indicates whether 'before' and 'after' hooks should be skipped. |
209 |
|
|
kSkipAsyncHooks = 1, |
210 |
|
|
// Indicates whether nextTick and microtask queues should be skipped. |
211 |
|
|
// This should only be used when there is no call into JS in this scope. |
212 |
|
|
// (The HTTP parser also uses it for some weird backwards |
213 |
|
|
// compatibility issues, but it shouldn't.) |
214 |
|
|
kSkipTaskQueues = 2 |
215 |
|
|
}; |
216 |
|
|
InternalCallbackScope(Environment* env, |
217 |
|
|
v8::Local<v8::Object> object, |
218 |
|
|
const async_context& asyncContext, |
219 |
|
|
int flags = kNoFlags); |
220 |
|
|
// Utility that can be used by AsyncWrap classes. |
221 |
|
|
explicit InternalCallbackScope(AsyncWrap* async_wrap, int flags = 0); |
222 |
|
|
~InternalCallbackScope(); |
223 |
|
|
void Close(); |
224 |
|
|
|
225 |
|
835140 |
inline bool Failed() const { return failed_; } |
226 |
|
1329 |
inline void MarkAsFailed() { failed_ = true; } |
227 |
|
|
|
228 |
|
|
private: |
229 |
|
|
Environment* env_; |
230 |
|
|
async_context async_context_; |
231 |
|
|
v8::Local<v8::Object> object_; |
232 |
|
|
bool skip_hooks_; |
233 |
|
|
bool skip_task_queues_; |
234 |
|
|
bool failed_ = false; |
235 |
|
|
bool pushed_ids_ = false; |
236 |
|
|
bool closed_ = false; |
237 |
|
|
}; |
238 |
|
|
|
239 |
|
|
class DebugSealHandleScope { |
240 |
|
|
public: |
241 |
|
650593 |
explicit inline DebugSealHandleScope(v8::Isolate* isolate = nullptr) |
242 |
|
|
#ifdef DEBUG |
243 |
|
|
: actual_scope_(isolate != nullptr ? isolate : v8::Isolate::GetCurrent()) |
244 |
|
|
#endif |
245 |
|
650593 |
{} |
246 |
|
|
|
247 |
|
|
private: |
248 |
|
|
#ifdef DEBUG |
249 |
|
|
v8::SealHandleScope actual_scope_; |
250 |
|
|
#endif |
251 |
|
|
}; |
252 |
|
|
|
253 |
|
|
class ThreadPoolWork { |
254 |
|
|
public: |
255 |
|
7214 |
explicit inline ThreadPoolWork(Environment* env) : env_(env) { |
256 |
✗✓ |
7214 |
CHECK_NOT_NULL(env); |
257 |
|
7214 |
} |
258 |
|
14252 |
inline virtual ~ThreadPoolWork() = default; |
259 |
|
|
|
260 |
|
|
inline void ScheduleWork(); |
261 |
|
|
inline int CancelWork(); |
262 |
|
|
|
263 |
|
|
virtual void DoThreadPoolWork() = 0; |
264 |
|
|
virtual void AfterThreadPoolWork(int status) = 0; |
265 |
|
|
|
266 |
|
|
Environment* env() const { return env_; } |
267 |
|
|
|
268 |
|
|
private: |
269 |
|
|
Environment* env_; |
270 |
|
|
uv_work_t work_req_; |
271 |
|
|
}; |
272 |
|
|
|
273 |
|
|
#define TRACING_CATEGORY_NODE "node" |
274 |
|
|
#define TRACING_CATEGORY_NODE1(one) \ |
275 |
|
|
TRACING_CATEGORY_NODE "," \ |
276 |
|
|
TRACING_CATEGORY_NODE "." #one |
277 |
|
|
#define TRACING_CATEGORY_NODE2(one, two) \ |
278 |
|
|
TRACING_CATEGORY_NODE "," \ |
279 |
|
|
TRACING_CATEGORY_NODE "." #one "," \ |
280 |
|
|
TRACING_CATEGORY_NODE "." #one "." #two |
281 |
|
|
|
282 |
|
|
// Functions defined in node.cc that are exposed via the bootstrapper object |
283 |
|
|
|
284 |
|
|
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__) |
285 |
|
|
#define NODE_IMPLEMENTS_POSIX_CREDENTIALS 1 |
286 |
|
|
#endif // defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__) |
287 |
|
|
|
288 |
|
|
namespace credentials { |
289 |
|
|
bool SafeGetenv(const char* key, std::string* text, Environment* env = nullptr); |
290 |
|
|
} // namespace credentials |
291 |
|
|
|
292 |
|
|
void DefineZlibConstants(v8::Local<v8::Object> target); |
293 |
|
|
v8::Isolate* NewIsolate(v8::Isolate::CreateParams* params, |
294 |
|
|
uv_loop_t* event_loop, |
295 |
|
|
MultiIsolatePlatform* platform); |
296 |
|
|
// This overload automatically picks the right 'main_script_id' if no callback |
297 |
|
|
// was provided by the embedder. |
298 |
|
|
v8::MaybeLocal<v8::Value> StartExecution(Environment* env, |
299 |
|
|
StartExecutionCallback cb = nullptr); |
300 |
|
|
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context); |
301 |
|
|
v8::MaybeLocal<v8::Value> ExecuteBootstrapper( |
302 |
|
|
Environment* env, |
303 |
|
|
const char* id, |
304 |
|
|
std::vector<v8::Local<v8::String>>* parameters, |
305 |
|
|
std::vector<v8::Local<v8::Value>>* arguments); |
306 |
|
|
void MarkBootstrapComplete(const v8::FunctionCallbackInfo<v8::Value>& args); |
307 |
|
|
|
308 |
|
|
struct InitializationResult { |
309 |
|
|
int exit_code = 0; |
310 |
|
|
std::vector<std::string> args; |
311 |
|
|
std::vector<std::string> exec_args; |
312 |
|
|
bool early_return = false; |
313 |
|
|
}; |
314 |
|
|
|
315 |
|
|
enum InitializationSettingsFlags : uint64_t { |
316 |
|
|
kDefaultInitialization = 1 << 0, |
317 |
|
|
kInitializeV8 = 1 << 1, |
318 |
|
|
kRunPlatformInit = 1 << 2, |
319 |
|
|
kInitOpenSSL = 1 << 3 |
320 |
|
|
}; |
321 |
|
|
|
322 |
|
|
// TODO(codebytere): eventually document and expose to embedders. |
323 |
|
|
InitializationResult NODE_EXTERN_PRIVATE InitializeOncePerProcess(int argc, |
324 |
|
|
char** argv); |
325 |
|
|
InitializationResult NODE_EXTERN_PRIVATE InitializeOncePerProcess( |
326 |
|
|
int argc, |
327 |
|
|
char** argv, |
328 |
|
|
InitializationSettingsFlags flags, |
329 |
|
|
ProcessFlags::Flags process_flags = ProcessFlags::kNoFlags); |
330 |
|
|
void NODE_EXTERN_PRIVATE TearDownOncePerProcess(); |
331 |
|
|
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s); |
332 |
|
|
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s); |
333 |
|
|
void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params); |
334 |
|
|
|
335 |
|
|
#if HAVE_INSPECTOR |
336 |
|
|
namespace profiler { |
337 |
|
|
void StartProfilers(Environment* env); |
338 |
|
|
} |
339 |
|
|
#endif // HAVE_INSPECTOR |
340 |
|
|
|
341 |
|
|
#ifdef __POSIX__ |
342 |
|
|
static constexpr unsigned kMaxSignal = 32; |
343 |
|
|
#endif |
344 |
|
|
|
345 |
|
|
bool HasSignalJSHandler(int signum); |
346 |
|
|
|
347 |
|
|
#ifdef _WIN32 |
348 |
|
|
typedef SYSTEMTIME TIME_TYPE; |
349 |
|
|
#else // UNIX, OSX |
350 |
|
|
typedef struct tm TIME_TYPE; |
351 |
|
|
#endif |
352 |
|
|
|
353 |
|
|
double GetCurrentTimeInMicroseconds(); |
354 |
|
|
int WriteFileSync(const char* path, uv_buf_t buf); |
355 |
|
|
int WriteFileSync(v8::Isolate* isolate, |
356 |
|
|
const char* path, |
357 |
|
|
v8::Local<v8::String> string); |
358 |
|
|
|
359 |
|
|
class DiagnosticFilename { |
360 |
|
|
public: |
361 |
|
|
static void LocalTime(TIME_TYPE* tm_struct); |
362 |
|
|
|
363 |
|
|
inline DiagnosticFilename(Environment* env, |
364 |
|
|
const char* prefix, |
365 |
|
|
const char* ext); |
366 |
|
|
|
367 |
|
|
inline DiagnosticFilename(uint64_t thread_id, |
368 |
|
|
const char* prefix, |
369 |
|
|
const char* ext); |
370 |
|
|
|
371 |
|
|
inline const char* operator*() const; |
372 |
|
|
|
373 |
|
|
private: |
374 |
|
|
static std::string MakeFilename( |
375 |
|
|
uint64_t thread_id, |
376 |
|
|
const char* prefix, |
377 |
|
|
const char* ext); |
378 |
|
|
|
379 |
|
|
std::string filename_; |
380 |
|
|
}; |
381 |
|
|
|
382 |
|
|
namespace heap { |
383 |
|
|
v8::Maybe<void> WriteSnapshot(Environment* env, const char* filename); |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
namespace heap { |
387 |
|
|
|
388 |
|
|
void DeleteHeapSnapshot(const v8::HeapSnapshot* snapshot); |
389 |
|
|
using HeapSnapshotPointer = |
390 |
|
|
DeleteFnPtr<const v8::HeapSnapshot, DeleteHeapSnapshot>; |
391 |
|
|
|
392 |
|
|
BaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream( |
393 |
|
|
Environment* env, HeapSnapshotPointer&& snapshot); |
394 |
|
|
} // namespace heap |
395 |
|
|
|
396 |
|
|
namespace fs { |
397 |
|
|
std::string Basename(const std::string& str, const std::string& extension); |
398 |
|
|
} // namespace fs |
399 |
|
|
|
400 |
|
|
node_module napi_module_to_node_module(const napi_module* mod); |
401 |
|
|
|
402 |
|
|
} // namespace node |
403 |
|
|
|
404 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
405 |
|
|
|
406 |
|
|
#endif // SRC_NODE_INTERNALS_H_ |