Skip to content

Commit

Permalink
src: refactor bootstrap to use bootstrap object
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jasnell authored and rvagg committed Aug 16, 2018
1 parent 4911c4e commit 54ea1cc
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 136 deletions.
27 changes: 20 additions & 7 deletions lib/internal/bootstrap_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@

'use strict';

(function(process) {
(function(process,
// bootstrapper properties... destructured to
// avoid retaining a reference to the bootstrap
// object.
{
_setupProcessObject,
_setupNextTick,
_setupPromises,
_cpuUsage,
_hrtime,
_memoryUsage,
_rawDebug
}) {

function startup() {
const EventEmitter = NativeModule.require('events');
Expand All @@ -31,7 +43,8 @@
_process.setupConfig(NativeModule._source);
_process.setupSignalHandlers();
NativeModule.require('internal/process/warning').setup();
NativeModule.require('internal/process/next_tick').setup();
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
_setupPromises);
NativeModule.require('internal/process/stdio').setup();

const perf = process.binding('performance');
Expand All @@ -47,10 +60,10 @@
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END
} = perf.constants;

_process.setup_hrtime();
_process.setup_hrtime(_hrtime);
_process.setup_performance();
_process.setup_cpuUsage();
_process.setupMemoryUsage();
_process.setup_cpuUsage(_cpuUsage);
_process.setupMemoryUsage(_memoryUsage);
_process.setupKillAndExit();
if (global.__coverage__)
NativeModule.require('internal/process/write-coverage').setup();
Expand All @@ -59,7 +72,7 @@
NativeModule.require('internal/inspector_async_hook').setup();

_process.setupChannel();
_process.setupRawDebug();
_process.setupRawDebug(_rawDebug);

const browserGlobals = !process._noBrowserGlobals;
if (browserGlobals) {
Expand Down Expand Up @@ -244,7 +257,7 @@
}

function setupProcessObject() {
process._setupProcessObject(pushValueToArray);
_setupProcessObject(pushValueToArray);

function pushValueToArray() {
for (var i = 0; i < arguments.length; i++)
Expand Down
18 changes: 6 additions & 12 deletions lib/internal/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ function setup_performance() {
}

// Set up the process.cpuUsage() function.
function setup_cpuUsage() {
// Get the native function, which will be replaced with a JS version.
const _cpuUsage = process.cpuUsage;

function setup_cpuUsage(_cpuUsage) {
// Create the argument array that will be passed to the native function.
const cpuValues = new Float64Array(2);

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

process.hrtime = function hrtime(time) {
Expand All @@ -96,12 +92,11 @@ function setup_hrtime() {
};
}

function setupMemoryUsage() {
const memoryUsage_ = process.memoryUsage;
function setupMemoryUsage(_memoryUsage) {
const memValues = new Float64Array(4);

process.memoryUsage = function memoryUsage() {
memoryUsage_(memValues);
_memoryUsage(memValues);
return {
rss: memValues[0],
heapTotal: memValues[1],
Expand Down Expand Up @@ -251,10 +246,9 @@ function setupChannel() {
}


function setupRawDebug() {
const rawDebug = process._rawDebug;
function setupRawDebug(_rawDebug) {
process._rawDebug = function() {
rawDebug(util.format.apply(null, arguments));
_rawDebug(util.format.apply(null, arguments));
};
}

Expand Down
7 changes: 4 additions & 3 deletions lib/internal/process/next_tick.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ class NextTickQueue {
}
}

function setupNextTick() {
function setupNextTick(_setupNextTick, _setupPromises) {
const async_wrap = process.binding('async_wrap');
const async_hooks = require('internal/async_hooks');
const promises = require('internal/process/promises');
const errors = require('internal/errors');
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks,
_setupPromises);
const getDefaultTriggerAsyncId = async_hooks.getDefaultTriggerAsyncId;
// Two arrays that share state between C++ and JS.
const { async_hook_fields, async_id_fields } = async_wrap;
Expand Down Expand Up @@ -81,7 +82,7 @@ function setupNextTick() {
// This tickInfo thing is used so that the C++ code in src/node.cc
// can have easy access to our nextTick state, and avoid unnecessary
// calls into JS land.
const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks);
const tickInfo = _setupNextTick(_tickCallback, _runMicrotasks);

_runMicrotasks = _runMicrotasks.runMicrotasks;

Expand Down
4 changes: 2 additions & 2 deletions lib/internal/process/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ function getAsynchronousRejectionWarningObject(uid) {
`asynchronously (rejection id: ${uid})`);
}

function setupPromises(scheduleMicrotasks) {
function setupPromises(scheduleMicrotasks, _setupPromises) {
let deprecationWarned = false;

process._setupPromises(function(event, promise, reason) {
_setupPromises(function(event, promise, reason) {
if (event === promiseRejectEvent.unhandled)
unhandledRejection(promise, reason);
else if (event === promiseRejectEvent.handled)
Expand Down
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@

'sources': [
'src/async_wrap.cc',
'src/bootstrapper.cc',
'src/cares_wrap.cc',
'src/connection_wrap.cc',
'src/connect_wrap.cc',
Expand Down
97 changes: 97 additions & 0 deletions src/bootstrapper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "node.h"
#include "env-inl.h"
#include "node_internals.h"
#include "v8.h"

namespace node {

using v8::Array;
using v8::ArrayBuffer;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Promise;
using v8::PromiseRejectMessage;
using v8::Uint32Array;
using v8::Value;

void SetupProcessObject(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsFunction());
env->set_push_values_to_array_function(args[0].As<Function>());
}

void RunMicrotasks(const FunctionCallbackInfo<Value>& args) {
args.GetIsolate()->RunMicrotasks();
}

void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

CHECK(args[0]->IsFunction());
CHECK(args[1]->IsObject());

env->set_tick_callback_function(args[0].As<Function>());

env->SetMethod(args[1].As<Object>(), "runMicrotasks", RunMicrotasks);

// Values use to cross communicate with processNextTick.
uint32_t* const fields = env->tick_info()->fields();
uint32_t const fields_count = env->tick_info()->fields_count();

Local<ArrayBuffer> array_buffer =
ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count);

args.GetReturnValue().Set(Uint32Array::New(array_buffer, 0, fields_count));
}

void PromiseRejectCallback(PromiseRejectMessage message) {
Local<Promise> promise = message.GetPromise();
Isolate* isolate = promise->GetIsolate();
Local<Value> value = message.GetValue();
Local<Integer> event = Integer::New(isolate, message.GetEvent());

Environment* env = Environment::GetCurrent(isolate);
Local<Function> callback = env->promise_reject_function();

if (value.IsEmpty())
value = Undefined(isolate);

Local<Value> args[] = { event, promise, value };
Local<Object> process = env->process_object();

callback->Call(process, arraysize(args), args);
}

void SetupPromises(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();

CHECK(args[0]->IsFunction());

isolate->SetPromiseRejectCallback(PromiseRejectCallback);
env->set_promise_reject_function(args[0].As<Function>());
}

#define BOOTSTRAP_METHOD(name, fn) env->SetMethod(bootstrapper, #name, fn)

// The Bootstrapper object is an ephemeral object that is used only during
// the bootstrap process of the Node.js environment. A reference to the
// bootstrap object must not be kept around after the bootstrap process
// completes so that it can be gc'd as soon as possible.
void SetupBootstrapObject(Environment* env,
Local<Object> bootstrapper) {
BOOTSTRAP_METHOD(_setupProcessObject, SetupProcessObject);
BOOTSTRAP_METHOD(_setupNextTick, SetupNextTick);
BOOTSTRAP_METHOD(_setupPromises, SetupPromises);
BOOTSTRAP_METHOD(_cpuUsage, CPUUsage);
BOOTSTRAP_METHOD(_hrtime, Hrtime);
BOOTSTRAP_METHOD(_memoryUsage, MemoryUsage);
BOOTSTRAP_METHOD(_rawDebug, RawDebug);
}
#undef BOOTSTRAP_METHOD

} // namespace node
Loading

0 comments on commit 54ea1cc

Please sign in to comment.