Skip to content

Commit 6390d7f

Browse files
jasnellMylesBorins
authored andcommitted
src: refactor bootstrap to use bootstrap object
Backport-PR-URL: #21798 PR-URL: #20917 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com>
1 parent 5026ab4 commit 6390d7f

File tree

8 files changed

+196
-136
lines changed

8 files changed

+196
-136
lines changed

lib/internal/bootstrap_node.js

+20-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,19 @@
77

88
'use strict';
99

10-
(function(process) {
10+
(function(process,
11+
// bootstrapper properties... destructured to
12+
// avoid retaining a reference to the bootstrap
13+
// object.
14+
{
15+
_setupProcessObject,
16+
_setupNextTick,
17+
_setupPromises,
18+
_cpuUsage,
19+
_hrtime,
20+
_memoryUsage,
21+
_rawDebug
22+
}) {
1123

1224
function startup() {
1325
const EventEmitter = NativeModule.require('events');
@@ -31,7 +43,8 @@
3143
_process.setupConfig(NativeModule._source);
3244
_process.setupSignalHandlers();
3345
NativeModule.require('internal/process/warning').setup();
34-
NativeModule.require('internal/process/next_tick').setup();
46+
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
47+
_setupPromises);
3548
NativeModule.require('internal/process/stdio').setup();
3649

3750
const perf = process.binding('performance');
@@ -47,10 +60,10 @@
4760
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END
4861
} = perf.constants;
4962

50-
_process.setup_hrtime();
63+
_process.setup_hrtime(_hrtime);
5164
_process.setup_performance();
52-
_process.setup_cpuUsage();
53-
_process.setupMemoryUsage();
65+
_process.setup_cpuUsage(_cpuUsage);
66+
_process.setupMemoryUsage(_memoryUsage);
5467
_process.setupKillAndExit();
5568
if (global.__coverage__)
5669
NativeModule.require('internal/process/write-coverage').setup();
@@ -59,7 +72,7 @@
5972
NativeModule.require('internal/inspector_async_hook').setup();
6073

6174
_process.setupChannel();
62-
_process.setupRawDebug();
75+
_process.setupRawDebug(_rawDebug);
6376

6477
const browserGlobals = !process._noBrowserGlobals;
6578
if (browserGlobals) {
@@ -244,7 +257,7 @@
244257
}
245258

246259
function setupProcessObject() {
247-
process._setupProcessObject(pushValueToArray);
260+
_setupProcessObject(pushValueToArray);
248261

249262
function pushValueToArray() {
250263
for (var i = 0; i < arguments.length; i++)

lib/internal/process.js

+6-12
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ function setup_performance() {
1717
}
1818

1919
// Set up the process.cpuUsage() function.
20-
function setup_cpuUsage() {
21-
// Get the native function, which will be replaced with a JS version.
22-
const _cpuUsage = process.cpuUsage;
23-
20+
function setup_cpuUsage(_cpuUsage) {
2421
// Create the argument array that will be passed to the native function.
2522
const cpuValues = new Float64Array(2);
2623

@@ -71,8 +68,7 @@ function setup_cpuUsage() {
7168
// The 3 entries filled in by the original process.hrtime contains
7269
// the upper/lower 32 bits of the second part of the value,
7370
// and the remaining nanoseconds of the value.
74-
function setup_hrtime() {
75-
const _hrtime = process.hrtime;
71+
function setup_hrtime(_hrtime) {
7672
const hrValues = new Uint32Array(3);
7773

7874
process.hrtime = function hrtime(time) {
@@ -96,12 +92,11 @@ function setup_hrtime() {
9692
};
9793
}
9894

99-
function setupMemoryUsage() {
100-
const memoryUsage_ = process.memoryUsage;
95+
function setupMemoryUsage(_memoryUsage) {
10196
const memValues = new Float64Array(4);
10297

10398
process.memoryUsage = function memoryUsage() {
104-
memoryUsage_(memValues);
99+
_memoryUsage(memValues);
105100
return {
106101
rss: memValues[0],
107102
heapTotal: memValues[1],
@@ -251,10 +246,9 @@ function setupChannel() {
251246
}
252247

253248

254-
function setupRawDebug() {
255-
const rawDebug = process._rawDebug;
249+
function setupRawDebug(_rawDebug) {
256250
process._rawDebug = function() {
257-
rawDebug(util.format.apply(null, arguments));
251+
_rawDebug(util.format.apply(null, arguments));
258252
};
259253
}
260254

lib/internal/process/next_tick.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@ class NextTickQueue {
4646
}
4747
}
4848

49-
function setupNextTick() {
49+
function setupNextTick(_setupNextTick, _setupPromises) {
5050
const async_wrap = process.binding('async_wrap');
5151
const async_hooks = require('internal/async_hooks');
5252
const promises = require('internal/process/promises');
5353
const errors = require('internal/errors');
54-
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
54+
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks,
55+
_setupPromises);
5556
const getDefaultTriggerAsyncId = async_hooks.getDefaultTriggerAsyncId;
5657
// Two arrays that share state between C++ and JS.
5758
const { async_hook_fields, async_id_fields } = async_wrap;
@@ -81,7 +82,7 @@ function setupNextTick() {
8182
// This tickInfo thing is used so that the C++ code in src/node.cc
8283
// can have easy access to our nextTick state, and avoid unnecessary
8384
// calls into JS land.
84-
const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks);
85+
const tickInfo = _setupNextTick(_tickCallback, _runMicrotasks);
8586

8687
_runMicrotasks = _runMicrotasks.runMicrotasks;
8788

lib/internal/process/promises.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ function getAsynchronousRejectionWarningObject(uid) {
1515
`asynchronously (rejection id: ${uid})`);
1616
}
1717

18-
function setupPromises(scheduleMicrotasks) {
18+
function setupPromises(scheduleMicrotasks, _setupPromises) {
1919
let deprecationWarned = false;
2020

21-
process._setupPromises(function(event, promise, reason) {
21+
_setupPromises(function(event, promise, reason) {
2222
if (event === promiseRejectEvent.unhandled)
2323
unhandledRejection(promise, reason);
2424
else if (event === promiseRejectEvent.handled)

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@
265265

266266
'sources': [
267267
'src/async_wrap.cc',
268+
'src/bootstrapper.cc',
268269
'src/cares_wrap.cc',
269270
'src/connection_wrap.cc',
270271
'src/connect_wrap.cc',

src/bootstrapper.cc

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include "node.h"
2+
#include "env-inl.h"
3+
#include "node_internals.h"
4+
#include "v8.h"
5+
6+
namespace node {
7+
8+
using v8::Array;
9+
using v8::ArrayBuffer;
10+
using v8::Function;
11+
using v8::FunctionCallbackInfo;
12+
using v8::Integer;
13+
using v8::Isolate;
14+
using v8::Local;
15+
using v8::Object;
16+
using v8::Promise;
17+
using v8::PromiseRejectMessage;
18+
using v8::Uint32Array;
19+
using v8::Value;
20+
21+
void SetupProcessObject(const FunctionCallbackInfo<Value>& args) {
22+
Environment* env = Environment::GetCurrent(args);
23+
CHECK(args[0]->IsFunction());
24+
env->set_push_values_to_array_function(args[0].As<Function>());
25+
}
26+
27+
void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
28+
args.GetIsolate()->RunMicrotasks();
29+
}
30+
31+
void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
32+
Environment* env = Environment::GetCurrent(args);
33+
34+
CHECK(args[0]->IsFunction());
35+
CHECK(args[1]->IsObject());
36+
37+
env->set_tick_callback_function(args[0].As<Function>());
38+
39+
env->SetMethod(args[1].As<Object>(), "runMicrotasks", RunMicrotasks);
40+
41+
// Values use to cross communicate with processNextTick.
42+
uint32_t* const fields = env->tick_info()->fields();
43+
uint32_t const fields_count = env->tick_info()->fields_count();
44+
45+
Local<ArrayBuffer> array_buffer =
46+
ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count);
47+
48+
args.GetReturnValue().Set(Uint32Array::New(array_buffer, 0, fields_count));
49+
}
50+
51+
void PromiseRejectCallback(PromiseRejectMessage message) {
52+
Local<Promise> promise = message.GetPromise();
53+
Isolate* isolate = promise->GetIsolate();
54+
Local<Value> value = message.GetValue();
55+
Local<Integer> event = Integer::New(isolate, message.GetEvent());
56+
57+
Environment* env = Environment::GetCurrent(isolate);
58+
Local<Function> callback = env->promise_reject_function();
59+
60+
if (value.IsEmpty())
61+
value = Undefined(isolate);
62+
63+
Local<Value> args[] = { event, promise, value };
64+
Local<Object> process = env->process_object();
65+
66+
callback->Call(process, arraysize(args), args);
67+
}
68+
69+
void SetupPromises(const FunctionCallbackInfo<Value>& args) {
70+
Environment* env = Environment::GetCurrent(args);
71+
Isolate* isolate = env->isolate();
72+
73+
CHECK(args[0]->IsFunction());
74+
75+
isolate->SetPromiseRejectCallback(PromiseRejectCallback);
76+
env->set_promise_reject_function(args[0].As<Function>());
77+
}
78+
79+
#define BOOTSTRAP_METHOD(name, fn) env->SetMethod(bootstrapper, #name, fn)
80+
81+
// The Bootstrapper object is an ephemeral object that is used only during
82+
// the bootstrap process of the Node.js environment. A reference to the
83+
// bootstrap object must not be kept around after the bootstrap process
84+
// completes so that it can be gc'd as soon as possible.
85+
void SetupBootstrapObject(Environment* env,
86+
Local<Object> bootstrapper) {
87+
BOOTSTRAP_METHOD(_setupProcessObject, SetupProcessObject);
88+
BOOTSTRAP_METHOD(_setupNextTick, SetupNextTick);
89+
BOOTSTRAP_METHOD(_setupPromises, SetupPromises);
90+
BOOTSTRAP_METHOD(_cpuUsage, CPUUsage);
91+
BOOTSTRAP_METHOD(_hrtime, Hrtime);
92+
BOOTSTRAP_METHOD(_memoryUsage, MemoryUsage);
93+
BOOTSTRAP_METHOD(_rawDebug, RawDebug);
94+
}
95+
#undef BOOTSTRAP_METHOD
96+
97+
} // namespace node

0 commit comments

Comments
 (0)