From 35ca570c96dece066cf8b61c89c20d9601799700 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Thu, 15 Aug 2019 13:06:51 +0200 Subject: [PATCH 1/3] stream: optimize creation --- lib/_stream_readable.js | 42 ++++++++++++++++++++--------------------- lib/_stream_writable.js | 39 +++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index cfa36731e3d661..02f669a0eab79e 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -33,7 +33,10 @@ const { Buffer } = require('buffer'); const debug = require('internal/util/debuglog').debuglog('stream'); const BufferList = require('internal/streams/buffer_list'); const destroyImpl = require('internal/streams/destroy'); -const { getHighWaterMark } = require('internal/streams/state'); +const { + getHighWaterMark, + getDefaultHighWaterMark +} = require('internal/streams/state'); const { ERR_INVALID_ARG_TYPE, ERR_STREAM_PUSH_AFTER_EOF, @@ -69,28 +72,20 @@ function prependListener(emitter, event, fn) { emitter._events[event] = [fn, emitter._events[event]]; } -function ReadableState(options, stream, isDuplex) { - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - if (typeof isDuplex !== 'boolean') - isDuplex = stream instanceof Stream.Duplex; - +function ReadableState(options, isDuplex) { // Object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; + this.objectMode = !!(options && options.objectMode); if (isDuplex) - this.objectMode = this.objectMode || !!options.readableObjectMode; + this.objectMode = this.objectMode || + !!(options && options.readableObjectMode); // The point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" - this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', - isDuplex); + this.highWaterMark = options ? + getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex) : + getDefaultHighWaterMark(false); // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than @@ -121,10 +116,10 @@ function ReadableState(options, stream, isDuplex) { this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true. - this.emitClose = options.emitClose !== false; + this.emitClose = !options || options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish') - this.autoDestroy = !!options.autoDestroy; + this.autoDestroy = !!(options && options.autoDestroy); // Has it been destroyed this.destroyed = false; @@ -132,7 +127,7 @@ function ReadableState(options, stream, isDuplex) { // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; + this.defaultEncoding = (options && options.defaultEncoding) || 'utf8'; // Ref the piped dest which we need a drain event on it // type: null | Writable | Set @@ -144,7 +139,7 @@ function ReadableState(options, stream, isDuplex) { this.decoder = null; this.encoding = null; - if (options.encoding) { + if (options && options.encoding) { if (!StringDecoder) StringDecoder = require('string_decoder').StringDecoder; this.decoder = new StringDecoder(options.encoding); @@ -163,11 +158,16 @@ function Readable(options) { if (!(this instanceof Readable)) return new Readable(options); + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. // Checking for a Stream.Duplex instance is faster here instead of inside // the ReadableState constructor, at least with V8 6.5 const isDuplex = this instanceof Stream.Duplex; - this._readableState = new ReadableState(options, this, isDuplex); + this._readableState = new ReadableState(options, isDuplex); // legacy this.readable = true; diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index e212881c4ac555..c5fdec065d73af 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -34,7 +34,10 @@ const internalUtil = require('internal/util'); const Stream = require('stream'); const { Buffer } = require('buffer'); const destroyImpl = require('internal/streams/destroy'); -const { getHighWaterMark } = require('internal/streams/state'); +const { + getHighWaterMark, + getDefaultHighWaterMark +} = require('internal/streams/state'); const { ERR_INVALID_ARG_TYPE, ERR_METHOD_NOT_IMPLEMENTED, @@ -55,28 +58,20 @@ Object.setPrototypeOf(Writable, Stream); function nop() {} function WritableState(options, stream, isDuplex) { - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream, - // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. - if (typeof isDuplex !== 'boolean') - isDuplex = stream instanceof Stream.Duplex; - // Object stream flag to indicate whether or not this stream // contains buffers or objects. - this.objectMode = !!options.objectMode; + this.objectMode = !!(options && options.objectMode); if (isDuplex) - this.objectMode = this.objectMode || !!options.writableObjectMode; + this.objectMode = this.objectMode || + !!(options && options.writableObjectMode); // The point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if // the entire buffer is not flushed immediately on write() - this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', - isDuplex); + this.highWaterMark = options ? + getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex) : + getDefaultHighWaterMark(false); // if _final has been called this.finalCalled = false; @@ -96,13 +91,13 @@ function WritableState(options, stream, isDuplex) { // Should we decode strings into buffers before passing to _write? // this is here so that some node-core streams can optimize string // handling at a lower level. - const noDecode = options.decodeStrings === false; + const noDecode = !!(options && options.decodeStrings === false); this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; + this.defaultEncoding = (options && options.defaultEncoding) || 'utf8'; // Not an actual buffer we keep track of, but a measurement // of how much we're waiting to get pushed to some underlying @@ -150,10 +145,10 @@ function WritableState(options, stream, isDuplex) { this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true. - this.emitClose = options.emitClose !== false; + this.emitClose = !options || options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end') - this.autoDestroy = !!options.autoDestroy; + this.autoDestroy = !!(options && options.autoDestroy); // Count buffered requests this.bufferedRequestCount = 0; @@ -212,6 +207,12 @@ function Writable(options) { // Node.js LazyTransform implementation, which has a non-trivial getter for // `_writableState` that would lead to infinite recursion. + + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream, + // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. // Checking for a Stream.Duplex instance is faster here instead of inside // the WritableState constructor, at least with V8 6.5 const isDuplex = (this instanceof Stream.Duplex); From fbec373ffdb32f8e404bc674adbbcadf08c8eb3b Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Thu, 12 Sep 2019 15:14:41 +0200 Subject: [PATCH 2/3] fixup: state object isDuplex --- lib/_stream_readable.js | 3 +++ lib/_stream_writable.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 02f669a0eab79e..ac749c2710a16d 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -73,6 +73,9 @@ function prependListener(emitter, event, fn) { } function ReadableState(options, isDuplex) { + if (typeof isDuplex !== 'boolean') + isDuplex = stream instanceof Stream.Duplex; + // Object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away this.objectMode = !!(options && options.objectMode); diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index c5fdec065d73af..7fdb748dcb80fc 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -58,6 +58,9 @@ Object.setPrototypeOf(Writable, Stream); function nop() {} function WritableState(options, stream, isDuplex) { + if (typeof isDuplex !== 'boolean') + isDuplex = stream instanceof Stream.Duplex; + // Object stream flag to indicate whether or not this stream // contains buffers or objects. this.objectMode = !!(options && options.objectMode); From e4328350127479265d44ec40c3940dc5b0792278 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Thu, 12 Sep 2019 17:25:36 +0200 Subject: [PATCH 3/3] fixup --- lib/_stream_readable.js | 14 +++++++------- lib/_stream_writable.js | 11 +++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index ac749c2710a16d..7502a1ac2c5ef2 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -72,7 +72,12 @@ function prependListener(emitter, event, fn) { emitter._events[event] = [fn, emitter._events[event]]; } -function ReadableState(options, isDuplex) { +function ReadableState(options, stream, isDuplex) { + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Stream.Duplex; @@ -161,16 +166,11 @@ function Readable(options) { if (!(this instanceof Readable)) return new Readable(options); - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. // Checking for a Stream.Duplex instance is faster here instead of inside // the ReadableState constructor, at least with V8 6.5 const isDuplex = this instanceof Stream.Duplex; - this._readableState = new ReadableState(options, isDuplex); + this._readableState = new ReadableState(options, this, isDuplex); // legacy this.readable = true; diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 7fdb748dcb80fc..cd9dab3e46a1a6 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -58,6 +58,11 @@ Object.setPrototypeOf(Writable, Stream); function nop() {} function WritableState(options, stream, isDuplex) { + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream, + // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Stream.Duplex; @@ -210,12 +215,6 @@ function Writable(options) { // Node.js LazyTransform implementation, which has a non-trivial getter for // `_writableState` that would lead to infinite recursion. - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream, - // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. // Checking for a Stream.Duplex instance is faster here instead of inside // the WritableState constructor, at least with V8 6.5 const isDuplex = (this instanceof Stream.Duplex);