diff --git a/lib/internal/streams/buffer_list.js b/lib/internal/streams/buffer_list.js index 2dc803d6fa0425..2551bee4473de4 100644 --- a/lib/internal/streams/buffer_list.js +++ b/lib/internal/streams/buffer_list.js @@ -1,9 +1,7 @@ 'use strict'; const { - StringPrototypeSlice, SymbolIterator, - TypedArrayPrototypeSet, Uint8Array, } = primordials; @@ -69,7 +67,7 @@ module.exports = class BufferList { let p = this.head; let i = 0; while (p) { - TypedArrayPrototypeSet(ret, p.data, i); + ret.set(p.data, i); i += p.data.length; p = p.next; } @@ -122,9 +120,9 @@ module.exports = class BufferList { else this.head = this.tail = null; } else { - ret += StringPrototypeSlice(str, 0, n); + ret += str.slice(0, n); this.head = p; - p.data = StringPrototypeSlice(str, n); + p.data = str.slice(n); } break; } @@ -143,20 +141,18 @@ module.exports = class BufferList { do { const buf = p.data; if (n > buf.length) { - TypedArrayPrototypeSet(ret, buf, retLen - n); + ret.set(buf, retLen - n); n -= buf.length; } else { if (n === buf.length) { - TypedArrayPrototypeSet(ret, buf, retLen - n); + ret.set(buf, retLen - n); ++c; if (p.next) this.head = p.next; else this.head = this.tail = null; } else { - TypedArrayPrototypeSet(ret, - new Uint8Array(buf.buffer, buf.byteOffset, n), - retLen - n); + ret.set(new Uint8Array(buf.buffer, buf.byteOffset, n), retLen - n); this.head = p; p.data = buf.slice(n); } diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 76df2aa0a34666..ff1bea5a415577 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -3,10 +3,7 @@ const { ERR_MULTIPLE_CALLBACK } = require('internal/errors').codes; -const { - FunctionPrototypeCall, - Symbol, -} = primordials; +const { Symbol } = primordials; const kDestroy = Symbol('kDestroy'); const kConstruct = Symbol('kConstruct'); @@ -96,8 +93,7 @@ function _destroy(self, err, cb) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, function() { if (called) @@ -315,8 +311,7 @@ function constructNT(stream) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, function() { // If the callback was invoked, do nothing further. diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js index 2f0043bf0b751e..5bf850ea6f8b92 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -3,10 +3,6 @@ 'use strict'; -const { - FunctionPrototype, - FunctionPrototypeCall, -} = primordials; const { ERR_STREAM_PREMATURE_CLOSE } = require('internal/errors').codes; @@ -57,7 +53,7 @@ function isWritableFinished(stream) { return wState.finished || (wState.ended && wState.length === 0); } -const nop = FunctionPrototype; +function nop() {} function isReadableEnded(stream) { if (stream.readableEnded) return true; @@ -114,7 +110,7 @@ function eos(stream, options, callback) { if (stream.destroyed) willEmitClose = false; if (willEmitClose && (!stream.readable || readable)) return; - if (!readable || readableEnded) FunctionPrototypeCall(callback, stream); + if (!readable || readableEnded) callback.call(stream); }; let readableEnded = stream.readableEnded || @@ -127,25 +123,23 @@ function eos(stream, options, callback) { if (stream.destroyed) willEmitClose = false; if (willEmitClose && (!stream.writable || writable)) return; - if (!writable || writableFinished) FunctionPrototypeCall(callback, stream); + if (!writable || writableFinished) callback.call(stream); }; const onerror = (err) => { - FunctionPrototypeCall(callback, stream, err); + callback.call(stream, err); }; const onclose = () => { if (readable && !readableEnded) { if (!isReadableEnded(stream)) - return FunctionPrototypeCall(callback, stream, - new ERR_STREAM_PREMATURE_CLOSE()); + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); } if (writable && !writableFinished) { if (!isWritableFinished(stream)) - return FunctionPrototypeCall(callback, stream, - new ERR_STREAM_PREMATURE_CLOSE()); + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); } - FunctionPrototypeCall(callback, stream); + callback.call(stream); }; const onrequest = () => { diff --git a/lib/internal/streams/from.js b/lib/internal/streams/from.js index c4e06945260d5f..949d0ceb6dae50 100644 --- a/lib/internal/streams/from.js +++ b/lib/internal/streams/from.js @@ -1,7 +1,6 @@ 'use strict'; const { - PromisePrototypeThen, SymbolAsyncIterator, SymbolIterator } = primordials; @@ -56,8 +55,7 @@ function from(Readable, iterable, opts) { readable._destroy = function(error, cb) { if (needToClose) { needToClose = false; - PromisePrototypeThen( - close(), + close().then( () => process.nextTick(cb, error), (e) => process.nextTick(cb, error || e), ); diff --git a/lib/internal/streams/lazy_transform.js b/lib/internal/streams/lazy_transform.js index ad072e3474b3e1..555e6430e33588 100644 --- a/lib/internal/streams/lazy_transform.js +++ b/lib/internal/streams/lazy_transform.js @@ -4,7 +4,6 @@ 'use strict'; const { - FunctionPrototypeCall, ObjectDefineProperties, ObjectDefineProperty, ObjectSetPrototypeOf, @@ -26,7 +25,7 @@ ObjectSetPrototypeOf(LazyTransform, stream.Transform); function makeGetter(name) { return function() { - FunctionPrototypeCall(stream.Transform, this, this._options); + stream.Transform.call(this, this._options); this._writableState.decodeStrings = false; if (!this._options || !this._options.defaultEncoding) { diff --git a/lib/internal/streams/legacy.js b/lib/internal/streams/legacy.js index d08df00259033b..0a0d0571c46378 100644 --- a/lib/internal/streams/legacy.js +++ b/lib/internal/streams/legacy.js @@ -2,15 +2,13 @@ const { ArrayIsArray, - ArrayPrototypeUnshift, - FunctionPrototypeCall, ObjectSetPrototypeOf, } = primordials; const EE = require('events'); function Stream(opts) { - FunctionPrototypeCall(EE, this, opts); + EE.call(this, opts); } ObjectSetPrototypeOf(Stream.prototype, EE.prototype); ObjectSetPrototypeOf(Stream, EE); @@ -108,7 +106,7 @@ function prependListener(emitter, event, fn) { if (!emitter._events || !emitter._events[event]) emitter.on(event, fn); else if (ArrayIsArray(emitter._events[event])) - ArrayPrototypeUnshift(emitter._events[event], fn); + emitter._events[event].unshift(fn); else emitter._events[event] = [fn, emitter._events[event]]; } diff --git a/lib/internal/streams/passthrough.js b/lib/internal/streams/passthrough.js index acc1a148a7d7c1..d37f9caf0116b5 100644 --- a/lib/internal/streams/passthrough.js +++ b/lib/internal/streams/passthrough.js @@ -26,7 +26,6 @@ 'use strict'; const { - FunctionPrototypeCall, ObjectSetPrototypeOf, } = primordials; @@ -40,7 +39,7 @@ function PassThrough(options) { if (!(this instanceof PassThrough)) return new PassThrough(options); - FunctionPrototypeCall(Transform, this, options); + Transform.call(this, options); } PassThrough.prototype._transform = function(chunk, encoding, cb) { diff --git a/lib/internal/streams/pipeline.js b/lib/internal/streams/pipeline.js index 876195b10c124a..900e561d32943c 100644 --- a/lib/internal/streams/pipeline.js +++ b/lib/internal/streams/pipeline.js @@ -5,10 +5,6 @@ const { ArrayIsArray, - ArrayPrototypePop, - ArrayPrototypePush, - ArrayPrototypeShift, - FunctionPrototypeCall, ReflectApply, SymbolAsyncIterator, SymbolIterator, @@ -79,7 +75,7 @@ function popCallback(streams) { // a single stream. Therefore optimize for the average case instead of // checking for length === 0 as well. validateCallback(streams[streams.length - 1]); - return ArrayPrototypePop(streams); + return streams.pop(); } function isReadable(obj) { @@ -118,7 +114,7 @@ async function* fromReadable(val) { Readable = require('internal/streams/readable'); } - yield* FunctionPrototypeCall(Readable.prototype[SymbolAsyncIterator], val); + yield* Readable.prototype[SymbolAsyncIterator].call(val); } async function pump(iterable, writable, finish) { @@ -175,7 +171,7 @@ function pipeline(...streams) { } while (destroys.length) { - ArrayPrototypeShift(destroys)(error); + destroys.shift()(error); } if (final) { @@ -191,7 +187,7 @@ function pipeline(...streams) { if (isStream(stream)) { finishCount++; - ArrayPrototypePush(destroys, destroyer(stream, reading, writing, finish)); + destroys.push(destroyer(stream, reading, writing, finish)); } if (i === 0) { @@ -254,7 +250,7 @@ function pipeline(...streams) { ret = pt; finishCount++; - ArrayPrototypePush(destroys, destroyer(ret, false, true, finish)); + destroys.push(destroyer(ret, false, true, finish)); } } else if (isStream(stream)) { if (isReadable(ret)) { diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index 6667c919c086a7..d0424edc1fa32b 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -22,13 +22,6 @@ 'use strict'; const { - ArrayPrototypeForEach, - ArrayPrototypeIndexOf, - ArrayPrototypePush, - ArrayPrototypeSplice, - FunctionPrototype, - FunctionPrototypeBind, - FunctionPrototypeCall, NumberIsInteger, NumberIsNaN, NumberParseInt, @@ -36,8 +29,7 @@ const { ObjectKeys, ObjectSetPrototypeOf, Promise, - ReflectApply, - SafeSet, + Set, SymbolAsyncIterator, Symbol } = primordials; @@ -78,7 +70,7 @@ let from; ObjectSetPrototypeOf(Readable.prototype, Stream.prototype); ObjectSetPrototypeOf(Readable, Stream); -const nop = FunctionPrototype; +function nop() {} const { errorOrDestroy } = destroyImpl; @@ -208,7 +200,7 @@ function Readable(options) { addAbortSignalNoValidate(options.signal, this); } - FunctionPrototypeCall(Stream, this, options); + Stream.call(this, options); destroyImpl.construct(this, () => { if (this._readableState.needReadable) { @@ -662,13 +654,13 @@ Readable.prototype.pipe = function(dest, pipeOpts) { if (state.pipes.length === 1) { if (!state.multiAwaitDrain) { state.multiAwaitDrain = true; - state.awaitDrainWriters = new SafeSet( + state.awaitDrainWriters = new Set( state.awaitDrainWriters ? [state.awaitDrainWriters] : [] ); } } - ArrayPrototypePush(state.pipes, dest); + state.pipes.push(dest); debug('pipe count=%d opts=%j', state.pipes.length, pipeOpts); const doEnd = (!pipeOpts || pipeOpts.end !== false) && @@ -855,17 +847,17 @@ Readable.prototype.unpipe = function(dest) { state.pipes = []; this.pause(); - ArrayPrototypeForEach(dests, (dest) => - dest.emit('unpipe', this, { hasUnpiped: false })); + for (const dest of dests) + dest.emit('unpipe', this, { hasUnpiped: false }); return this; } // Try to find the right one. - const index = ArrayPrototypeIndexOf(state.pipes, dest); + const index = state.pipes.indexOf(dest); if (index === -1) return this; - ArrayPrototypeSplice(state.pipes, index, 1); + state.pipes.splice(index, 1); if (state.pipes.length === 0) this.pause(); @@ -877,7 +869,7 @@ Readable.prototype.unpipe = function(dest) { // Set up data events if they are asked for // Ensure readable listeners eventually get something. Readable.prototype.on = function(ev, fn) { - const res = FunctionPrototypeCall(Stream.prototype.on, this, ev, fn); + const res = Stream.prototype.on.call(this, ev, fn); const state = this._readableState; if (ev === 'data') { @@ -907,8 +899,7 @@ Readable.prototype.on = function(ev, fn) { Readable.prototype.addListener = Readable.prototype.on; Readable.prototype.removeListener = function(ev, fn) { - const res = FunctionPrototypeCall(Stream.prototype.removeListener, this, - ev, fn); + const res = Stream.prototype.removeListener.call(this, ev, fn); if (ev === 'readable') { // We need to check if there is someone still listening to @@ -925,8 +916,7 @@ Readable.prototype.removeListener = function(ev, fn) { Readable.prototype.off = Readable.prototype.removeListener; Readable.prototype.removeAllListeners = function(ev) { - const res = ReflectApply(Stream.prototype.removeAllListeners, this, - arguments); + const res = Stream.prototype.removeAllListeners.apply(this, arguments); if (ev === 'readable' || ev === undefined) { // We need to check if there is someone still listening to @@ -1057,11 +1047,11 @@ Readable.prototype.wrap = function(stream) { }; // Proxy all the other methods. Important when wrapping filters and duplexes. - ArrayPrototypeForEach(ObjectKeys(stream), (i) => { + for (const i of ObjectKeys(stream)) { if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = FunctionPrototypeBind(stream[i], stream); + this[i] = stream[i].bind(stream); } - }); + } return this; }; @@ -1110,15 +1100,15 @@ async function* createAsyncIterator(stream) { .on('error', function(err) { error = err; errorEmitted = true; - FunctionPrototypeCall(next, this); + next.call(this); }) .on('end', function() { endEmitted = true; - FunctionPrototypeCall(next, this); + next.call(this); }) .on('close', function() { closeEmitted = true; - FunctionPrototypeCall(next, this); + next.call(this); }); try { diff --git a/lib/internal/streams/transform.js b/lib/internal/streams/transform.js index 971bf5126f250d..26e0b07c2956c8 100644 --- a/lib/internal/streams/transform.js +++ b/lib/internal/streams/transform.js @@ -64,7 +64,6 @@ 'use strict'; const { - FunctionPrototypeCall, ObjectSetPrototypeOf, Symbol } = primordials; @@ -133,8 +132,7 @@ function final(cb) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, (data) => { if (called) @@ -167,7 +165,7 @@ function final(cb) { function prefinish() { if (this._final !== final) { - FunctionPrototypeCall(final, this); + final.call(this); } } @@ -209,8 +207,7 @@ Transform.prototype._write = function(chunk, encoding, callback) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, (val) => { if (called) diff --git a/lib/internal/streams/writable.js b/lib/internal/streams/writable.js index 2fe811236a27e8..2510398d999fe1 100644 --- a/lib/internal/streams/writable.js +++ b/lib/internal/streams/writable.js @@ -26,17 +26,11 @@ 'use strict'; const { - ArrayPrototypeForEach, - ArrayPrototypePush, - ArrayPrototypeSlice, - ArrayPrototypeSplice, + FunctionPrototype, Error, - FunctionPrototypeCall, - FunctionPrototypeSymbolHasInstance, ObjectDefineProperty, ObjectDefineProperties, ObjectSetPrototypeOf, - StringPrototypeToLowerCase, Symbol, SymbolHasInstance, } = primordials; @@ -212,7 +206,7 @@ function resetBuffer(state) { } WritableState.prototype.getBuffer = function getBuffer() { - return ArrayPrototypeSlice(this.buffered, this.bufferedIndex); + return this.buffered.slice(this.bufferedIndex); }; ObjectDefineProperty(WritableState.prototype, 'bufferedRequestCount', { @@ -221,6 +215,27 @@ ObjectDefineProperty(WritableState.prototype, 'bufferedRequestCount', { } }); +// Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. +let realHasInstance; +if (typeof Symbol === 'function' && SymbolHasInstance) { + realHasInstance = FunctionPrototype[SymbolHasInstance]; + ObjectDefineProperty(Writable, SymbolHasInstance, { + value: function(object) { + if (realHasInstance.call(this, object)) + return true; + if (this !== Writable) + return false; + + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function(object) { + return object instanceof this; + }; +} + function Writable(options) { // Writable ctor is applied to Duplexes, too. // `realHasInstance` is necessary because using plain `instanceof` @@ -234,7 +249,7 @@ function Writable(options) { // the WritableState constructor, at least with V8 6.5. const isDuplex = (this instanceof Stream.Duplex); - if (!isDuplex && !FunctionPrototypeSymbolHasInstance(Writable, this)) + if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options); this._writableState = new WritableState(options, this, isDuplex); @@ -258,7 +273,7 @@ function Writable(options) { addAbortSignalNoValidate(options.signal, this); } - FunctionPrototypeCall(Stream, this, options); + Stream.call(this, options); destroyImpl.construct(this, () => { const state = this._writableState; @@ -271,15 +286,6 @@ function Writable(options) { }); } -ObjectDefineProperty(Writable, SymbolHasInstance, { - value: function(object) { - if (FunctionPrototypeSymbolHasInstance(this, object)) return true; - if (this !== Writable) return false; - - return object && object._writableState instanceof WritableState; - }, -}); - // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function() { errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); @@ -357,7 +363,7 @@ Writable.prototype.uncork = function() { Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { // node::ParseEncoding() requires lower case. if (typeof encoding === 'string') - encoding = StringPrototypeToLowerCase(encoding); + encoding = encoding.toLowerCase(); if (!Buffer.isEncoding(encoding)) throw new ERR_UNKNOWN_ENCODING(encoding); this._writableState.defaultEncoding = encoding; @@ -522,10 +528,9 @@ function errorBuffer(state) { callback(new ERR_STREAM_DESTROYED('write')); } - ArrayPrototypeForEach( - ArrayPrototypeSplice(state[kOnFinished], 0), - (callback) => callback(new ERR_STREAM_DESTROYED('end')) - ); + for (const callback of state[kOnFinished].splice(0)) { + callback(new ERR_STREAM_DESTROYED('end')); + } resetBuffer(state); } @@ -559,8 +564,7 @@ function clearBuffer(stream, state) { }; // Make a copy of `buffered` if it's going to be used by `callback` above, // since `doWrite` will mutate the array. - const chunks = state.allNoop && i === 0 ? - buffered : ArrayPrototypeSlice(buffered, i); + const chunks = state.allNoop && i === 0 ? buffered : buffered.slice(i); chunks.allBuffers = state.allBuffers; doWrite(stream, state, true, state.length, chunks, '', callback); @@ -577,7 +581,7 @@ function clearBuffer(stream, state) { if (i === buffered.length) { resetBuffer(state); } else if (i > 256) { - ArrayPrototypeSplice(buffered, 0, i); + buffered.splice(0, i); state.bufferedIndex = 0; } else { state.bufferedIndex = i; @@ -645,7 +649,7 @@ Writable.prototype.end = function(chunk, encoding, cb) { if (err || state.finished) { process.nextTick(cb, err); } else { - ArrayPrototypePush(state[kOnFinished], cb); + state[kOnFinished].push(cb); } } @@ -668,7 +672,7 @@ function callFinal(stream, state) { const result = stream._final((err) => { state.pendingcb--; if (err) { - for (const callback of ArrayPrototypeSplice(state[kOnFinished], 0)) { + for (const callback of state[kOnFinished].splice(0)) { callback(err); } errorOrDestroy(stream, err, state.sync); @@ -686,8 +690,7 @@ function callFinal(stream, state) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, function() { if (state.prefinished) @@ -698,8 +701,8 @@ function callFinal(stream, state) { process.nextTick(finish, stream, state); }, function(err) { - for (const cb of ArrayPrototypeSplice(state[kOnFinished], 0)) { - process.nextTick(cb, err); + for (const callback of state[kOnFinished].splice(0)) { + process.nextTick(callback, err); } process.nextTick(errorOrDestroy, stream, err, state.sync); }); @@ -745,8 +748,9 @@ function finish(stream, state) { state.finished = true; - ArrayPrototypeForEach(ArrayPrototypeSplice(state[kOnFinished], 0), - (callback) => callback()); + for (const callback of state[kOnFinished].splice(0)) { + callback(); + } stream.emit('finish'); @@ -862,7 +866,7 @@ Writable.prototype.destroy = function(err, cb) { process.nextTick(errorBuffer, state); } - FunctionPrototypeCall(destroy, this, err, cb); + destroy.call(this, err, cb); return this; }; diff --git a/test/parallel/test-stream-pipe-await-drain.js b/test/parallel/test-stream-pipe-await-drain.js index 35b86f67f99676..90d418a09783e3 100644 --- a/test/parallel/test-stream-pipe-await-drain.js +++ b/test/parallel/test-stream-pipe-await-drain.js @@ -27,7 +27,7 @@ writer1.once('chunk-received', () => { reader._readableState.awaitDrainWriters.size, 0, 'awaitDrain initial value should be 0, actual is ' + - reader._readableState.awaitDrainWriters.size + reader._readableState.awaitDrainWriters ); setImmediate(() => { // This one should *not* get through to writer1 because writer2 is not