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 builtins { |
47 |
|
|
class BuiltinLoader; |
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 |
|
4455 |
void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>& args) { |
68 |
|
|
T* wrap; |
69 |
|
4455 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, |
70 |
|
|
args.Holder(), |
71 |
|
|
args.GetReturnValue().Set(UV_EBADF)); |
72 |
|
4455 |
CHECK(args[0]->IsObject()); |
73 |
|
|
sockaddr_storage storage; |
74 |
|
4455 |
int addrlen = sizeof(storage); |
75 |
|
4455 |
sockaddr* const addr = reinterpret_cast<sockaddr*>(&storage); |
76 |
|
4455 |
const int err = F(&wrap->handle_, addr, &addrlen); |
77 |
|
4455 |
if (err == 0) |
78 |
|
8906 |
AddressToJS(wrap->env(), addr, args[0].As<v8::Object>()); |
79 |
|
8910 |
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> InitializeBaseContextForSnapshot( |
96 |
|
|
v8::Local<v8::Context> context); |
97 |
|
|
v8::Maybe<bool> InitializeContextRuntime(v8::Local<v8::Context> context); |
98 |
|
|
v8::Maybe<bool> InitializePrimordials(v8::Local<v8::Context> context); |
99 |
|
|
|
100 |
|
|
class NodeArrayBufferAllocator : public ArrayBufferAllocator { |
101 |
|
|
public: |
102 |
|
240173 |
inline uint32_t* zero_fill_field() { return &zero_fill_field_; } |
103 |
|
|
|
104 |
|
|
void* Allocate(size_t size) override; // Defined in src/node.cc |
105 |
|
|
void* AllocateUninitialized(size_t size) override; |
106 |
|
|
void Free(void* data, size_t size) override; |
107 |
|
|
void* Reallocate(void* data, size_t old_size, size_t size) override; |
108 |
|
|
virtual void RegisterPointer(void* data, size_t size) { |
109 |
|
|
total_mem_usage_.fetch_add(size, std::memory_order_relaxed); |
110 |
|
|
} |
111 |
|
|
virtual void UnregisterPointer(void* data, size_t size) { |
112 |
|
|
total_mem_usage_.fetch_sub(size, std::memory_order_relaxed); |
113 |
|
|
} |
114 |
|
|
|
115 |
|
6261 |
NodeArrayBufferAllocator* GetImpl() final { return this; } |
116 |
|
522 |
inline uint64_t total_mem_usage() const { |
117 |
|
1044 |
return total_mem_usage_.load(std::memory_order_relaxed); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
private: |
121 |
|
|
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land. |
122 |
|
|
std::atomic<size_t> total_mem_usage_ {0}; |
123 |
|
|
|
124 |
|
|
// Delegate to V8's allocator for compatibility with the V8 memory cage. |
125 |
|
|
std::unique_ptr<v8::ArrayBuffer::Allocator> allocator_{ |
126 |
|
|
v8::ArrayBuffer::Allocator::NewDefaultAllocator()}; |
127 |
|
|
}; |
128 |
|
|
|
129 |
|
|
class DebuggingArrayBufferAllocator final : public NodeArrayBufferAllocator { |
130 |
|
|
public: |
131 |
|
|
~DebuggingArrayBufferAllocator() override; |
132 |
|
|
void* Allocate(size_t size) override; |
133 |
|
|
void* AllocateUninitialized(size_t size) override; |
134 |
|
|
void Free(void* data, size_t size) override; |
135 |
|
|
void* Reallocate(void* data, size_t old_size, size_t size) override; |
136 |
|
|
void RegisterPointer(void* data, size_t size) override; |
137 |
|
|
void UnregisterPointer(void* data, size_t size) override; |
138 |
|
|
|
139 |
|
|
private: |
140 |
|
|
void RegisterPointerInternal(void* data, size_t size); |
141 |
|
|
void UnregisterPointerInternal(void* data, size_t size); |
142 |
|
|
Mutex mutex_; |
143 |
|
|
std::unordered_map<void*, size_t> allocations_; |
144 |
|
|
}; |
145 |
|
|
|
146 |
|
|
namespace Buffer { |
147 |
|
|
v8::MaybeLocal<v8::Object> Copy(Environment* env, const char* data, size_t len); |
148 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, size_t size); |
149 |
|
|
// Takes ownership of |data|. |
150 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, |
151 |
|
|
char* data, |
152 |
|
|
size_t length, |
153 |
|
|
void (*callback)(char* data, void* hint), |
154 |
|
|
void* hint); |
155 |
|
|
// Takes ownership of |data|. Must allocate |data| with the current Isolate's |
156 |
|
|
// ArrayBuffer::Allocator(). |
157 |
|
|
v8::MaybeLocal<v8::Object> New(Environment* env, |
158 |
|
|
char* data, |
159 |
|
|
size_t length); |
160 |
|
|
// Creates a Buffer instance over an existing ArrayBuffer. |
161 |
|
|
v8::MaybeLocal<v8::Uint8Array> New(Environment* env, |
162 |
|
|
v8::Local<v8::ArrayBuffer> ab, |
163 |
|
|
size_t byte_offset, |
164 |
|
|
size_t length); |
165 |
|
|
// Construct a Buffer from a MaybeStackBuffer (and also its subclasses like |
166 |
|
|
// Utf8Value and TwoByteValue). |
167 |
|
|
// If |buf| is invalidated, an empty MaybeLocal is returned, and nothing is |
168 |
|
|
// changed. |
169 |
|
|
// If |buf| contains actual data, this method takes ownership of |buf|'s |
170 |
|
|
// underlying buffer. However, |buf| itself can be reused even after this call, |
171 |
|
|
// but its capacity, if increased through AllocateSufficientStorage, is not |
172 |
|
|
// guaranteed to stay the same. |
173 |
|
|
template <typename T> |
174 |
|
2258 |
static v8::MaybeLocal<v8::Object> New(Environment* env, |
175 |
|
|
MaybeStackBuffer<T>* buf) { |
176 |
|
|
v8::MaybeLocal<v8::Object> ret; |
177 |
|
2258 |
char* src = reinterpret_cast<char*>(buf->out()); |
178 |
|
2258 |
const size_t len_in_bytes = buf->length() * sizeof(buf->out()[0]); |
179 |
|
|
|
180 |
|
2258 |
if (buf->IsAllocated()) |
181 |
|
361 |
ret = New(env, src, len_in_bytes); |
182 |
|
1897 |
else if (!buf->IsInvalidated()) |
183 |
|
1897 |
ret = Copy(env, src, len_in_bytes); |
184 |
|
|
|
185 |
|
2258 |
if (ret.IsEmpty()) |
186 |
|
|
return ret; |
187 |
|
|
|
188 |
|
2258 |
if (buf->IsAllocated()) |
189 |
|
361 |
buf->Release(); |
190 |
|
|
|
191 |
|
2258 |
return ret; |
192 |
|
|
} |
193 |
|
|
} // namespace Buffer |
194 |
|
|
|
195 |
|
|
v8::MaybeLocal<v8::Value> InternalMakeCallback( |
196 |
|
|
Environment* env, |
197 |
|
|
v8::Local<v8::Object> resource, |
198 |
|
|
v8::Local<v8::Object> recv, |
199 |
|
|
const v8::Local<v8::Function> callback, |
200 |
|
|
int argc, |
201 |
|
|
v8::Local<v8::Value> argv[], |
202 |
|
|
async_context asyncContext); |
203 |
|
|
|
204 |
|
|
v8::MaybeLocal<v8::Value> MakeSyncCallback(v8::Isolate* isolate, |
205 |
|
|
v8::Local<v8::Object> recv, |
206 |
|
|
v8::Local<v8::Function> callback, |
207 |
|
|
int argc, |
208 |
|
|
v8::Local<v8::Value> argv[]); |
209 |
|
|
|
210 |
|
|
class InternalCallbackScope { |
211 |
|
|
public: |
212 |
|
|
enum Flags { |
213 |
|
|
kNoFlags = 0, |
214 |
|
|
// Indicates whether 'before' and 'after' hooks should be skipped. |
215 |
|
|
kSkipAsyncHooks = 1, |
216 |
|
|
// Indicates whether nextTick and microtask queues should be skipped. |
217 |
|
|
// This should only be used when there is no call into JS in this scope. |
218 |
|
|
// (The HTTP parser also uses it for some weird backwards |
219 |
|
|
// compatibility issues, but it shouldn't.) |
220 |
|
|
kSkipTaskQueues = 2 |
221 |
|
|
}; |
222 |
|
|
InternalCallbackScope(Environment* env, |
223 |
|
|
v8::Local<v8::Object> object, |
224 |
|
|
const async_context& asyncContext, |
225 |
|
|
int flags = kNoFlags); |
226 |
|
|
// Utility that can be used by AsyncWrap classes. |
227 |
|
|
explicit InternalCallbackScope(AsyncWrap* async_wrap, int flags = 0); |
228 |
|
|
~InternalCallbackScope(); |
229 |
|
|
void Close(); |
230 |
|
|
|
231 |
|
884020 |
inline bool Failed() const { return failed_; } |
232 |
|
1289 |
inline void MarkAsFailed() { failed_ = true; } |
233 |
|
|
|
234 |
|
|
private: |
235 |
|
|
Environment* env_; |
236 |
|
|
async_context async_context_; |
237 |
|
|
v8::Local<v8::Object> object_; |
238 |
|
|
bool skip_hooks_; |
239 |
|
|
bool skip_task_queues_; |
240 |
|
|
bool failed_ = false; |
241 |
|
|
bool pushed_ids_ = false; |
242 |
|
|
bool closed_ = false; |
243 |
|
|
}; |
244 |
|
|
|
245 |
|
|
class DebugSealHandleScope { |
246 |
|
|
public: |
247 |
|
704030 |
explicit inline DebugSealHandleScope(v8::Isolate* isolate = nullptr) |
248 |
|
|
#ifdef DEBUG |
249 |
|
|
: actual_scope_(isolate != nullptr ? isolate : v8::Isolate::GetCurrent()) |
250 |
|
|
#endif |
251 |
|
704030 |
{} |
252 |
|
|
|
253 |
|
|
private: |
254 |
|
|
#ifdef DEBUG |
255 |
|
|
v8::SealHandleScope actual_scope_; |
256 |
|
|
#endif |
257 |
|
|
}; |
258 |
|
|
|
259 |
|
|
class ThreadPoolWork { |
260 |
|
|
public: |
261 |
|
11419 |
explicit inline ThreadPoolWork(Environment* env) : env_(env) { |
262 |
✗✓ |
11419 |
CHECK_NOT_NULL(env); |
263 |
|
11419 |
} |
264 |
|
22588 |
inline virtual ~ThreadPoolWork() = default; |
265 |
|
|
|
266 |
|
|
inline void ScheduleWork(); |
267 |
|
|
inline int CancelWork(); |
268 |
|
|
|
269 |
|
|
virtual void DoThreadPoolWork() = 0; |
270 |
|
|
virtual void AfterThreadPoolWork(int status) = 0; |
271 |
|
|
|
272 |
|
|
Environment* env() const { return env_; } |
273 |
|
|
|
274 |
|
|
private: |
275 |
|
|
Environment* env_; |
276 |
|
|
uv_work_t work_req_; |
277 |
|
|
}; |
278 |
|
|
|
279 |
|
|
#define TRACING_CATEGORY_NODE "node" |
280 |
|
|
#define TRACING_CATEGORY_NODE1(one) \ |
281 |
|
|
TRACING_CATEGORY_NODE "," \ |
282 |
|
|
TRACING_CATEGORY_NODE "." #one |
283 |
|
|
#define TRACING_CATEGORY_NODE2(one, two) \ |
284 |
|
|
TRACING_CATEGORY_NODE "," \ |
285 |
|
|
TRACING_CATEGORY_NODE "." #one "," \ |
286 |
|
|
TRACING_CATEGORY_NODE "." #one "." #two |
287 |
|
|
|
288 |
|
|
// Functions defined in node.cc that are exposed via the bootstrapper object |
289 |
|
|
|
290 |
|
|
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__) |
291 |
|
|
#define NODE_IMPLEMENTS_POSIX_CREDENTIALS 1 |
292 |
|
|
#endif // defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__) |
293 |
|
|
|
294 |
|
|
namespace credentials { |
295 |
|
|
bool SafeGetenv(const char* key, |
296 |
|
|
std::string* text, |
297 |
|
|
std::shared_ptr<KVStore> env_vars = nullptr, |
298 |
|
|
v8::Isolate* isolate = nullptr); |
299 |
|
|
} // namespace credentials |
300 |
|
|
|
301 |
|
|
void DefineZlibConstants(v8::Local<v8::Object> target); |
302 |
|
|
v8::Isolate* NewIsolate(v8::Isolate::CreateParams* params, |
303 |
|
|
uv_loop_t* event_loop, |
304 |
|
|
MultiIsolatePlatform* platform); |
305 |
|
|
// This overload automatically picks the right 'main_script_id' if no callback |
306 |
|
|
// was provided by the embedder. |
307 |
|
|
v8::MaybeLocal<v8::Value> StartExecution(Environment* env, |
308 |
|
|
StartExecutionCallback cb = nullptr); |
309 |
|
|
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context); |
310 |
|
|
void MarkBootstrapComplete(const v8::FunctionCallbackInfo<v8::Value>& args); |
311 |
|
|
|
312 |
|
|
class InitializationResultImpl final : public InitializationResult { |
313 |
|
|
public: |
314 |
|
|
~InitializationResultImpl(); |
315 |
|
11186 |
int exit_code() const { return exit_code_; } |
316 |
|
5597 |
bool early_return() const { return early_return_; } |
317 |
|
5603 |
const std::vector<std::string>& args() const { return args_; } |
318 |
|
5537 |
const std::vector<std::string>& exec_args() const { return exec_args_; } |
319 |
|
5591 |
const std::vector<std::string>& errors() const { return errors_; } |
320 |
|
|
MultiIsolatePlatform* platform() const { return platform_; } |
321 |
|
|
|
322 |
|
|
int exit_code_ = 0; |
323 |
|
|
std::vector<std::string> args_; |
324 |
|
|
std::vector<std::string> exec_args_; |
325 |
|
|
std::vector<std::string> errors_; |
326 |
|
|
bool early_return_ = false; |
327 |
|
|
MultiIsolatePlatform* platform_ = nullptr; |
328 |
|
|
}; |
329 |
|
|
|
330 |
|
|
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s); |
331 |
|
|
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s); |
332 |
|
|
void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params); |
333 |
|
|
|
334 |
|
|
#if HAVE_INSPECTOR |
335 |
|
|
namespace profiler { |
336 |
|
|
void StartProfilers(Environment* env); |
337 |
|
|
} |
338 |
|
|
#endif // HAVE_INSPECTOR |
339 |
|
|
|
340 |
|
|
#ifdef __POSIX__ |
341 |
|
|
static constexpr unsigned kMaxSignal = 32; |
342 |
|
|
#endif |
343 |
|
|
|
344 |
|
|
bool HasSignalJSHandler(int signum); |
345 |
|
|
|
346 |
|
|
#ifdef _WIN32 |
347 |
|
|
typedef SYSTEMTIME TIME_TYPE; |
348 |
|
|
#else // UNIX, OSX |
349 |
|
|
typedef struct tm TIME_TYPE; |
350 |
|
|
#endif |
351 |
|
|
|
352 |
|
|
double GetCurrentTimeInMicroseconds(); |
353 |
|
|
int WriteFileSync(const char* path, uv_buf_t buf); |
354 |
|
|
int WriteFileSync(v8::Isolate* isolate, |
355 |
|
|
const char* path, |
356 |
|
|
v8::Local<v8::String> string); |
357 |
|
|
|
358 |
|
|
class DiagnosticFilename { |
359 |
|
|
public: |
360 |
|
|
static void LocalTime(TIME_TYPE* tm_struct); |
361 |
|
|
|
362 |
|
|
inline DiagnosticFilename(Environment* env, |
363 |
|
|
const char* prefix, |
364 |
|
|
const char* ext); |
365 |
|
|
|
366 |
|
|
inline DiagnosticFilename(uint64_t thread_id, |
367 |
|
|
const char* prefix, |
368 |
|
|
const char* ext); |
369 |
|
|
|
370 |
|
|
inline const char* operator*() const; |
371 |
|
|
|
372 |
|
|
private: |
373 |
|
|
static std::string MakeFilename( |
374 |
|
|
uint64_t thread_id, |
375 |
|
|
const char* prefix, |
376 |
|
|
const char* ext); |
377 |
|
|
|
378 |
|
|
std::string filename_; |
379 |
|
|
}; |
380 |
|
|
|
381 |
|
|
namespace heap { |
382 |
|
|
v8::Maybe<void> WriteSnapshot(Environment* env, const char* filename); |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
namespace heap { |
386 |
|
|
|
387 |
|
|
void DeleteHeapSnapshot(const v8::HeapSnapshot* snapshot); |
388 |
|
|
using HeapSnapshotPointer = |
389 |
|
|
DeleteFnPtr<const v8::HeapSnapshot, DeleteHeapSnapshot>; |
390 |
|
|
|
391 |
|
|
BaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream( |
392 |
|
|
Environment* env, HeapSnapshotPointer&& snapshot); |
393 |
|
|
} // namespace heap |
394 |
|
|
|
395 |
|
|
namespace fs { |
396 |
|
|
std::string Basename(const std::string& str, const std::string& extension); |
397 |
|
|
} // namespace fs |
398 |
|
|
|
399 |
|
|
node_module napi_module_to_node_module(const napi_module* mod); |
400 |
|
|
|
401 |
|
|
std::ostream& operator<<(std::ostream& output, |
402 |
|
|
const std::vector<SnapshotIndex>& v); |
403 |
|
|
std::ostream& operator<<(std::ostream& output, |
404 |
|
|
const std::vector<std::string>& vec); |
405 |
|
|
std::ostream& operator<<(std::ostream& output, |
406 |
|
|
const std::vector<PropInfo>& vec); |
407 |
|
|
std::ostream& operator<<(std::ostream& output, const PropInfo& d); |
408 |
|
|
std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& d); |
409 |
|
|
std::ostream& operator<<(std::ostream& output, |
410 |
|
|
const ImmediateInfo::SerializeInfo& d); |
411 |
|
|
std::ostream& operator<<(std::ostream& output, |
412 |
|
|
const TickInfo::SerializeInfo& d); |
413 |
|
|
std::ostream& operator<<(std::ostream& output, |
414 |
|
|
const AsyncHooks::SerializeInfo& d); |
415 |
|
|
std::ostream& operator<<(std::ostream& output, const SnapshotMetadata& d); |
416 |
|
|
|
417 |
|
|
namespace performance { |
418 |
|
|
std::ostream& operator<<(std::ostream& output, |
419 |
|
|
const PerformanceState::SerializeInfo& d); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
bool linux_at_secure(); |
423 |
|
|
} // namespace node |
424 |
|
|
|
425 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
426 |
|
|
|
427 |
|
|
#endif // SRC_NODE_INTERNALS_H_ |