diff --git a/node.gyp b/node.gyp index e0e1449bfa680f..f5dfe097fdbc20 100644 --- a/node.gyp +++ b/node.gyp @@ -371,6 +371,7 @@ 'src/node_perf.cc', 'src/node_platform.cc', 'src/node_postmortem_metadata.cc', + 'src/node_process_events.cc', 'src/node_process_methods.cc', 'src/node_process_object.cc', 'src/node_serdes.cc', diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index d9a252bbe88140..a53c58337e900b 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -370,26 +370,13 @@ class SameThreadInspectorSession : public InspectorSession { void NotifyClusterWorkersDebugEnabled(Environment* env) { Isolate* isolate = env->isolate(); HandleScope handle_scope(isolate); - auto context = env->context(); + Local context = env->context(); // Send message to enable debug in cluster workers - Local process_object = env->process_object(); - Local emit_fn = - process_object->Get(context, FIXED_ONE_BYTE_STRING(isolate, "emit")) - .ToLocalChecked(); - // In case the thread started early during the startup - if (!emit_fn->IsFunction()) - return; - Local message = Object::New(isolate); message->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cmd"), FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED")).FromJust(); - Local argv[] = { - FIXED_ONE_BYTE_STRING(isolate, "internalMessage"), - message - }; - MakeCallback(env->isolate(), process_object, emit_fn.As(), - arraysize(argv), argv, {0, 0}); + ProcessEmit(env, "internalMessage", message); } #ifdef _WIN32 diff --git a/src/node.cc b/src/node.cc index 8e5dbd1516235d..7a585646f66ec4 100644 --- a/src/node.cc +++ b/src/node.cc @@ -124,8 +124,6 @@ using v8::Maybe; using v8::MaybeLocal; using v8::Message; using v8::MicrotasksPolicy; -using v8::NewStringType; -using v8::Nothing; using v8::Object; using v8::ObjectTemplate; using v8::Script; @@ -586,82 +584,6 @@ void Exit(const FunctionCallbackInfo& args) { env->Exit(code); } -static Maybe ProcessEmitWarningGeneric(Environment* env, - const char* warning, - const char* type = nullptr, - const char* code = nullptr) { - HandleScope handle_scope(env->isolate()); - Context::Scope context_scope(env->context()); - - Local process = env->process_object(); - Local emit_warning; - if (!process->Get(env->context(), - env->emit_warning_string()).ToLocal(&emit_warning)) { - return Nothing(); - } - - if (!emit_warning->IsFunction()) return Just(false); - - int argc = 0; - Local args[3]; // warning, type, code - - // The caller has to be able to handle a failure anyway, so we might as well - // do proper error checking for string creation. - if (!String::NewFromUtf8(env->isolate(), - warning, - NewStringType::kNormal).ToLocal(&args[argc++])) { - return Nothing(); - } - if (type != nullptr) { - if (!String::NewFromOneByte(env->isolate(), - reinterpret_cast(type), - NewStringType::kNormal) - .ToLocal(&args[argc++])) { - return Nothing(); - } - if (code != nullptr && - !String::NewFromOneByte(env->isolate(), - reinterpret_cast(code), - NewStringType::kNormal) - .ToLocal(&args[argc++])) { - return Nothing(); - } - } - - // MakeCallback() unneeded because emitWarning is internal code, it calls - // process.emit('warning', ...), but does so on the nextTick. - if (emit_warning.As()->Call(env->context(), - process, - argc, - args).IsEmpty()) { - return Nothing(); - } - return Just(true); -} - - -// Call process.emitWarning(str), fmt is a snprintf() format string -Maybe ProcessEmitWarning(Environment* env, const char* fmt, ...) { - char warning[1024]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(warning, sizeof(warning), fmt, ap); - va_end(ap); - - return ProcessEmitWarningGeneric(env, warning); -} - - -Maybe ProcessEmitDeprecationWarning(Environment* env, - const char* warning, - const char* deprecation_code) { - return ProcessEmitWarningGeneric(env, - warning, - "DeprecationWarning", - deprecation_code); -} - static void OnMessage(Local message, Local error) { Isolate* isolate = message->GetIsolate(); switch (message->ErrorLevel()) { @@ -1164,19 +1086,14 @@ void RunBeforeExit(Environment* env) { void EmitBeforeExit(Environment* env) { HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); - Local process_object = env->process_object(); - Local exit_code = env->exit_code_string(); - Local args[] = { - FIXED_ONE_BYTE_STRING(env->isolate(), "beforeExit"), - process_object->Get(env->context(), exit_code).ToLocalChecked() - ->ToInteger(env->context()).ToLocalChecked() - }; - MakeCallback(env->isolate(), - process_object, "emit", arraysize(args), args, - {0, 0}).ToLocalChecked(); + Local exit_code = env->process_object() + ->Get(env->context(), env->exit_code_string()) + .ToLocalChecked() + ->ToInteger(env->context()) + .ToLocalChecked(); + ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked(); } - int EmitExit(Environment* env) { // process.emit('exit') HandleScope handle_scope(env->isolate()); @@ -1189,15 +1106,7 @@ int EmitExit(Environment* env) { Local exit_code = env->exit_code_string(); int code = process_object->Get(env->context(), exit_code).ToLocalChecked() ->Int32Value(env->context()).ToChecked(); - - Local args[] = { - FIXED_ONE_BYTE_STRING(env->isolate(), "exit"), - Integer::New(env->isolate(), code) - }; - - MakeCallback(env->isolate(), - process_object, "emit", arraysize(args), args, - {0, 0}).ToLocalChecked(); + ProcessEmit(env, "exit", Integer::New(env->isolate(), code)); // Reload exit code, it may be changed by `emit('exit')` return process_object->Get(env->context(), exit_code).ToLocalChecked() diff --git a/src/node_process.h b/src/node_process.h index 35667ca1b9de40..865223c1634010 100644 --- a/src/node_process.h +++ b/src/node_process.h @@ -17,6 +17,15 @@ v8::Local CreateEnvVarProxy(v8::Local context, // function, it is useful to bypass JavaScript entirely. void RawDebug(const v8::FunctionCallbackInfo& args); +v8::MaybeLocal ProcessEmit(Environment* env, + const char* event, + v8::Local message); + +v8::Maybe ProcessEmitWarningGeneric(Environment* env, + const char* warning, + const char* type = nullptr, + const char* code = nullptr); + v8::Maybe ProcessEmitWarning(Environment* env, const char* fmt, ...); v8::Maybe ProcessEmitDeprecationWarning(Environment* env, const char* warning, diff --git a/src/node_process_events.cc b/src/node_process_events.cc new file mode 100644 index 00000000000000..d9c87173abe317 --- /dev/null +++ b/src/node_process_events.cc @@ -0,0 +1,103 @@ +#include + +#include "env.h" +#include "node_internals.h" +#include "node_process.h" + +namespace node { +using v8::Context; +using v8::Function; +using v8::HandleScope; +using v8::Isolate; +using v8::Just; +using v8::Local; +using v8::Maybe; +using v8::MaybeLocal; +using v8::NewStringType; +using v8::Nothing; +using v8::Object; +using v8::String; +using v8::Value; + +MaybeLocal ProcessEmit(Environment* env, + const char* event, + Local message) { + // Send message to enable debug in cluster workers + Local process = env->process_object(); + Isolate* isolate = env->isolate(); + Local argv[] = {OneByteString(isolate, event), message}; + + return MakeCallback(isolate, process, "emit", arraysize(argv), argv, {0, 0}); +} + +Maybe ProcessEmitWarningGeneric(Environment* env, + const char* warning, + const char* type, + const char* code) { + HandleScope handle_scope(env->isolate()); + Context::Scope context_scope(env->context()); + + Local process = env->process_object(); + Local emit_warning; + if (!process->Get(env->context(), env->emit_warning_string()) + .ToLocal(&emit_warning)) { + return Nothing(); + } + + if (!emit_warning->IsFunction()) return Just(false); + + int argc = 0; + Local args[3]; // warning, type, code + + // The caller has to be able to handle a failure anyway, so we might as well + // do proper error checking for string creation. + if (!String::NewFromUtf8(env->isolate(), warning, NewStringType::kNormal) + .ToLocal(&args[argc++])) { + return Nothing(); + } + if (type != nullptr) { + if (!String::NewFromOneByte(env->isolate(), + reinterpret_cast(type), + NewStringType::kNormal) + .ToLocal(&args[argc++])) { + return Nothing(); + } + if (code != nullptr && + !String::NewFromOneByte(env->isolate(), + reinterpret_cast(code), + NewStringType::kNormal) + .ToLocal(&args[argc++])) { + return Nothing(); + } + } + + // MakeCallback() unneeded because emitWarning is internal code, it calls + // process.emit('warning', ...), but does so on the nextTick. + if (emit_warning.As() + ->Call(env->context(), process, argc, args) + .IsEmpty()) { + return Nothing(); + } + return Just(true); +} + +// Call process.emitWarning(str), fmt is a snprintf() format string +Maybe ProcessEmitWarning(Environment* env, const char* fmt, ...) { + char warning[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(warning, sizeof(warning), fmt, ap); + va_end(ap); + + return ProcessEmitWarningGeneric(env, warning); +} + +Maybe ProcessEmitDeprecationWarning(Environment* env, + const char* warning, + const char* deprecation_code) { + return ProcessEmitWarningGeneric( + env, warning, "DeprecationWarning", deprecation_code); +} + +} // namespace node