Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] backport node.cc changes #21798

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
3 changes: 3 additions & 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 All @@ -282,13 +283,15 @@
'src/node_constants.cc',
'src/node_contextify.cc',
'src/node_debug_options.cc',
'src/node_encoding.cc',
'src/node_file.cc',
'src/node_http2.cc',
'src/node_http_parser.cc',
'src/node_os.cc',
'src/node_platform.cc',
'src/node_perf.cc',
'src/node_postmortem_metadata.cc',
'src/node_process.cc',
'src/node_serdes.cc',
'src/node_trace_events.cc',
'src/node_url.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