Skip to content

Commit c7391ee

Browse files
RaisinTentargos
authored andcommitted
src: use a typed array internally for process._exiting
This would prevent manual writes to the _exiting JS property on the process object by passing the data directly via a typed array for performance. This change partially addresses this TODO: https://github.com/nodejs/node/blob/3d575a4f1bd197c3ce669758a2a3c763462a883a/src/api/hooks.cc#L68-L71 Signed-off-by: Darshan Sen <[email protected]> PR-URL: #43883 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 6da01ff commit c7391ee

File tree

7 files changed

+68
-17
lines changed

7 files changed

+68
-17
lines changed

lib/internal/bootstrap/node.js

+19
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,32 @@ const {
5757
const config = internalBinding('config');
5858
const internalTimers = require('internal/timers');
5959
const { deprecate } = require('internal/util');
60+
const {
61+
exiting_aliased_Uint32Array,
62+
getHiddenValue,
63+
} = internalBinding('util');
6064

6165
setupProcessObject();
6266

6367
setupGlobalProxy();
6468
setupBuffer();
6569

6670
process.domain = null;
71+
{
72+
const exitingAliasedUint32Array =
73+
getHiddenValue(process, exiting_aliased_Uint32Array);
74+
ObjectDefineProperty(process, '_exiting', {
75+
__proto__: null,
76+
get() {
77+
return exitingAliasedUint32Array[0] === 1;
78+
},
79+
set(value) {
80+
exitingAliasedUint32Array[0] = value ? 1 : 0;
81+
},
82+
enumerable: true,
83+
configurable: true,
84+
});
85+
}
6786
process._exiting = false;
6887

6988
// process.config is serialized config.gypi

src/api/hooks.cc

+5-8
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,11 @@ Maybe<int> EmitProcessExit(Environment* env) {
6565
Context::Scope context_scope(context);
6666
Local<Object> process_object = env->process_object();
6767

68-
// TODO(addaleax): It might be nice to share process._exiting and
69-
// process.exitCode via getter/setter pairs that pass data directly to the
70-
// native side, so that we don't manually have to read and write JS properties
71-
// here. These getters could use e.g. a typed array for performance.
72-
if (process_object
73-
->Set(context,
74-
FIXED_ONE_BYTE_STRING(isolate, "_exiting"),
75-
True(isolate)).IsNothing()) return Nothing<int>();
68+
// TODO(addaleax): It might be nice to share process.exitCode via
69+
// getter/setter pairs that pass data directly to the native side, so that we
70+
// don't manually have to read and write JS properties here. These getters
71+
// could use e.g. a typed array for performance.
72+
env->set_exiting(true);
7673

7774
Local<String> exit_code = env->exit_code_string();
7875
Local<Value> code_v;

src/env-inl.h

+8
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,14 @@ inline bool Environment::force_context_aware() const {
362362
return options_->force_context_aware;
363363
}
364364

365+
inline void Environment::set_exiting(bool value) {
366+
exiting_[0] = value ? 1 : 0;
367+
}
368+
369+
inline AliasedUint32Array& Environment::exiting() {
370+
return exiting_;
371+
}
372+
365373
inline void Environment::set_abort_on_uncaught_exception(bool value) {
366374
options_->abort_on_uncaught_exception = value;
367375
}

src/env.cc

+8
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ Environment::Environment(IsolateData* isolate_data,
734734
exec_argv_(exec_args),
735735
argv_(args),
736736
exec_path_(GetExecPath(args)),
737+
exiting_(isolate_, 1, MAYBE_FIELD_PTR(env_info, exiting)),
737738
should_abort_on_uncaught_toggle_(
738739
isolate_,
739740
1,
@@ -840,6 +841,9 @@ void Environment::InitializeMainContext(Local<Context> context,
840841
// By default, always abort when --abort-on-uncaught-exception was passed.
841842
should_abort_on_uncaught_toggle_[0] = 1;
842843

844+
// The process is not exiting by default.
845+
set_exiting(false);
846+
843847
performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT,
844848
environment_start_time_);
845849
performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
@@ -1741,6 +1745,7 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
17411745
info.immediate_info = immediate_info_.Serialize(ctx, creator);
17421746
info.tick_info = tick_info_.Serialize(ctx, creator);
17431747
info.performance_state = performance_state_->Serialize(ctx, creator);
1748+
info.exiting = exiting_.Serialize(ctx, creator);
17441749
info.stream_base_state = stream_base_state_.Serialize(ctx, creator);
17451750
info.should_abort_on_uncaught_toggle =
17461751
should_abort_on_uncaught_toggle_.Serialize(ctx, creator);
@@ -1812,6 +1817,7 @@ std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
18121817
<< "// -- performance_state begins --\n"
18131818
<< i.performance_state << ",\n"
18141819
<< "// -- performance_state ends --\n"
1820+
<< i.exiting << ", // exiting\n"
18151821
<< i.stream_base_state << ", // stream_base_state\n"
18161822
<< i.should_abort_on_uncaught_toggle
18171823
<< ", // should_abort_on_uncaught_toggle\n"
@@ -1858,6 +1864,7 @@ void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
18581864
immediate_info_.Deserialize(ctx);
18591865
tick_info_.Deserialize(ctx);
18601866
performance_state_->Deserialize(ctx);
1867+
exiting_.Deserialize(ctx);
18611868
stream_base_state_.Deserialize(ctx);
18621869
should_abort_on_uncaught_toggle_.Deserialize(ctx);
18631870

@@ -2088,6 +2095,7 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const {
20882095
native_modules_without_cache);
20892096
tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
20902097
tracker->TrackField("exec_argv", exec_argv_);
2098+
tracker->TrackField("exiting", exiting_);
20912099
tracker->TrackField("should_abort_on_uncaught_toggle",
20922100
should_abort_on_uncaught_toggle_);
20932101
tracker->TrackField("stream_base_state", stream_base_state_);

src/env.h

+18-9
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,16 @@ class NoArrayBufferZeroFillScope {
165165
// Private symbols are per-isolate primitives but Environment proxies them
166166
// for the sake of convenience. Strings should be ASCII-only and have a
167167
// "node:" prefix to avoid name clashes with third-party code.
168-
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
169-
V(alpn_buffer_private_symbol, "node:alpnBuffer") \
170-
V(arrow_message_private_symbol, "node:arrowMessage") \
171-
V(contextify_context_private_symbol, "node:contextify:context") \
172-
V(contextify_global_private_symbol, "node:contextify:global") \
173-
V(decorated_private_symbol, "node:decorated") \
174-
V(napi_type_tag, "node:napi:type_tag") \
175-
V(napi_wrapper, "node:napi:wrapper") \
176-
V(untransferable_object_private_symbol, "node:untransferableObject") \
168+
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
169+
V(alpn_buffer_private_symbol, "node:alpnBuffer") \
170+
V(arrow_message_private_symbol, "node:arrowMessage") \
171+
V(contextify_context_private_symbol, "node:contextify:context") \
172+
V(contextify_global_private_symbol, "node:contextify:global") \
173+
V(decorated_private_symbol, "node:decorated") \
174+
V(napi_type_tag, "node:napi:type_tag") \
175+
V(napi_wrapper, "node:napi:wrapper") \
176+
V(untransferable_object_private_symbol, "node:untransferableObject") \
177+
V(exiting_aliased_Uint32Array, "node:exiting_aliased_Uint32Array")
177178

178179
// Symbols are per-isolate primitives but Environment proxies them
179180
// for the sake of convenience.
@@ -951,6 +952,7 @@ struct EnvSerializeInfo {
951952
TickInfo::SerializeInfo tick_info;
952953
ImmediateInfo::SerializeInfo immediate_info;
953954
performance::PerformanceState::SerializeInfo performance_state;
955+
AliasedBufferIndex exiting;
954956
AliasedBufferIndex stream_base_state;
955957
AliasedBufferIndex should_abort_on_uncaught_toggle;
956958

@@ -1126,6 +1128,11 @@ class Environment : public MemoryRetainer {
11261128
inline void set_force_context_aware(bool value);
11271129
inline bool force_context_aware() const;
11281130

1131+
// This is a pseudo-boolean that keeps track of whether the process is
1132+
// exiting.
1133+
inline void set_exiting(bool value);
1134+
inline AliasedUint32Array& exiting();
1135+
11291136
// This stores whether the --abort-on-uncaught-exception flag was passed
11301137
// to Node.
11311138
inline bool abort_on_uncaught_exception() const;
@@ -1515,6 +1522,8 @@ class Environment : public MemoryRetainer {
15151522
uint32_t script_id_counter_ = 0;
15161523
uint32_t function_id_counter_ = 0;
15171524

1525+
AliasedUint32Array exiting_;
1526+
15181527
AliasedUint32Array should_abort_on_uncaught_toggle_;
15191528
int should_not_abort_scope_counter_ = 0;
15201529

src/node_process_object.cc

+9
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ MaybeLocal<Object> CreateProcessObject(Environment* env) {
9191
return MaybeLocal<Object>();
9292
}
9393

94+
// process[exiting_aliased_Uint32Array]
95+
if (process
96+
->SetPrivate(context,
97+
env->exiting_aliased_Uint32Array(),
98+
env->exiting().GetJSArray())
99+
.IsNothing()) {
100+
return {};
101+
}
102+
94103
// process.version
95104
READONLY_PROPERTY(process,
96105
"version",

typings/internalBinding/util.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ declare function InternalBinding(binding: 'util'): {
1717
napi_type_tag: 5;
1818
napi_wrapper: 6;
1919
untransferable_object_private_symbol: 7;
20+
exiting_aliased_Uint32Array: 8;
2021

2122
kPending: 0;
2223
kFulfilled: 1;

0 commit comments

Comments
 (0)