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