Browse Source

lib: reduce process.binding() calls

This commit better handles calls to process.binding() in lib/ by
no longer lazy loading the bindings (the load times themselves are
rather miniscule compared to the load time of V8) and never reloading
the bindings (which is 172 times slower than referencing a variable with
the same value).

PR-URL: https://github.com/iojs/io.js/pull/1367
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
v1.8.0-commit
Brendan Ashworth 10 years ago
parent
commit
1219e7466c
  1. 16
      lib/_tls_wrap.js
  2. 75
      lib/child_process.js
  3. 4
      lib/cluster.js
  4. 1
      lib/dgram.js
  5. 4
      lib/fs.js
  6. 31
      lib/net.js
  7. 3
      lib/tls.js
  8. 4
      lib/util.js

16
lib/_tls_wrap.js

@ -12,18 +12,8 @@ const Duplex = require('stream').Duplex;
const debug = util.debuglog('tls'); const debug = util.debuglog('tls');
const Timer = process.binding('timer_wrap').Timer; const Timer = process.binding('timer_wrap').Timer;
const tls_wrap = process.binding('tls_wrap'); const tls_wrap = process.binding('tls_wrap');
const TCP = process.binding('tcp_wrap').TCP;
// constructor for lazy loading const Pipe = process.binding('pipe_wrap').Pipe;
function createTCP() {
var TCP = process.binding('tcp_wrap').TCP;
return new TCP();
}
// constructor for lazy loading
function createPipe() {
var Pipe = process.binding('pipe_wrap').Pipe;
return new Pipe();
}
function onhandshakestart() { function onhandshakestart() {
debug('onhandshakestart'); debug('onhandshakestart');
@ -284,7 +274,7 @@ TLSSocket.prototype._wrapHandle = function(handle) {
var options = this._tlsOptions; var options = this._tlsOptions;
if (!handle) { if (!handle) {
handle = options.pipe ? createPipe() : createTCP(); handle = options.pipe ? new Pipe() : new TCP();
handle.owner = this; handle.owner = this;
} }

75
lib/child_process.js

@ -7,48 +7,18 @@ const dgram = require('dgram');
const assert = require('assert'); const assert = require('assert');
const util = require('util'); const util = require('util');
const debug = util.debuglog('child_process'); const debug = util.debuglog('child_process');
const constants = require('constants');
const Process = process.binding('process_wrap').Process; const Process = process.binding('process_wrap').Process;
const WriteWrap = process.binding('stream_wrap').WriteWrap; const WriteWrap = process.binding('stream_wrap').WriteWrap;
const uv = process.binding('uv'); const uv = process.binding('uv');
const spawn_sync = process.binding('spawn_sync');
var spawn_sync; // Lazy-loaded process.binding('spawn_sync') const Pipe = process.binding('pipe_wrap').Pipe;
var constants; // Lazy-loaded process.binding('constants') const TTY = process.binding('tty_wrap').TTY;
const TCP = process.binding('tcp_wrap').TCP;
const UDP = process.binding('udp_wrap').UDP;
const errnoException = util._errnoException; const errnoException = util._errnoException;
var handleWraps = {};
function handleWrapGetter(name, callback) {
var cons;
Object.defineProperty(handleWraps, name, {
get: function() {
if (cons !== undefined) return cons;
return cons = callback();
}
});
}
handleWrapGetter('Pipe', function() {
return process.binding('pipe_wrap').Pipe;
});
handleWrapGetter('TTY', function() {
return process.binding('tty_wrap').TTY;
});
handleWrapGetter('TCP', function() {
return process.binding('tcp_wrap').TCP;
});
handleWrapGetter('UDP', function() {
return process.binding('udp_wrap').UDP;
});
// constructors for lazy loading
function createPipe(ipc) {
return new handleWraps.Pipe(ipc);
}
function createSocket(pipe, readable) { function createSocket(pipe, readable) {
var s = new net.Socket({ handle: pipe }); var s = new net.Socket({ handle: pipe });
@ -417,12 +387,11 @@ function setupChannel(target, channel) {
message.type = 'net.Socket'; message.type = 'net.Socket';
} else if (handle instanceof net.Server) { } else if (handle instanceof net.Server) {
message.type = 'net.Server'; message.type = 'net.Server';
} else if (handle instanceof process.binding('tcp_wrap').TCP || } else if (handle instanceof TCP || handle instanceof Pipe) {
handle instanceof process.binding('pipe_wrap').Pipe) {
message.type = 'net.Native'; message.type = 'net.Native';
} else if (handle instanceof dgram.Socket) { } else if (handle instanceof dgram.Socket) {
message.type = 'dgram.Socket'; message.type = 'dgram.Socket';
} else if (handle instanceof process.binding('udp_wrap').UDP) { } else if (handle instanceof UDP) {
message.type = 'dgram.Native'; message.type = 'dgram.Native';
} else { } else {
throw new TypeError("This handle type can't be sent"); throw new TypeError("This handle type can't be sent");
@ -564,7 +533,7 @@ exports.fork = function(modulePath /*, args, options*/) {
exports._forkChild = function(fd) { exports._forkChild = function(fd) {
// set process.send() // set process.send()
var p = createPipe(true); var p = new Pipe(true);
p.open(fd); p.open(fd);
p.unref(); p.unref();
setupChannel(process, p); setupChannel(process, p);
@ -852,7 +821,7 @@ function _validateStdio(stdio, sync) {
}; };
if (!sync) if (!sync)
a.handle = createPipe(); a.handle = new Pipe();
acc.push(a); acc.push(a);
} else if (stdio === 'ipc') { } else if (stdio === 'ipc') {
@ -865,7 +834,7 @@ function _validateStdio(stdio, sync) {
throw new Error('You cannot use IPC with synchronous forks'); throw new Error('You cannot use IPC with synchronous forks');
} }
ipc = createPipe(true); ipc = new Pipe(true);
ipcFd = i; ipcFd = i;
acc.push({ acc.push({
@ -989,10 +958,6 @@ function maybeClose(subprocess) {
function ChildProcess() { function ChildProcess() {
EventEmitter.call(this); EventEmitter.call(this);
// Initialize TCPWrap and PipeWrap
process.binding('tcp_wrap');
process.binding('pipe_wrap');
var self = this; var self = this;
this._closesNeeded = 1; this._closesNeeded = 1;
@ -1072,10 +1037,10 @@ function flushStdio(subprocess) {
function getHandleWrapType(stream) { function getHandleWrapType(stream) {
if (stream instanceof handleWraps.Pipe) return 'pipe'; if (stream instanceof Pipe) return 'pipe';
if (stream instanceof handleWraps.TTY) return 'tty'; if (stream instanceof TTY) return 'tty';
if (stream instanceof handleWraps.TCP) return 'tcp'; if (stream instanceof TCP) return 'tcp';
if (stream instanceof handleWraps.UDP) return 'udp'; if (stream instanceof UDP) return 'udp';
return false; return false;
} }
@ -1177,10 +1142,6 @@ ChildProcess.prototype.spawn = function(options) {
ChildProcess.prototype.kill = function(sig) { ChildProcess.prototype.kill = function(sig) {
var signal; var signal;
if (!constants) {
constants = process.binding('constants');
}
if (sig === 0) { if (sig === 0) {
signal = 0; signal = 0;
} else if (!sig) { } else if (!sig) {
@ -1230,9 +1191,6 @@ function lookupSignal(signal) {
if (typeof signal === 'number') if (typeof signal === 'number')
return signal; return signal;
if (!constants)
constants = process.binding('constants');
if (!(signal in constants)) if (!(signal in constants))
throw new Error('Unknown signal: ' + signal); throw new Error('Unknown signal: ' + signal);
@ -1280,9 +1238,6 @@ function spawnSync(/*file, args, options*/) {
} }
} }
if (!spawn_sync)
spawn_sync = process.binding('spawn_sync');
var result = spawn_sync.spawn(options); var result = spawn_sync.spawn(options);
if (result.output && options.encoding) { if (result.output && options.encoding) {

4
lib/cluster.js

@ -9,6 +9,8 @@ const util = require('util');
const SCHED_NONE = 1; const SCHED_NONE = 1;
const SCHED_RR = 2; const SCHED_RR = 2;
const uv = process.binding('uv');
const cluster = new EventEmitter; const cluster = new EventEmitter;
module.exports = cluster; module.exports = cluster;
cluster.Worker = Worker; cluster.Worker = Worker;
@ -142,7 +144,7 @@ RoundRobinHandle.prototype.add = function(worker, send) {
// Hack: translate 'EADDRINUSE' error string back to numeric error code. // Hack: translate 'EADDRINUSE' error string back to numeric error code.
// It works but ideally we'd have some backchannel between the net and // It works but ideally we'd have some backchannel between the net and
// cluster modules for stuff like this. // cluster modules for stuff like this.
var errno = process.binding('uv')['UV_' + err.errno]; var errno = uv['UV_' + err.errno];
send(errno, null); send(errno, null);
}); });
}; };

1
lib/dgram.js

@ -146,7 +146,6 @@ Socket.prototype.bind = function(port /*, address, callback*/) {
if (typeof arguments[arguments.length - 1] === 'function') if (typeof arguments[arguments.length - 1] === 'function')
self.once('listening', arguments[arguments.length - 1]); self.once('listening', arguments[arguments.length - 1]);
const UDP = process.binding('udp_wrap').UDP;
if (port instanceof UDP) { if (port instanceof UDP) {
replaceHandle(self, port); replaceHandle(self, port);
startListening(self); startListening(self);

4
lib/fs.js

@ -8,11 +8,12 @@ const util = require('util');
const pathModule = require('path'); const pathModule = require('path');
const binding = process.binding('fs'); const binding = process.binding('fs');
const constants = process.binding('constants'); const constants = require('constants');
const fs = exports; const fs = exports;
const Stream = require('stream').Stream; const Stream = require('stream').Stream;
const EventEmitter = require('events').EventEmitter; const EventEmitter = require('events').EventEmitter;
const FSReqWrap = binding.FSReqWrap; const FSReqWrap = binding.FSReqWrap;
const FSEvent = process.binding('fs_event_wrap').FSEvent;
const Readable = Stream.Readable; const Readable = Stream.Readable;
const Writable = Stream.Writable; const Writable = Stream.Writable;
@ -1201,7 +1202,6 @@ function FSWatcher() {
EventEmitter.call(this); EventEmitter.call(this);
var self = this; var self = this;
var FSEvent = process.binding('fs_event_wrap').FSEvent;
this._handle = new FSEvent(); this._handle = new FSEvent();
this._handle.owner = this; this._handle.owner = this;

31
lib/net.js

@ -7,8 +7,10 @@ const util = require('util');
const assert = require('assert'); const assert = require('assert');
const cares = process.binding('cares_wrap'); const cares = process.binding('cares_wrap');
const uv = process.binding('uv'); const uv = process.binding('uv');
const Pipe = process.binding('pipe_wrap').Pipe;
const TTYWrap = process.binding('tty_wrap');
const TCP = process.binding('tcp_wrap').TCP;
const Pipe = process.binding('pipe_wrap').Pipe;
const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap; const TCPConnectWrap = process.binding('tcp_wrap').TCPConnectWrap;
const PipeConnectWrap = process.binding('pipe_wrap').PipeConnectWrap; const PipeConnectWrap = process.binding('pipe_wrap').PipeConnectWrap;
const ShutdownWrap = process.binding('stream_wrap').ShutdownWrap; const ShutdownWrap = process.binding('stream_wrap').ShutdownWrap;
@ -21,23 +23,10 @@ const exceptionWithHostPort = util._exceptionWithHostPort;
function noop() {} function noop() {}
// constructor for lazy loading
function createPipe() {
return new Pipe();
}
// constructor for lazy loading
function createTCP() {
var TCP = process.binding('tcp_wrap').TCP;
return new TCP();
}
function createHandle(fd) { function createHandle(fd) {
var tty = process.binding('tty_wrap'); var type = TTYWrap.guessHandleType(fd);
var type = tty.guessHandleType(fd); if (type === 'PIPE') return new Pipe();
if (type === 'PIPE') return createPipe(); if (type === 'TCP') return new TCP();
if (type === 'TCP') return createTCP();
throw new TypeError('Unsupported fd type: ' + type); throw new TypeError('Unsupported fd type: ' + type);
} }
@ -873,7 +862,7 @@ Socket.prototype.connect = function(options, cb) {
debug('pipe', pipe, options.path); debug('pipe', pipe, options.path);
if (!this._handle) { if (!this._handle) {
this._handle = pipe ? createPipe() : createTCP(); this._handle = pipe ? new Pipe() : new TCP();
initSocketHandle(this); initSocketHandle(this);
} }
@ -1095,7 +1084,7 @@ var createServerHandle = exports._createServerHandle =
handle.writable = true; handle.writable = true;
assert(!address && !port); assert(!address && !port);
} else if (port === -1 && addressType === -1) { } else if (port === -1 && addressType === -1) {
handle = createPipe(); handle = new Pipe();
if (process.platform === 'win32') { if (process.platform === 'win32') {
var instances = parseInt(process.env.NODE_PENDING_PIPE_INSTANCES); var instances = parseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
if (!isNaN(instances)) { if (!isNaN(instances)) {
@ -1103,7 +1092,7 @@ var createServerHandle = exports._createServerHandle =
} }
} }
} else { } else {
handle = createTCP(); handle = new TCP();
isTCP = true; isTCP = true;
} }
@ -1255,8 +1244,6 @@ Server.prototype.listen = function() {
// When the ip is omitted it can be the second argument. // When the ip is omitted it can be the second argument.
var backlog = toNumber(arguments[1]) || toNumber(arguments[2]); var backlog = toNumber(arguments[1]) || toNumber(arguments[2]);
const TCP = process.binding('tcp_wrap').TCP;
if (arguments.length === 0 || typeof arguments[0] === 'function') { if (arguments.length === 0 || typeof arguments[0] === 'function') {
// Bind to a random port. // Bind to a random port.
listen(self, null, 0, null, backlog); listen(self, null, 0, null, backlog);

3
lib/tls.js

@ -3,6 +3,7 @@
const net = require('net'); const net = require('net');
const url = require('url'); const url = require('url');
const util = require('util'); const util = require('util');
const binding = process.binding('crypto');
// Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
// every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more
@ -35,7 +36,7 @@ exports.DEFAULT_CIPHERS = [
exports.DEFAULT_ECDH_CURVE = 'prime256v1'; exports.DEFAULT_ECDH_CURVE = 'prime256v1';
exports.getCiphers = function() { exports.getCiphers = function() {
const names = process.binding('crypto').getSSLCiphers(); const names = binding.getSSLCiphers();
// Drop all-caps names in favor of their lowercase aliases, // Drop all-caps names in favor of their lowercase aliases,
var ctx = {}; var ctx = {};
names.forEach(function(name) { names.forEach(function(name) {

4
lib/util.js

@ -1,5 +1,7 @@
'use strict'; 'use strict';
const uv = process.binding('uv');
const formatRegExp = /%[sdj%]/g; const formatRegExp = /%[sdj%]/g;
exports.format = function(f) { exports.format = function(f) {
if (typeof f !== 'string') { if (typeof f !== 'string') {
@ -739,9 +741,7 @@ exports.pump = exports.deprecate(function(readStream, writeStream, callback) {
}, 'util.pump(): Use readableStream.pipe() instead'); }, 'util.pump(): Use readableStream.pipe() instead');
var uv;
exports._errnoException = function(err, syscall, original) { exports._errnoException = function(err, syscall, original) {
if (uv === undefined) uv = process.binding('uv');
var errname = uv.errname(err); var errname = uv.errname(err);
var message = syscall + ' ' + errname; var message = syscall + ' ' + errname;
if (original) if (original)

Loading…
Cancel
Save