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 Timer = process.binding('timer_wrap').Timer;
const tls_wrap = process.binding('tls_wrap');
// constructor for lazy loading
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();
}
const TCP = process.binding('tcp_wrap').TCP;
const Pipe = process.binding('pipe_wrap').Pipe;
function onhandshakestart() {
debug('onhandshakestart');
@ -284,7 +274,7 @@ TLSSocket.prototype._wrapHandle = function(handle) {
var options = this._tlsOptions;
if (!handle) {
handle = options.pipe ? createPipe() : createTCP();
handle = options.pipe ? new Pipe() : new TCP();
handle.owner = this;
}

75
lib/child_process.js

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

4
lib/cluster.js

@ -9,6 +9,8 @@ const util = require('util');
const SCHED_NONE = 1;
const SCHED_RR = 2;
const uv = process.binding('uv');
const cluster = new EventEmitter;
module.exports = cluster;
cluster.Worker = Worker;
@ -142,7 +144,7 @@ RoundRobinHandle.prototype.add = function(worker, send) {
// Hack: translate 'EADDRINUSE' error string back to numeric error code.
// It works but ideally we'd have some backchannel between the net and
// cluster modules for stuff like this.
var errno = process.binding('uv')['UV_' + err.errno];
var errno = uv['UV_' + err.errno];
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')
self.once('listening', arguments[arguments.length - 1]);
const UDP = process.binding('udp_wrap').UDP;
if (port instanceof UDP) {
replaceHandle(self, port);
startListening(self);

4
lib/fs.js

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

31
lib/net.js

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

3
lib/tls.js

@ -3,6 +3,7 @@
const net = require('net');
const url = require('url');
const util = require('util');
const binding = process.binding('crypto');
// Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
// 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.getCiphers = function() {
const names = process.binding('crypto').getSSLCiphers();
const names = binding.getSSLCiphers();
// Drop all-caps names in favor of their lowercase aliases,
var ctx = {};
names.forEach(function(name) {

4
lib/util.js

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

Loading…
Cancel
Save