Skip to content

Commit eef1c86

Browse files
committed
src: simplify exit code accesses
This simplifies getting the exit code which is set through `process.exitCode` by removing manually reading the JS property from the native side. Signed-off-by: Daeyeon Jeong <[email protected]>
1 parent e43d191 commit eef1c86

File tree

7 files changed

+73
-37
lines changed

7 files changed

+73
-37
lines changed

lib/internal/bootstrap/node.js

+7
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ const {
8383
exiting_aliased_Uint32Array,
8484
getHiddenValue,
8585
} = internalBinding('util');
86+
const {
87+
exit_code_symbol: kExitCode,
88+
} = internalBinding('symbols');
8689

8790
setupProcessObject();
8891

@@ -123,6 +126,10 @@ process._exiting = false;
123126
value = code;
124127
}
125128
validateInteger(value, 'code');
129+
process[kExitCode] = value;
130+
} else {
131+
// unset exit code
132+
process[kExitCode] = code;
126133
}
127134
exitCode = code;
128135
},

src/api/hooks.cc

+13-26
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ using v8::NewStringType;
1616
using v8::Nothing;
1717
using v8::Object;
1818
using v8::String;
19-
using v8::Value;
2019

2120
void RunAtExit(Environment* env) {
2221
env->RunAtExitCallbacks();
@@ -36,18 +35,14 @@ Maybe<bool> EmitProcessBeforeExit(Environment* env) {
3635
if (!env->destroy_async_id_list()->empty())
3736
AsyncWrap::DestroyAsyncIdsCallback(env);
3837

39-
HandleScope handle_scope(env->isolate());
38+
Isolate* isolate = env->isolate();
39+
HandleScope handle_scope(isolate);
4040
Local<Context> context = env->context();
4141
Context::Scope context_scope(context);
4242

43-
Local<Value> exit_code_v;
44-
if (!env->process_object()->Get(context, env->exit_code_string())
45-
.ToLocal(&exit_code_v)) return Nothing<bool>();
46-
47-
Local<Integer> exit_code;
48-
if (!exit_code_v->ToInteger(context).ToLocal(&exit_code)) {
49-
return Nothing<bool>();
50-
}
43+
Local<Integer> exit_code = v8::Integer::New(
44+
isolate,
45+
env->exit_code().value_or(static_cast<int32_t>(ExitCode::kNoFailure)));
5146

5247
return ProcessEmit(env, "beforeExit", exit_code).IsEmpty() ?
5348
Nothing<bool>() : Just(true);
@@ -67,27 +62,19 @@ Maybe<ExitCode> EmitProcessExitInternal(Environment* env) {
6762
HandleScope handle_scope(isolate);
6863
Local<Context> context = env->context();
6964
Context::Scope context_scope(context);
70-
Local<Object> process_object = env->process_object();
7165

72-
// TODO(addaleax): It might be nice to share process.exitCode via
73-
// getter/setter pairs that pass data directly to the native side, so that we
74-
// don't manually have to read and write JS properties here. These getters
75-
// could use e.g. a typed array for performance.
7666
env->set_exiting(true);
7767

78-
Local<String> exit_code = env->exit_code_string();
79-
Local<Value> code_v;
80-
int code;
81-
if (!process_object->Get(context, exit_code).ToLocal(&code_v) ||
82-
!code_v->Int32Value(context).To(&code) ||
83-
ProcessEmit(env, "exit", Integer::New(isolate, code)).IsEmpty() ||
84-
// Reload exit code, it may be changed by `emit('exit')`
85-
!process_object->Get(context, exit_code).ToLocal(&code_v) ||
86-
!code_v->Int32Value(context).To(&code)) {
68+
const std::optional<int32_t>& exit_code = env->exit_code();
69+
const int no_failure = static_cast<int32_t>(ExitCode::kNoFailure);
70+
71+
if (ProcessEmit(
72+
env, "exit", Integer::New(isolate, exit_code.value_or(no_failure)))
73+
.IsEmpty()) {
8774
return Nothing<ExitCode>();
8875
}
89-
90-
return Just(static_cast<ExitCode>(code));
76+
// Reload exit code, it may be changed by `emit('exit')`
77+
return Just(static_cast<ExitCode>(exit_code.value_or(no_failure)));
9178
}
9279

9380
Maybe<int> EmitProcessExit(Environment* env) {

src/env-inl.h

+8
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,14 @@ inline AliasedUint32Array& Environment::exiting() {
371371
return exiting_;
372372
}
373373

374+
inline void Environment::set_exit_code(const std::optional<int32_t> value) {
375+
exit_code_ = value;
376+
}
377+
378+
inline const std::optional<int32_t>& Environment::exit_code() const {
379+
return exit_code_;
380+
}
381+
374382
inline void Environment::set_abort_on_uncaught_exception(bool value) {
375383
options_->abort_on_uncaught_exception = value;
376384
}

src/env.h

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include <functional>
5555
#include <list>
5656
#include <memory>
57+
#include <optional>
5758
#include <ostream>
5859
#include <set>
5960
#include <string>
@@ -746,6 +747,9 @@ class Environment : public MemoryRetainer {
746747
inline void set_exiting(bool value);
747748
inline AliasedUint32Array& exiting();
748749

750+
inline void set_exit_code(const std::optional<int32_t> value);
751+
inline const std::optional<int32_t>& exit_code() const;
752+
749753
// This stores whether the --abort-on-uncaught-exception flag was passed
750754
// to Node.
751755
inline bool abort_on_uncaught_exception() const;
@@ -1102,6 +1106,7 @@ class Environment : public MemoryRetainer {
11021106
uint32_t function_id_counter_ = 0;
11031107

11041108
AliasedUint32Array exiting_;
1109+
std::optional<int32_t> exit_code_;
11051110

11061111
AliasedUint32Array should_abort_on_uncaught_toggle_;
11071112
int should_not_abort_scope_counter_ = 0;

src/env_properties.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
V(owner_symbol, "owner_symbol") \
4242
V(onpskexchange_symbol, "onpskexchange") \
4343
V(resource_symbol, "resource_symbol") \
44-
V(trigger_async_id_symbol, "trigger_async_id_symbol")
44+
V(trigger_async_id_symbol, "trigger_async_id_symbol") \
45+
V(exit_code_symbol, "exit_code_symbol")
4546

4647
// Strings are per-isolate primitives but Environment proxies them
4748
// for the sake of convenience. Strings should be ASCII-only.
@@ -114,7 +115,6 @@
114115
V(errno_string, "errno") \
115116
V(error_string, "error") \
116117
V(exchange_string, "exchange") \
117-
V(exit_code_string, "exitCode") \
118118
V(expire_string, "expire") \
119119
V(exponent_string, "exponent") \
120120
V(exports_string, "exports") \

src/node_errors.cc

+3-9
Original file line numberDiff line numberDiff line change
@@ -1151,15 +1151,9 @@ void TriggerUncaughtException(Isolate* isolate,
11511151
RunAtExit(env);
11521152

11531153
// If the global uncaught exception handler sets process.exitCode,
1154-
// exit with that code. Otherwise, exit with 1.
1155-
Local<String> exit_code = env->exit_code_string();
1156-
Local<Value> code;
1157-
if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
1158-
code->IsInt32()) {
1159-
env->Exit(static_cast<ExitCode>(code.As<Int32>()->Value()));
1160-
} else {
1161-
env->Exit(ExitCode::kGenericUserError);
1162-
}
1154+
// exit with that code. Otherwise, exit with `ExitCode::kGenericUserError`.
1155+
env->Exit(static_cast<ExitCode>(env->exit_code().value_or(
1156+
static_cast<int32_t>(ExitCode::kGenericUserError))));
11631157
}
11641158

11651159
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {

src/node_process_object.cc

+35
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace node {
1515
using v8::Context;
1616
using v8::DEFAULT;
17+
using v8::DontEnum;
1718
using v8::EscapableHandleScope;
1819
using v8::Function;
1920
using v8::FunctionCallbackInfo;
@@ -73,6 +74,27 @@ static void DebugPortSetter(Local<Name> property,
7374
host_port->set_port(static_cast<int>(port));
7475
}
7576

77+
static void ExitCodeGetter(Local<Name> property,
78+
const PropertyCallbackInfo<Value>& info) {
79+
Environment* env = Environment::GetCurrent(info);
80+
std::optional<int32_t> maybe_exit_code = env->exit_code();
81+
if (maybe_exit_code) {
82+
info.GetReturnValue().Set(*maybe_exit_code);
83+
}
84+
}
85+
86+
static void ExitCodeSetter(Local<Name> property,
87+
Local<Value> value,
88+
const PropertyCallbackInfo<void>& info) {
89+
Environment* env = Environment::GetCurrent(info);
90+
if (value->IsNullOrUndefined()) {
91+
return env->set_exit_code(std::nullopt);
92+
}
93+
env->set_exit_code(
94+
value->Int32Value(env->context())
95+
.FromMaybe(static_cast<int32_t>(ExitCode::kNoFailure)));
96+
}
97+
7698
static void GetParentProcessId(Local<Name> property,
7799
const PropertyCallbackInfo<Value>& info) {
78100
info.GetReturnValue().Set(uv_os_getppid());
@@ -216,6 +238,17 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) {
216238
env->owns_process_state() ? DebugPortSetter : nullptr,
217239
Local<Value>())
218240
.FromJust());
241+
242+
// process[exit_code_symbol]
243+
CHECK(process
244+
->SetAccessor(context,
245+
env->exit_code_symbol(),
246+
ExitCodeGetter,
247+
ExitCodeSetter,
248+
Local<Value>(),
249+
DEFAULT,
250+
DontEnum)
251+
.FromJust());
219252
}
220253

221254
void RegisterProcessExternalReferences(ExternalReferenceRegistry* registry) {
@@ -225,6 +258,8 @@ void RegisterProcessExternalReferences(ExternalReferenceRegistry* registry) {
225258
registry->Register(DebugPortGetter);
226259
registry->Register(ProcessTitleSetter);
227260
registry->Register(ProcessTitleGetter);
261+
registry->Register(ExitCodeSetter);
262+
registry->Register(ExitCodeGetter);
228263
}
229264

230265
} // namespace node

0 commit comments

Comments
 (0)