Skip to content

Commit 7b1e153

Browse files
authored
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]> PR-URL: #45125 Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 09ae62b commit 7b1e153

10 files changed

+82
-66
lines changed

lib/internal/bootstrap/node.js

+15-9
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,11 @@ const {
8080
validateInteger,
8181
} = require('internal/validators');
8282
const {
83-
exiting_aliased_Uint32Array,
83+
exit_info_private_symbol,
8484
getHiddenValue,
85+
kExitCode,
86+
kExiting,
87+
kHasExitCode,
8588
} = internalBinding('util');
8689

8790
setupProcessObject();
@@ -90,26 +93,24 @@ setupGlobalProxy();
9093
setupBuffer();
9194

9295
process.domain = null;
96+
97+
// process._exiting and process.exitCode
9398
{
94-
const exitingAliasedUint32Array =
95-
getHiddenValue(process, exiting_aliased_Uint32Array);
99+
const fields = getHiddenValue(process, exit_info_private_symbol);
100+
96101
ObjectDefineProperty(process, '_exiting', {
97102
__proto__: null,
98103
get() {
99-
return exitingAliasedUint32Array[0] === 1;
104+
return fields[kExiting] === 1;
100105
},
101106
set(value) {
102-
exitingAliasedUint32Array[0] = value ? 1 : 0;
107+
fields[kExiting] = value ? 1 : 0;
103108
},
104109
enumerable: true,
105110
configurable: true,
106111
});
107-
}
108-
process._exiting = false;
109112

110-
{
111113
let exitCode;
112-
113114
ObjectDefineProperty(process, 'exitCode', {
114115
__proto__: null,
115116
get() {
@@ -123,13 +124,18 @@ process._exiting = false;
123124
value = code;
124125
}
125126
validateInteger(value, 'code');
127+
fields[kExitCode] = value;
128+
fields[kHasExitCode] = 1;
129+
} else {
130+
fields[kHasExitCode] = 0;
126131
}
127132
exitCode = code;
128133
},
129134
enumerable: true,
130135
configurable: false,
131136
});
132137
}
138+
process._exiting = false;
133139

134140
// process.config is serialized config.gypi
135141
const nativeModule = internalBinding('builtins');

src/api/hooks.cc

+18-28
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,19 +35,17 @@ Maybe<bool> EmitProcessBeforeExit(Environment* env) {
3635
if (!env->destroy_async_id_list()->empty())
3736
AsyncWrap::DestroyAsyncIdsCallback(env);
3837

39-
HandleScope handle_scope(env->isolate());
40-
Local<Context> context = env->context();
41-
Context::Scope context_scope(context);
42-
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>();
38+
Isolate* isolate = env->isolate();
39+
HandleScope handle_scope(isolate);
40+
Context::Scope context_scope(env->context());
4641

47-
Local<Integer> exit_code;
48-
if (!exit_code_v->ToInteger(context).ToLocal(&exit_code)) {
42+
if (!env->can_call_into_js()) {
4943
return Nothing<bool>();
5044
}
5145

46+
Local<Integer> exit_code = Integer::New(
47+
isolate, static_cast<int32_t>(env->exit_code(ExitCode::kNoFailure)));
48+
5249
return ProcessEmit(env, "beforeExit", exit_code).IsEmpty() ?
5350
Nothing<bool>() : Just(true);
5451
}
@@ -65,29 +62,22 @@ Maybe<ExitCode> EmitProcessExitInternal(Environment* env) {
6562
// process.emit('exit')
6663
Isolate* isolate = env->isolate();
6764
HandleScope handle_scope(isolate);
68-
Local<Context> context = env->context();
69-
Context::Scope context_scope(context);
70-
Local<Object> process_object = env->process_object();
71-
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.
65+
Context::Scope context_scope(env->context());
66+
7667
env->set_exiting(true);
7768

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)) {
69+
if (!env->can_call_into_js()) {
8770
return Nothing<ExitCode>();
8871
}
8972

90-
return Just(static_cast<ExitCode>(code));
73+
Local<Integer> exit_code = Integer::New(
74+
isolate, static_cast<int32_t>(env->exit_code(ExitCode::kNoFailure)));
75+
76+
if (ProcessEmit(env, "exit", exit_code).IsEmpty()) {
77+
return Nothing<ExitCode>();
78+
}
79+
// Reload exit code, it may be changed by `emit('exit')`
80+
return Just(env->exit_code(ExitCode::kNoFailure));
9181
}
9282

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

src/env-inl.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,17 @@ inline bool Environment::force_context_aware() const {
364364
}
365365

366366
inline void Environment::set_exiting(bool value) {
367-
exiting_[0] = value ? 1 : 0;
367+
exit_info_[kExiting] = value ? 1 : 0;
368368
}
369369

370-
inline AliasedUint32Array& Environment::exiting() {
371-
return exiting_;
370+
inline ExitCode Environment::exit_code(const ExitCode default_code) const {
371+
return exit_info_[kHasExitCode] == 0
372+
? default_code
373+
: static_cast<ExitCode>(exit_info_[kExitCode]);
374+
}
375+
376+
inline AliasedInt32Array& Environment::exit_info() {
377+
return exit_info_;
372378
}
373379

374380
inline void Environment::set_abort_on_uncaught_exception(bool value) {

src/env.cc

+5-4
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,8 @@ Environment::Environment(IsolateData* isolate_data,
655655
exec_argv_(exec_args),
656656
argv_(args),
657657
exec_path_(GetExecPath(args)),
658-
exiting_(isolate_, 1, MAYBE_FIELD_PTR(env_info, exiting)),
658+
exit_info_(
659+
isolate_, kExitInfoFieldCount, MAYBE_FIELD_PTR(env_info, exit_info)),
659660
should_abort_on_uncaught_toggle_(
660661
isolate_,
661662
1,
@@ -1608,7 +1609,7 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
16081609
info.immediate_info = immediate_info_.Serialize(ctx, creator);
16091610
info.tick_info = tick_info_.Serialize(ctx, creator);
16101611
info.performance_state = performance_state_->Serialize(ctx, creator);
1611-
info.exiting = exiting_.Serialize(ctx, creator);
1612+
info.exit_info = exit_info_.Serialize(ctx, creator);
16121613
info.stream_base_state = stream_base_state_.Serialize(ctx, creator);
16131614
info.should_abort_on_uncaught_toggle =
16141615
should_abort_on_uncaught_toggle_.Serialize(ctx, creator);
@@ -1654,7 +1655,7 @@ void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
16541655
immediate_info_.Deserialize(ctx);
16551656
tick_info_.Deserialize(ctx);
16561657
performance_state_->Deserialize(ctx);
1657-
exiting_.Deserialize(ctx);
1658+
exit_info_.Deserialize(ctx);
16581659
stream_base_state_.Deserialize(ctx);
16591660
should_abort_on_uncaught_toggle_.Deserialize(ctx);
16601661

@@ -1844,7 +1845,7 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const {
18441845
tracker->TrackField("builtins_without_cache", builtins_without_cache);
18451846
tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
18461847
tracker->TrackField("exec_argv", exec_argv_);
1847-
tracker->TrackField("exiting", exiting_);
1848+
tracker->TrackField("exit_info", exit_info_);
18481849
tracker->TrackField("should_abort_on_uncaught_toggle",
18491850
should_abort_on_uncaught_toggle_);
18501851
tracker->TrackField("stream_base_state", stream_base_state_);

src/env.h

+15-5
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ struct EnvSerializeInfo {
510510
TickInfo::SerializeInfo tick_info;
511511
ImmediateInfo::SerializeInfo immediate_info;
512512
performance::PerformanceState::SerializeInfo performance_state;
513-
AliasedBufferIndex exiting;
513+
AliasedBufferIndex exit_info;
514514
AliasedBufferIndex stream_base_state;
515515
AliasedBufferIndex should_abort_on_uncaught_toggle;
516516

@@ -743,10 +743,12 @@ class Environment : public MemoryRetainer {
743743
inline void set_force_context_aware(bool value);
744744
inline bool force_context_aware() const;
745745

746-
// This is a pseudo-boolean that keeps track of whether the process is
747-
// exiting.
746+
// This contains fields that are a pseudo-boolean that keeps track of whether
747+
// the process is exiting, an integer representing the process exit code, and
748+
// a pseudo-boolean to indicate whether the exit code is undefined.
749+
inline AliasedInt32Array& exit_info();
748750
inline void set_exiting(bool value);
749-
inline AliasedUint32Array& exiting();
751+
inline ExitCode exit_code(const ExitCode default_code) const;
750752

751753
// This stores whether the --abort-on-uncaught-exception flag was passed
752754
// to Node.
@@ -1038,6 +1040,14 @@ class Environment : public MemoryRetainer {
10381040

10391041
inline void RemoveHeapSnapshotNearHeapLimitCallback(size_t heap_limit);
10401042

1043+
// Field identifiers for exit_info_
1044+
enum ExitInfoField {
1045+
kExiting = 0,
1046+
kExitCode,
1047+
kHasExitCode,
1048+
kExitInfoFieldCount
1049+
};
1050+
10411051
private:
10421052
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
10431053
const char* errmsg);
@@ -1103,7 +1113,7 @@ class Environment : public MemoryRetainer {
11031113
uint32_t script_id_counter_ = 0;
11041114
uint32_t function_id_counter_ = 0;
11051115

1106-
AliasedUint32Array exiting_;
1116+
AliasedInt32Array exit_info_;
11071117

11081118
AliasedUint32Array should_abort_on_uncaught_toggle_;
11091119
int should_not_abort_scope_counter_ = 0;

src/env_properties.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
V(napi_type_tag, "node:napi:type_tag") \
2525
V(napi_wrapper, "node:napi:wrapper") \
2626
V(untransferable_object_private_symbol, "node:untransferableObject") \
27-
V(exiting_aliased_Uint32Array, "node:exiting_aliased_Uint32Array")
27+
V(exit_info_private_symbol, "node:exit_info_private_symbol")
2828

2929
// Symbols are per-isolate primitives but Environment proxies them
3030
// for the sake of convenience.
@@ -114,7 +114,6 @@
114114
V(errno_string, "errno") \
115115
V(error_string, "error") \
116116
V(exchange_string, "exchange") \
117-
V(exit_code_string, "exitCode") \
118117
V(expire_string, "expire") \
119118
V(exponent_string, "exponent") \
120119
V(exports_string, "exports") \

src/node_errors.cc

+2-9
Original file line numberDiff line numberDiff line change
@@ -1151,15 +1151,8 @@ 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(env->exit_code(ExitCode::kGenericUserError));
11631156
}
11641157

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

src/node_process_object.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ MaybeLocal<Object> CreateProcessObject(Realm* realm) {
9292
return MaybeLocal<Object>();
9393
}
9494

95-
// process[exiting_aliased_Uint32Array]
95+
// process[exit_info_private_symbol]
9696
if (process
9797
->SetPrivate(context,
98-
realm->env()->exiting_aliased_Uint32Array(),
99-
realm->env()->exiting().GetJSArray())
98+
realm->env()->exit_info_private_symbol(),
99+
realm->env()->exit_info().GetJSArray())
100100
.IsNothing()) {
101101
return {};
102102
}

src/node_snapshotable.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
123123
<< "// -- performance_state begins --\n"
124124
<< i.performance_state << ",\n"
125125
<< "// -- performance_state ends --\n"
126-
<< i.exiting << ", // exiting\n"
126+
<< i.exit_info << ", // exit_info\n"
127127
<< i.stream_base_state << ", // stream_base_state\n"
128128
<< i.should_abort_on_uncaught_toggle
129129
<< ", // should_abort_on_uncaught_toggle\n"
@@ -736,7 +736,7 @@ EnvSerializeInfo FileReader::Read() {
736736
result.immediate_info = Read<ImmediateInfo::SerializeInfo>();
737737
result.performance_state =
738738
Read<performance::PerformanceState::SerializeInfo>();
739-
result.exiting = Read<AliasedBufferIndex>();
739+
result.exit_info = Read<AliasedBufferIndex>();
740740
result.stream_base_state = Read<AliasedBufferIndex>();
741741
result.should_abort_on_uncaught_toggle = Read<AliasedBufferIndex>();
742742
result.principal_realm = Read<RealmSerializeInfo>();
@@ -757,7 +757,7 @@ size_t FileWriter::Write(const EnvSerializeInfo& data) {
757757
written_total += Write<ImmediateInfo::SerializeInfo>(data.immediate_info);
758758
written_total += Write<performance::PerformanceState::SerializeInfo>(
759759
data.performance_state);
760-
written_total += Write<AliasedBufferIndex>(data.exiting);
760+
written_total += Write<AliasedBufferIndex>(data.exit_info);
761761
written_total += Write<AliasedBufferIndex>(data.stream_base_state);
762762
written_total +=
763763
Write<AliasedBufferIndex>(data.should_abort_on_uncaught_toggle);

src/node_util.cc

+11
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,17 @@ void Initialize(Local<Object> target,
424424
V(kRejected);
425425
#undef V
426426

427+
#define V(name) \
428+
target \
429+
->Set(context, \
430+
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
431+
Integer::New(env->isolate(), Environment::ExitInfoField::name)) \
432+
.FromJust()
433+
V(kExiting);
434+
V(kExitCode);
435+
V(kHasExitCode);
436+
#undef V
437+
427438
SetMethodNoSideEffect(context, target, "getHiddenValue", GetHiddenValue);
428439
SetMethod(context, target, "setHiddenValue", SetHiddenValue);
429440
SetMethodNoSideEffect(

0 commit comments

Comments
 (0)