lib: use Object.create(null) directly

After V8 5.6, using Object.create(null) directly is now faster than
using a constructor for map-like objects.

PR-URL: https://github.com/nodejs/node/pull/11930
Refs: https://github.com/emberjs/ember.js/issues/15001
Refs: https://crrev.com/532c16eca071df3ec8eed394dcebb932ef584ee6
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Timothy Gu 2017-03-19 16:11:10 -07:00
parent 14a91957f8
commit cfc8422a68
6 changed files with 19 additions and 34 deletions

View File

@ -31,7 +31,6 @@ const common = require('_http_common');
const checkIsHttpToken = common._checkIsHttpToken; const checkIsHttpToken = common._checkIsHttpToken;
const checkInvalidHeaderChar = common._checkInvalidHeaderChar; const checkInvalidHeaderChar = common._checkInvalidHeaderChar;
const outHeadersKey = require('internal/http').outHeadersKey; const outHeadersKey = require('internal/http').outHeadersKey;
const StorageObject = require('internal/querystring').StorageObject;
const CRLF = common.CRLF; const CRLF = common.CRLF;
const debug = common.debug; const debug = common.debug;
@ -143,7 +142,7 @@ Object.defineProperty(OutgoingMessage.prototype, '_headerNames', {
get: function() { get: function() {
const headers = this[outHeadersKey]; const headers = this[outHeadersKey];
if (headers) { if (headers) {
const out = new StorageObject(); const out = Object.create(null);
const keys = Object.keys(headers); const keys = Object.keys(headers);
for (var i = 0; i < keys.length; ++i) { for (var i = 0; i < keys.length; ++i) {
const key = keys[i]; const key = keys[i];
@ -552,7 +551,7 @@ OutgoingMessage.prototype.getHeaderNames = function getHeaderNames() {
// Returns a shallow copy of the current outgoing headers. // Returns a shallow copy of the current outgoing headers.
OutgoingMessage.prototype.getHeaders = function getHeaders() { OutgoingMessage.prototype.getHeaders = function getHeaders() {
const headers = this[outHeadersKey]; const headers = this[outHeadersKey];
const ret = new StorageObject(); const ret = Object.create(null);
if (headers) { if (headers) {
const keys = Object.keys(headers); const keys = Object.keys(headers);
for (var i = 0; i < keys.length; ++i) { for (var i = 0; i < keys.length; ++i) {

View File

@ -23,12 +23,6 @@
var domain; var domain;
// This constructor is used to store event handlers. Instantiating this is
// faster than explicitly calling `Object.create(null)` to get a "clean" empty
// object (tested with v8 v4.9).
function EventHandlers() {}
EventHandlers.prototype = Object.create(null);
function EventEmitter() { function EventEmitter() {
EventEmitter.init.call(this); EventEmitter.init.call(this);
} }
@ -75,7 +69,7 @@ EventEmitter.init = function() {
} }
if (!this._events || this._events === Object.getPrototypeOf(this)._events) { if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
this._events = new EventHandlers(); this._events = Object.create(null);
this._eventsCount = 0; this._eventsCount = 0;
} }
@ -245,7 +239,7 @@ function _addListener(target, type, listener, prepend) {
events = target._events; events = target._events;
if (!events) { if (!events) {
events = target._events = new EventHandlers(); events = target._events = Object.create(null);
target._eventsCount = 0; target._eventsCount = 0;
} else { } else {
// To avoid recursion in the case that type === "newListener"! Before // To avoid recursion in the case that type === "newListener"! Before
@ -360,7 +354,7 @@ EventEmitter.prototype.removeListener =
if (list === listener || list.listener === listener) { if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0) if (--this._eventsCount === 0)
this._events = new EventHandlers(); this._events = Object.create(null);
else { else {
delete events[type]; delete events[type];
if (events.removeListener) if (events.removeListener)
@ -383,7 +377,7 @@ EventEmitter.prototype.removeListener =
if (list.length === 1) { if (list.length === 1) {
list[0] = undefined; list[0] = undefined;
if (--this._eventsCount === 0) { if (--this._eventsCount === 0) {
this._events = new EventHandlers(); this._events = Object.create(null);
return this; return this;
} else { } else {
delete events[type]; delete events[type];
@ -412,11 +406,11 @@ EventEmitter.prototype.removeAllListeners =
// not listening for removeListener, no need to emit // not listening for removeListener, no need to emit
if (!events.removeListener) { if (!events.removeListener) {
if (arguments.length === 0) { if (arguments.length === 0) {
this._events = new EventHandlers(); this._events = Object.create(null);
this._eventsCount = 0; this._eventsCount = 0;
} else if (events[type]) { } else if (events[type]) {
if (--this._eventsCount === 0) if (--this._eventsCount === 0)
this._events = new EventHandlers(); this._events = Object.create(null);
else else
delete events[type]; delete events[type];
} }
@ -432,7 +426,7 @@ EventEmitter.prototype.removeAllListeners =
this.removeAllListeners(key); this.removeAllListeners(key);
} }
this.removeAllListeners('removeListener'); this.removeAllListeners('removeListener');
this._events = new EventHandlers(); this._events = Object.create(null);
this._eventsCount = 0; this._eventsCount = 0;
return this; return this;
} }

View File

@ -43,7 +43,6 @@ const internalUtil = require('internal/util');
const assertEncoding = internalFS.assertEncoding; const assertEncoding = internalFS.assertEncoding;
const stringToFlags = internalFS.stringToFlags; const stringToFlags = internalFS.stringToFlags;
const getPathFromURL = internalURL.getPathFromURL; const getPathFromURL = internalURL.getPathFromURL;
const { StorageObject } = require('internal/querystring');
Object.defineProperty(exports, 'constants', { Object.defineProperty(exports, 'constants', {
configurable: false, configurable: false,
@ -1560,7 +1559,7 @@ if (isWindows) {
nextPart = function nextPart(p, i) { return p.indexOf('/', i); }; nextPart = function nextPart(p, i) { return p.indexOf('/', i); };
} }
const emptyObj = new StorageObject(); const emptyObj = Object.create(null);
fs.realpathSync = function realpathSync(p, options) { fs.realpathSync = function realpathSync(p, options) {
if (!options) if (!options)
options = emptyObj; options = emptyObj;
@ -1580,8 +1579,8 @@ fs.realpathSync = function realpathSync(p, options) {
return maybeCachedResult; return maybeCachedResult;
} }
const seenLinks = new StorageObject(); const seenLinks = Object.create(null);
const knownHard = new StorageObject(); const knownHard = Object.create(null);
const original = p; const original = p;
// current character position in p // current character position in p
@ -1700,8 +1699,8 @@ fs.realpath = function realpath(p, options, callback) {
return; return;
p = pathModule.resolve(p); p = pathModule.resolve(p);
const seenLinks = new StorageObject(); const seenLinks = Object.create(null);
const knownHard = new StorageObject(); const knownHard = Object.create(null);
// current character position in p // current character position in p
var pos; var pos;

View File

@ -23,13 +23,7 @@ const isHexTable = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // ... 256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // ... 256
]; ];
// Instantiating this is faster than explicitly calling `Object.create(null)`
// to get a "clean" empty object (tested with v8 v4.9).
function StorageObject() {}
StorageObject.prototype = Object.create(null);
module.exports = { module.exports = {
hexTable, hexTable,
isHexTable, isHexTable
StorageObject
}; };

View File

@ -25,7 +25,6 @@
const { Buffer } = require('buffer'); const { Buffer } = require('buffer');
const { const {
StorageObject,
hexTable, hexTable,
isHexTable isHexTable
} = require('internal/querystring'); } = require('internal/querystring');
@ -281,7 +280,7 @@ const defEqCodes = [61]; // =
// Parse a key/val string. // Parse a key/val string.
function parse(qs, sep, eq, options) { function parse(qs, sep, eq, options) {
const obj = new StorageObject(); const obj = Object.create(null);
if (typeof qs !== 'string' || qs.length === 0) { if (typeof qs !== 'string' || qs.length === 0) {
return obj; return obj;

View File

@ -23,7 +23,7 @@
const { toASCII } = process.binding('config').hasIntl ? const { toASCII } = process.binding('config').hasIntl ?
process.binding('icu') : require('punycode'); process.binding('icu') : require('punycode');
const { StorageObject, hexTable } = require('internal/querystring'); const { hexTable } = require('internal/querystring');
const internalUrl = require('internal/url'); const internalUrl = require('internal/url');
exports.parse = urlParse; exports.parse = urlParse;
exports.resolve = urlResolve; exports.resolve = urlResolve;
@ -197,7 +197,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
} }
} else if (parseQueryString) { } else if (parseQueryString) {
this.search = ''; this.search = '';
this.query = new StorageObject(); this.query = Object.create(null);
} }
return this; return this;
} }
@ -390,7 +390,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
} else if (parseQueryString) { } else if (parseQueryString) {
// no query string, but parseQueryString still requested // no query string, but parseQueryString still requested
this.search = ''; this.search = '';
this.query = new StorageObject(); this.query = Object.create(null);
} }
var firstIdx = (questionIdx !== -1 && var firstIdx = (questionIdx !== -1 &&