From f49ba493f0efb4b3aced57f823074a5c56a239d0 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sat, 10 Apr 2021 22:57:19 +0200 Subject: [PATCH 1/8] Revert "stream: refactor to use more primordials" This reverts commit 419686cdfbb3429c512f18bc10c06a8cf5f32cf7. --- lib/internal/streams/buffer_list.js | 16 ++-- lib/internal/streams/destroy.js | 10 +-- lib/internal/streams/end-of-stream.js | 25 +++--- lib/internal/streams/from.js | 8 +- lib/internal/streams/lazy_transform.js | 3 +- lib/internal/streams/legacy.js | 6 +- lib/internal/streams/passthrough.js | 3 +- lib/internal/streams/pipeline.js | 14 ++-- lib/internal/streams/readable.js | 47 +++++------- lib/internal/streams/transform.js | 9 +-- lib/internal/streams/writable.js | 76 ++++++++++--------- test/parallel/test-stream-pipe-await-drain.js | 2 +- 12 files changed, 92 insertions(+), 127 deletions(-) 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 467275c2edac35..c16f669d97aa49 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -6,10 +6,6 @@ const { ERR_MULTIPLE_CALLBACK, }, } = require('internal/errors'); -const { - FunctionPrototypeCall, - Symbol, -} = primordials; const kDestroy = Symbol('kDestroy'); const kConstruct = Symbol('kConstruct'); @@ -99,8 +95,7 @@ function _destroy(self, err, cb) { try { const then = result.then; if (typeof then === 'function') { - FunctionPrototypeCall( - then, + then.call( result, function() { if (called) @@ -318,8 +313,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 da48831a405dbe..35b9d5e742376d 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -3,11 +3,6 @@ 'use strict'; -const { - FunctionPrototype, - FunctionPrototypeCall, - ReflectApply, -} = primordials; const { AbortError, codes, @@ -55,7 +50,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; @@ -113,7 +108,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 || @@ -126,25 +121,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 = () => { @@ -218,7 +211,7 @@ function eos(stream, options, callback) { // Keep it because cleanup removes it. const endCallback = callback; cleanup(); - FunctionPrototypeCall(endCallback, stream, new AbortError()); + endCallback.call(stream, new AbortError()); }; if (options.signal.aborted) { process.nextTick(abort); @@ -226,7 +219,7 @@ function eos(stream, options, callback) { const originalCallback = callback; callback = once((...args) => { options.signal.removeEventListener('abort', abort); - ReflectApply(originalCallback, stream, args); + Reflect.apply(originalCallback, stream, args); }); options.signal.addEventListener('abort', abort); } diff --git a/lib/internal/streams/from.js b/lib/internal/streams/from.js index 906ddcf9af844b..c5ce03ea354b81 100644 --- a/lib/internal/streams/from.js +++ b/lib/internal/streams/from.js @@ -1,7 +1,6 @@ 'use strict'; const { - PromisePrototypeThen, SymbolAsyncIterator, SymbolIterator, } = primordials; @@ -55,10 +54,9 @@ function from(Readable, iterable, opts) { }; readable._destroy = function(error, cb) { - PromisePrototypeThen( - close(error), - () => process.nextTick(cb, error), // nextTick is here in case cb throws - (e) => process.nextTick(cb, e || error), + close(error).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 5215d986ef1f1c..573f32d1421bf8 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, } = primordials; @@ -84,7 +80,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 makeAsyncIterable(val) { @@ -103,7 +99,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) { @@ -160,7 +156,7 @@ function pipeline(...streams) { } while (destroys.length) { - ArrayPrototypeShift(destroys)(error); + destroys.shift()(error); } if (final) { @@ -176,7 +172,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) { @@ -239,7 +235,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 cc3f5e93fd0201..e67c25c8d3592c 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,18 @@ 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 +870,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 +900,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 +917,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 +1048,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 +1101,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 From f9763d85ecfe824fd2fe02b0b15997729e079571 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 14 Apr 2021 01:03:56 +0200 Subject: [PATCH 2/8] stream: removed number primordials --- lib/internal/streams/readable.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js index e67c25c8d3592c..f574482e5bd455 100644 --- a/lib/internal/streams/readable.js +++ b/lib/internal/streams/readable.js @@ -22,9 +22,6 @@ 'use strict'; const { - NumberIsInteger, - NumberIsNaN, - NumberParseInt, ObjectDefineProperties, ObjectKeys, ObjectSetPrototypeOf, @@ -379,7 +376,7 @@ function howMuchToRead(n, state) { return 0; if (state.objectMode) return 1; - if (NumberIsNaN(n)) { + if (Number.isNaN(n)) { // Only flow one buffer at a time. if (state.flowing && state.length) return state.buffer.first().length; @@ -397,8 +394,8 @@ Readable.prototype.read = function(n) { // in this scenario, so we are doing it manually. if (n === undefined) { n = NaN; - } else if (!NumberIsInteger(n)) { - n = NumberParseInt(n, 10); + } else if (!Number.isInteger(n)) { + n = Number.parseInt(n, 10); } const state = this._readableState; const nOrig = n; From 1e0d89c7acd01b1d24c6b470484ec8584bbddfb4 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 14 Apr 2021 01:29:37 +0200 Subject: [PATCH 3/8] http: remove primordials from hot path --- lib/_http_incoming.js | 12 +++---- lib/_http_outgoing.js | 84 ++++++++++++++++++------------------------- lib/_http_server.js | 76 ++++++++++++++++++--------------------- 3 files changed, 74 insertions(+), 98 deletions(-) diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js index d09683c9a8f1b1..2260eae0aebc33 100644 --- a/lib/_http_incoming.js +++ b/lib/_http_incoming.js @@ -22,13 +22,9 @@ 'use strict'; const { - ArrayPrototypePush, FunctionPrototypeCall, ObjectDefineProperty, ObjectSetPrototypeOf, - StringPrototypeCharCodeAt, - StringPrototypeSlice, - StringPrototypeToLowerCase, Symbol } = primordials; @@ -324,7 +320,7 @@ function matchKnownFields(field, lowercased) { if (lowercased) { return '\u0000' + field; } - return matchKnownFields(StringPrototypeToLowerCase(field), true); + return matchKnownFields(field.toLowerCase(), true); } // Add the given (field, value) pair to the message // @@ -338,9 +334,9 @@ function matchKnownFields(field, lowercased) { IncomingMessage.prototype._addHeaderLine = _addHeaderLine; function _addHeaderLine(field, value, dest) { field = matchKnownFields(field); - const flag = StringPrototypeCharCodeAt(field, 0); + const flag = field.charCodeAt(0); if (flag === 0 || flag === 2) { - field = StringPrototypeSlice(field, 1); + field = field.slice(1); // Make a delimited list if (typeof dest[field] === 'string') { dest[field] += (flag === 0 ? ', ' : '; ') + value; @@ -350,7 +346,7 @@ function _addHeaderLine(field, value, dest) { } else if (flag === 1) { // Array header -- only Set-Cookie at the moment if (dest['set-cookie'] !== undefined) { - ArrayPrototypePush(dest['set-cookie'], value); + dest['set-cookie'].push(value); } else { dest['set-cookie'] = [value]; } diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index b627608a527201..58da505f58ce4b 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -22,25 +22,10 @@ 'use strict'; const { - Array, - ArrayIsArray, - ArrayPrototypeForEach, - ArrayPrototypeJoin, - ArrayPrototypePush, - ArrayPrototypeUnshift, FunctionPrototype, - FunctionPrototypeBind, - FunctionPrototypeCall, - MathFloor, - NumberPrototypeToString, - ObjectCreate, ObjectDefineProperty, - ObjectKeys, - ObjectValues, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, - RegExpPrototypeTest, - StringPrototypeToLowerCase, Symbol, } = primordials; @@ -97,11 +82,11 @@ const RE_TE_CHUNKED = common.chunkExpression; // against the word "cookie." As of V8 6.6 this is faster than handrolling or // using a case-insensitive RegExp. function isCookieField(s) { - return s.length === 6 && StringPrototypeToLowerCase(s) === 'cookie'; + return s.length === 6 && s.toLowerCase() === 'cookie'; } function OutgoingMessage() { - FunctionPrototypeCall(Stream, this); + Stream.call(this); // Queue that holds all currently pending data, until the response will be // assigned to the socket (until it will its turn in the HTTP pipeline). @@ -190,13 +175,13 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headers', { if (val == null) { this[kOutHeaders] = null; } else if (typeof val === 'object') { - const headers = this[kOutHeaders] = ObjectCreate(null); - const keys = ObjectKeys(val); + const headers = this[kOutHeaders] = Object.create(null); + const keys = Object.keys(val); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0; i < keys.length; ++i) { const name = keys[i]; - headers[StringPrototypeToLowerCase(name)] = [name, val[name]]; + headers[name.toLowerCase()] = [name, val[name]]; } } }, 'OutgoingMessage.prototype._headers is deprecated', 'DEP0066') @@ -215,8 +200,8 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headerNames', { get: internalUtil.deprecate(function() { const headers = this[kOutHeaders]; if (headers !== null) { - const out = ObjectCreate(null); - const keys = ObjectKeys(headers); + const out = Object.create(null); + const keys = Object.keys(headers); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0; i < keys.length; ++i) { @@ -233,7 +218,7 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headerNames', { const headers = this[kOutHeaders]; if (!headers) return; - const keys = ObjectKeys(val); + const keys = Object.keys(val); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0; i < keys.length; ++i) { @@ -255,7 +240,7 @@ OutgoingMessage.prototype._renderHeaders = function _renderHeaders() { const headers = {}; if (headersMap !== null) { - const keys = ObjectKeys(headersMap); + const keys = Object.keys(headersMap); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0, l = keys.length; i < l; i++) { @@ -331,7 +316,7 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) { data = this._header + data; } else { const header = this._header; - ArrayPrototypeUnshift(this.outputData, { + this.outputData.unshift({ data: header, encoding: 'latin1', callback: null @@ -368,7 +353,7 @@ function _writeRaw(data, encoding, callback) { return conn.write(data, encoding, callback); } // Buffer, as long as we're not destroyed. - ArrayPrototypePush(this.outputData, { data, encoding, callback }); + this.outputData.push({ data, encoding, callback }); this.outputSize += data.length; this._onPendingData(data.length); return this.outputSize < HIGH_WATER_MARK; @@ -395,11 +380,12 @@ function _storeHeader(firstLine, headers) { const entry = headers[key]; processHeader(this, state, entry[0], entry[1], false); } - } else if (ArrayIsArray(headers)) { - if (headers.length && ArrayIsArray(headers[0])) { - ArrayPrototypeForEach(headers, (entry) => + } else if (Array.isArray(headers)) { + if (headers.length && Array.isArray(headers[0])) { + for (let n = 0; n < headers.length; n++) { + const entry = headers[n] processHeader(this, state, entry[0], entry[1], true) - ); + } } else { if (headers.length % 2 !== 0) { throw new ERR_INVALID_ARG_VALUE('headers', headers); @@ -454,7 +440,7 @@ function _storeHeader(firstLine, headers) { if (shouldSendKeepAlive) { header += 'Connection: keep-alive' + CRLF; if (this._keepAliveTimeout && this._defaultKeepAlive) { - const timeoutSeconds = MathFloor(this._keepAliveTimeout / 1000); + const timeoutSeconds = Math.floor(this._keepAliveTimeout / 1000); header += `Keep-Alive: timeout=${timeoutSeconds}${CRLF}`; } } else { @@ -504,7 +490,7 @@ function _storeHeader(firstLine, headers) { function processHeader(self, state, key, value, validate) { if (validate) validateHeaderName(key); - if (ArrayIsArray(value)) { + if (Array.isArray(value)) { if (value.length < 2 || !isCookieField(key)) { // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 @@ -512,7 +498,7 @@ function processHeader(self, state, key, value, validate) { storeHeader(self, state, key, value[i], validate); return; } - value = ArrayPrototypeJoin(value, '; '); + value = value.join('; '); } storeHeader(self, state, key, value, validate); } @@ -527,12 +513,12 @@ function storeHeader(self, state, key, value, validate) { function matchHeader(self, state, field, value) { if (field.length < 4 || field.length > 17) return; - field = StringPrototypeToLowerCase(field); + field = field.toLowerCase(); switch (field) { case 'connection': state.connection = true; self._removedConnection = false; - if (RegExpPrototypeTest(RE_CONN_CLOSE, value)) + if (RE_CONN_CLOSE.test(value)) self._last = true; else self.shouldKeepAlive = true; @@ -540,7 +526,7 @@ function matchHeader(self, state, field, value) { case 'transfer-encoding': state.te = true; self._removedTE = false; - if (RegExpPrototypeTest(RE_TE_CHUNKED, value)) + if (RE_TE_CHUNKED.test(value)) self.chunkedEncoding = true; break; case 'content-length': @@ -583,9 +569,9 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) { let headers = this[kOutHeaders]; if (headers === null) - this[kOutHeaders] = headers = ObjectCreate(null); + this[kOutHeaders] = headers = Object.create(null); - headers[StringPrototypeToLowerCase(name)] = [name, value]; + headers[name.toLowerCase()] = [name, value]; return this; }; @@ -597,14 +583,14 @@ OutgoingMessage.prototype.getHeader = function getHeader(name) { if (headers === null) return; - const entry = headers[StringPrototypeToLowerCase(name)]; + const entry = headers[name.toLowerCase()]; return entry && entry[1]; }; // Returns an array of the names of the current outgoing headers. OutgoingMessage.prototype.getHeaderNames = function getHeaderNames() { - return this[kOutHeaders] !== null ? ObjectKeys(this[kOutHeaders]) : []; + return this[kOutHeaders] !== null ? Object.keys(this[kOutHeaders]) : []; }; @@ -613,7 +599,7 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { const headersMap = this[kOutHeaders]; if (headersMap === null) return []; - const values = ObjectValues(headersMap); + const values = Object.values(headersMap); const headers = Array(values.length); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 @@ -628,9 +614,9 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { // Returns a shallow copy of the current outgoing headers. OutgoingMessage.prototype.getHeaders = function getHeaders() { const headers = this[kOutHeaders]; - const ret = ObjectCreate(null); + const ret = Object.create(null); if (headers) { - const keys = ObjectKeys(headers); + const keys = Object.keys(headers); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0; i < keys.length; ++i) { @@ -646,7 +632,7 @@ OutgoingMessage.prototype.getHeaders = function getHeaders() { OutgoingMessage.prototype.hasHeader = function hasHeader(name) { validateString(name, 'name'); return this[kOutHeaders] !== null && - !!this[kOutHeaders][StringPrototypeToLowerCase(name)]; + !!this[kOutHeaders][name.toLowerCase()]; }; @@ -657,7 +643,7 @@ OutgoingMessage.prototype.removeHeader = function removeHeader(name) { throw new ERR_HTTP_HEADERS_SENT('remove'); } - const key = StringPrototypeToLowerCase(name); + const key = name.toLowerCase(); switch (key) { case 'connection': @@ -783,7 +769,7 @@ function write_(msg, chunk, encoding, callback, fromEnd) { let ret; if (msg.chunkedEncoding && chunk.length !== 0) { - msg._send(NumberPrototypeToString(len, 16), 'latin1', null); + msg._send(len.toString(16), 'latin1', null); msg._send(crlf_buf, null, null); msg._send(chunk, encoding, null); ret = msg._send(crlf_buf, null, callback); @@ -803,8 +789,8 @@ function connectionCorkNT(conn) { OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { this._trailer = ''; - const keys = ObjectKeys(headers); - const isArray = ArrayIsArray(headers); + const keys = Object.keys(headers); + const isArray = Array.isArray(headers); // Retain for(;;) loop for performance reasons // Refs: https://github.com/nodejs/node/pull/30958 for (let i = 0, l = keys.length; i < l; i++) { @@ -877,7 +863,7 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) { if (typeof callback === 'function') this.once('finish', callback); - const finish = FunctionPrototypeBind(onFinish, undefined, this); + const finish = onFinish.bind(undefined, this); if (this._hasBody && this.chunkedEncoding) { this._send('0\r\n' + this._trailer + '\r\n', 'latin1', finish); diff --git a/lib/_http_server.js b/lib/_http_server.js index aa457687593a54..5faefcca264900 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -22,18 +22,12 @@ 'use strict'; const { - ArrayIsArray, ArrayPrototypeForEach, - ArrayPrototypePush, - ArrayPrototypeShift, Error, FunctionPrototype, - FunctionPrototypeBind, FunctionPrototypeCall, ObjectKeys, ObjectSetPrototypeOf, - ReflectApply, - RegExpPrototypeTest, Symbol, SymbolFor, TypedArrayPrototypeSlice, @@ -193,8 +187,8 @@ function ServerResponse(req) { this._expect_continue = false; if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) { - this.useChunkedEncodingByDefault = RegExpPrototypeTest(chunkExpression, - req.headers.te); + this.useChunkedEncodingByDefault = chunkExpression.test( + req.headers.te); this.shouldKeepAlive = false; } @@ -210,7 +204,7 @@ ObjectSetPrototypeOf(ServerResponse, OutgoingMessage); ServerResponse.prototype._finish = function _finish() { DTRACE_HTTP_SERVER_RESPONSE(this.socket); emitStatistics(this[kServerResponseStatistics]); - FunctionPrototypeCall(OutgoingMessage.prototype._finish, this); + OutgoingMessage.prototype._finish.call(this); }; @@ -297,7 +291,7 @@ function writeHead(statusCode, reason, obj) { if (this[kOutHeaders]) { // Slow-case: when progressive API and header fields are passed. let k; - if (ArrayIsArray(obj)) { + if (Array.isArray(obj)) { if (obj.length % 2 !== 0) { throw new ERR_INVALID_ARG_VALUE('headers', obj); } @@ -429,7 +423,7 @@ Server.prototype[EE.captureRejectionSymbol] = function(err, event, ...args) { } break; default: - ReflectApply(net.Server.prototype[SymbolFor('nodejs.rejection')], + Reflect.apply(net.Server.prototype[SymbolFor('nodejs.rejection')], this, arguments); } }; @@ -489,20 +483,20 @@ function connectionListenerInternal(server, socket) { outgoingData: 0, keepAliveTimeoutSet: false }; - state.onData = FunctionPrototypeBind(socketOnData, undefined, - server, socket, parser, state); - state.onEnd = FunctionPrototypeBind(socketOnEnd, undefined, - server, socket, parser, state); - state.onClose = FunctionPrototypeBind(socketOnClose, undefined, - socket, state); - state.onDrain = FunctionPrototypeBind(socketOnDrain, undefined, - socket, state); + state.onData = socketOnData.bind(undefined, + server, socket, parser, state); + state.onEnd = socketOnEnd.bind(undefined, + server, socket, parser, state); + state.onClose = socketOnClose.bind(undefined, + socket, state); + state.onDrain = socketOnDrain.bind(undefined, + socket, state); socket.on('data', state.onData); socket.on('error', socketOnError); socket.on('end', state.onEnd); socket.on('close', state.onClose); socket.on('drain', state.onDrain); - parser.onIncoming = FunctionPrototypeBind(parserOnIncoming, undefined, + parser.onIncoming = parserOnIncoming.bind(undefined, server, socket, state); // We are consuming socket, so it won't get any actual data @@ -523,18 +517,18 @@ function connectionListenerInternal(server, socket) { parser.consume(socket._handle); } parser[kOnExecute] = - FunctionPrototypeBind(onParserExecute, undefined, - server, socket, parser, state); + onParserExecute.bind(undefined, + server, socket, parser, state); parser[kOnTimeout] = - FunctionPrototypeBind(onParserTimeout, undefined, - server, socket); + onParserTimeout.bind(undefined, + server, socket); // When receiving new requests on the same socket (pipelining or keep alive) // make sure the requestTimeout is active. parser[kOnMessageBegin] = - FunctionPrototypeBind(setRequestTimeout, undefined, - server, socket); + setRequestTimeout.bind(undefined, + server, socket); // This protects from DOS attack where an attacker establish the connection // without sending any data on applications where server.timeout is left to @@ -590,7 +584,7 @@ function socketOnClose(socket, state) { function abortIncoming(incoming) { while (incoming.length) { - const req = ArrayPrototypeShift(incoming); + const req = incoming.shift(); req.destroy(connResetException('aborted')); } // Abort socket._httpMessage ? @@ -602,7 +596,7 @@ function socketOnEnd(server, socket, parser, state) { if (ret instanceof Error) { debug('parse error'); // socketOnError has additional logic and will call socket.destroy(err). - FunctionPrototypeCall(socketOnError, socket, ret); + socketOnError.call(socket, ret); } else if (!server.httpAllowHalfOpen) { socket.end(); } else if (state.outgoing.length) { @@ -625,7 +619,7 @@ function socketOnData(server, socket, parser, state, d) { function onRequestTimeout(socket) { socket[kRequestTimeout] = undefined; // socketOnError has additional logic and will call socket.destroy(err). - ReflectApply(socketOnError, socket, [new ERR_HTTP_REQUEST_TIMEOUT()]); + Reflect.apply(socketOnError, socket, [new ERR_HTTP_REQUEST_TIMEOUT()]); } function onParserExecute(server, socket, parser, state, ret) { @@ -692,7 +686,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) { prepareError(ret, parser, d); ret.rawPacket = d || parser.getCurrentBuffer(); debug('parse error', ret); - FunctionPrototypeCall(socketOnError, socket, ret); + socketOnError.call(socket, ret); } else if (parser.incoming && parser.incoming.upgrade) { // Upgrade or CONNECT const req = parser.incoming; @@ -731,7 +725,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) { // When receiving new requests on the same socket (pipelining or keep alive) // make sure the requestTimeout is active. parser[kOnMessageBegin] = - FunctionPrototypeBind(setRequestTimeout, undefined, server, socket); + setRequestTimeout.bind(undefined, server, socket); } if (socket._paused && socket.parser) { @@ -795,7 +789,7 @@ function resOnFinish(req, res, socket, state, server) { // array will be empty. assert(state.incoming.length === 0 || state.incoming[0] === req); - ArrayPrototypeShift(state.incoming); + state.incoming.shift(); // If the user never called req.read(), and didn't pipe() or // .resume() or .on('data'), then we call req._dump() so that the @@ -828,7 +822,7 @@ function resOnFinish(req, res, socket, state, server) { } } else { // Start sending the next message - const m = ArrayPrototypeShift(state.outgoing); + const m = state.outgoing.shift(); if (m) { m.assignSocket(socket); } @@ -854,7 +848,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { return 2; } - ArrayPrototypePush(state.incoming, req); + state.incoming.push(req); // If the writable end isn't consuming, then stop reading // so that we don't become overwhelmed by a flood of @@ -872,8 +866,8 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { const res = new server[kServerResponse](req); res._keepAliveTimeout = server.keepAliveTimeout; - res._onPendingData = FunctionPrototypeBind(updateOutgoingData, undefined, - socket, state); + res._onPendingData = updateOutgoingData.bind(undefined, + socket, state); res.shouldKeepAlive = keepAlive; DTRACE_HTTP_SERVER_REQUEST(req, socket); @@ -889,7 +883,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { if (socket._httpMessage) { // There are already pending outgoing res, append. - ArrayPrototypePush(state.outgoing, res); + state.outgoing.push(res); } else { res.assignSocket(socket); } @@ -897,12 +891,12 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { // When we're finished writing the response, check if this is the last // response, if so destroy the socket. res.on('finish', - FunctionPrototypeBind(resOnFinish, undefined, - req, res, socket, state, server)); + resOnFinish.bind(undefined, + req, res, socket, state, server)); if (req.headers.expect !== undefined && (req.httpVersionMajor === 1 && req.httpVersionMinor === 1)) { - if (RegExpPrototypeTest(continueExpression, req.headers.expect)) { + if (continueExpression.test(req.headers.expect)) { res._expect_continue = true; if (server.listenerCount('checkContinue') > 0) { @@ -970,7 +964,7 @@ function unconsume(parser, socket) { function generateSocketListenerWrapper(originalFnName) { return function socketListenerWrap(ev, fn) { - const res = ReflectApply(net.Socket.prototype[originalFnName], this, + const res = Reflect.apply(net.Socket.prototype[originalFnName], this, [ev, fn]); if (!this.parser) { this.on = net.Socket.prototype.on; From 74d24971fafcefe193a2e7aac6c3d03471ded954 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 14 Apr 2021 14:36:41 +0200 Subject: [PATCH 4/8] lib: revert more primordials in the hot path --- lib/_http_common.js | 14 +++++------- lib/_http_incoming.js | 3 +-- lib/_http_outgoing.js | 3 +-- lib/_http_server.js | 11 ++++----- lib/events.js | 37 +++++++++++------------------- lib/internal/buffer.js | 9 -------- lib/internal/http.js | 7 ++---- lib/internal/streams/state.js | 9 ++------ lib/net.js | 42 +++++++++++++---------------------- 9 files changed, 43 insertions(+), 92 deletions(-) diff --git a/lib/_http_common.js b/lib/_http_common.js index 229353ec735288..6eb5fb11c55523 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -22,11 +22,7 @@ 'use strict'; const { - ArrayPrototypePushApply, - MathMin, Symbol, - RegExpPrototypeTest, - TypedArrayPrototypeSlice, } = primordials; const { setImmediate } = require('timers'); @@ -66,7 +62,7 @@ function parserOnHeaders(headers, url) { // Once we exceeded headers limit - stop collecting them if (this.maxHeaderPairs <= 0 || this._headers.length < this.maxHeaderPairs) { - ArrayPrototypePushApply(this._headers, headers); + this._headers = this._headers.concat(headers); } this._url += url; } @@ -113,7 +109,7 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, // If parser.maxHeaderPairs <= 0 assume that there's no limit. if (parser.maxHeaderPairs > 0) - n = MathMin(n, parser.maxHeaderPairs); + n = Math.min(n, parser.maxHeaderPairs); incoming._addHeaderLines(headers, n); @@ -138,7 +134,7 @@ function parserOnBody(b, start, len) { // Pretend this was the result of a stream._read call. if (len > 0 && !stream._dumped) { - const slice = TypedArrayPrototypeSlice(b, start, start + len); + const slice = b.slice(start, start + len); const ret = stream.push(slice); if (!ret) readStop(this.socket); @@ -220,7 +216,7 @@ const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/; * See https://tools.ietf.org/html/rfc7230#section-3.2.6 */ function checkIsHttpToken(val) { - return RegExpPrototypeTest(tokenRegExp, val); + return tokenRegExp.test(val); } const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; @@ -231,7 +227,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; * field-vchar = VCHAR / obs-text */ function checkInvalidHeaderChar(val) { - return RegExpPrototypeTest(headerCharRegex, val); + return headerCharRegex.test(val); } function cleanParser(parser) { diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js index 2260eae0aebc33..8d3a1850d449f0 100644 --- a/lib/_http_incoming.js +++ b/lib/_http_incoming.js @@ -22,7 +22,6 @@ 'use strict'; const { - FunctionPrototypeCall, ObjectDefineProperty, ObjectSetPrototypeOf, Symbol @@ -55,7 +54,7 @@ function IncomingMessage(socket) { }; } - FunctionPrototypeCall(Readable, this, streamOptions); + Readable.call(this, streamOptions); this._readableState.readingMore = true; diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 58da505f58ce4b..2dad56a3b09a1d 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -22,7 +22,6 @@ 'use strict'; const { - FunctionPrototype, ObjectDefineProperty, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, @@ -73,7 +72,7 @@ const { CRLF } = common; const kCorked = Symbol('corked'); -const nop = FunctionPrototype; +const nop = function () {}; const RE_CONN_CLOSE = /(?:^|\W)close(?:$|\W)/i; const RE_TE_CHUNKED = common.chunkExpression; diff --git a/lib/_http_server.js b/lib/_http_server.js index 5faefcca264900..d541229164a2db 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -24,13 +24,10 @@ const { ArrayPrototypeForEach, Error, - FunctionPrototype, - FunctionPrototypeCall, ObjectKeys, ObjectSetPrototypeOf, Symbol, SymbolFor, - TypedArrayPrototypeSlice, } = primordials; const net = require('net'); @@ -177,7 +174,7 @@ class HTTPServerAsyncResource { } function ServerResponse(req) { - FunctionPrototypeCall(OutgoingMessage, this); + OutgoingMessage.call(this); if (req.method === 'HEAD') this._hasBody = false; @@ -378,7 +375,7 @@ function Server(options, requestListener) { validateBoolean(insecureHTTPParser, 'options.insecureHTTPParser'); this.insecureHTTPParser = insecureHTTPParser; - FunctionPrototypeCall(net.Server, this, { allowHalfOpen: true }); + net.Server.call(this, { allowHalfOpen: true }); if (requestListener) { this.on('request', requestListener); @@ -639,7 +636,7 @@ function onParserTimeout(server, socket) { socket.destroy(); } -const noop = FunctionPrototype; +const noop = function() {}; const badRequestResponse = Buffer.from( `HTTP/1.1 400 ${STATUS_CODES[400]}${CRLF}` + `Connection: close${CRLF}${CRLF}`, 'ascii' @@ -709,7 +706,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) { const eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade'; if (eventName === 'upgrade' || server.listenerCount(eventName) > 0) { debug('SERVER have listener for %s', eventName); - const bodyHead = TypedArrayPrototypeSlice(d, ret, d.length); + const bodyHead = d.slice(ret, d.length); socket.readableFlowing = null; diff --git a/lib/events.js b/lib/events.js index 15c69c30271aa6..88932ca33573f9 100644 --- a/lib/events.js +++ b/lib/events.js @@ -23,25 +23,14 @@ const { ArrayPrototypeForEach, - ArrayPrototypePush, - ArrayPrototypeSlice, - Boolean, - Error, ErrorCaptureStackTrace, - FunctionPrototypeCall, - MathMin, - NumberIsNaN, - ObjectCreate, ObjectDefineProperty, ObjectDefineProperties, - ObjectGetPrototypeOf, - ObjectSetPrototypeOf, Promise, PromiseReject, PromiseResolve, ReflectApply, ReflectOwnKeys, - String, Symbol, SymbolFor, SymbolAsyncIterator @@ -76,7 +65,7 @@ const kMaxEventTargetListenersWarned = Symbol('events.maxEventTargetListenersWarned'); function EventEmitter(opts) { - FunctionPrototypeCall(EventEmitter.init, this, opts); + EventEmitter.init.call(this, opts); } module.exports = EventEmitter; module.exports.once = once; @@ -131,7 +120,7 @@ ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', { return defaultMaxListeners; }, set: function(arg) { - if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + if (typeof arg !== 'number' || arg < 0 || Number.isNaN(arg)) { throw new ERR_OUT_OF_RANGE('defaultMaxListeners', 'a non-negative number', arg); @@ -185,8 +174,8 @@ EventEmitter.setMaxListeners = EventEmitter.init = function(opts) { if (this._events === undefined || - this._events === ObjectGetPrototypeOf(this)._events) { - this._events = ObjectCreate(null); + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); this._eventsCount = 0; } @@ -217,7 +206,7 @@ function addCatch(that, promise, type, args) { const then = promise.then; if (typeof then === 'function') { - FunctionPrototypeCall(then, promise, undefined, function(err) { + then.call(promise, undefined, function(err) { // The callback is called with nextTick to avoid a follow-up // rejection from this promise. process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args); @@ -279,7 +268,7 @@ function identicalSequenceRange(a, b) { const rest = b.length - pos; if (rest > 3) { let len = 1; - const maxLen = MathMin(a.length - i, rest); + const maxLen = Math.min(a.length - i, rest); // Count the number of consecutive entries. while (maxLen > len && a[i + len] === b[pos + len]) { len++; @@ -663,7 +652,7 @@ function arrayClone(arr) { case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]]; case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]]; } - return ArrayPrototypeSlice(arr); + return arr.slice(); } function unwrapListeners(arr) { @@ -690,7 +679,7 @@ function getEventListeners(emitterOrTarget, type) { while (handler?.listener !== undefined) { const listener = handler.listener?.deref ? handler.listener.deref() : handler.listener; - ArrayPrototypePush(listeners, listener); + listeners.push(listener); handler = handler.next; } return listeners; @@ -738,8 +727,8 @@ async function once(emitter, name, options = {}) { }); } -const AsyncIteratorPrototype = ObjectGetPrototypeOf( - ObjectGetPrototypeOf(async function* () {}).prototype); +const AsyncIteratorPrototype = Object.getPrototypeOf( + Object.getPrototypeOf(async function* () {}).prototype); function createIterResult(value, done) { return { value, done }; @@ -782,7 +771,7 @@ function on(emitter, event, options) { let error = null; let finished = false; - const iterator = ObjectSetPrototypeOf({ + const iterator = Object.setPrototypeOf({ next() { // First, we consume all unread events const value = unconsumedEvents.shift(); @@ -807,7 +796,7 @@ function on(emitter, event, options) { // Wait until an event happens return new Promise(function(resolve, reject) { - ArrayPrototypePush(unconsumedPromises, { resolve, reject }); + unconsumedPromises.push({ resolve, reject }); }); }, @@ -871,7 +860,7 @@ function on(emitter, event, options) { if (promise) { promise.resolve(createIterResult(args, false)); } else { - ArrayPrototypePush(unconsumedEvents, args); + unconsumedEvents.push(args); } } diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index b20b8c6ae76448..43c49fe8af89e8 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -1,14 +1,5 @@ 'use strict'; -const { - BigInt, - Float32Array, - Float64Array, - MathFloor, - Number, - Uint8Array, -} = primordials; - const { ERR_BUFFER_OUT_OF_BOUNDS, ERR_INVALID_ARG_TYPE, diff --git a/lib/internal/http.js b/lib/internal/http.js index badfaa5c4a88d8..3fc19b04ddbd8b 100644 --- a/lib/internal/http.js +++ b/lib/internal/http.js @@ -2,9 +2,6 @@ const { Symbol, - Date, - DatePrototypeGetMilliseconds, - DatePrototypeToUTCString, } = primordials; const { setUnrefTimeout } = require('internal/timers'); @@ -25,8 +22,8 @@ function utcDate() { function cache() { const d = new Date(); - utcCache = DatePrototypeToUTCString(d); - setUnrefTimeout(resetCache, 1000 - DatePrototypeGetMilliseconds(d)); + utcCache = d.toUTCString(); + setUnrefTimeout(resetCache, 1000 - d.getMilliseconds()); } function resetCache() { diff --git a/lib/internal/streams/state.js b/lib/internal/streams/state.js index 83050a62f9cedc..f0a89e07be0693 100644 --- a/lib/internal/streams/state.js +++ b/lib/internal/streams/state.js @@ -1,10 +1,5 @@ 'use strict'; -const { - MathFloor, - NumberIsInteger, -} = primordials; - const { ERR_INVALID_ARG_VALUE } = require('internal/errors').codes; function highWaterMarkFrom(options, isDuplex, duplexKey) { @@ -19,11 +14,11 @@ function getDefaultHighWaterMark(objectMode) { function getHighWaterMark(state, options, duplexKey, isDuplex) { const hwm = highWaterMarkFrom(options, isDuplex, duplexKey); if (hwm != null) { - if (!NumberIsInteger(hwm) || hwm < 0) { + if (!Number.isInteger(hwm) || hwm < 0) { const name = isDuplex ? `options.${duplexKey}` : 'options.highWaterMark'; throw new ERR_INVALID_ARG_VALUE(name, hwm); } - return MathFloor(hwm); + return Math.floor(hwm); } // Default value diff --git a/lib/net.js b/lib/net.js index 826cffd234852d..f6dcaff899f934 100644 --- a/lib/net.js +++ b/lib/net.js @@ -22,20 +22,8 @@ 'use strict'; const { - ArrayIsArray, - ArrayPrototypeIndexOf, - ArrayPrototypePush, - ArrayPrototypeSplice, - Boolean, - Error, - FunctionPrototype, - FunctionPrototypeCall, - Number, - NumberIsNaN, - NumberParseInt, ObjectDefineProperty, ObjectSetPrototypeOf, - ReflectApply, Symbol, } = primordials; @@ -132,7 +120,7 @@ const DEFAULT_IPV6_ADDR = '::'; const isWindows = process.platform === 'win32'; -const noop = FunctionPrototype; +const noop = function () {}; function getFlags(ipv6Only) { return ipv6Only === true ? TCPConstants.UV_TCP_IPV6ONLY : 0; @@ -305,7 +293,7 @@ function Socket(options) { options.autoDestroy = true; // Handle strings directly. options.decodeStrings = false; - ReflectApply(stream.Duplex, this, [options]); + stream.Duplex.call(this, options); if (options.handle) { this._handle = options.handle; // private @@ -441,8 +429,8 @@ function afterShutdown() { // is overly vague, and makes it seem like the user's code is to blame. function writeAfterFIN(chunk, encoding, cb) { if (!this.writableEnded) { - return ReflectApply( - stream.Duplex.prototype.write, this, [chunk, encoding, cb]); + return + stream.Duplex.prototype.write.call(this, chunk, encoding, cb); } if (typeof encoding === 'function') { @@ -586,7 +574,7 @@ Socket.prototype._read = function(n) { Socket.prototype.end = function(data, encoding, callback) { - ReflectApply(stream.Duplex.prototype.end, this, [data, encoding, callback]); + stream.Duplex.prototype.end.call(this, data, encoding, callback); DTRACE_NET_STREAM_END(this); return this; }; @@ -602,7 +590,7 @@ Socket.prototype.pause = function() { this.destroy(errnoException(err, 'read')); } } - return FunctionPrototypeCall(stream.Duplex.prototype.pause, this); + return stream.Duplex.prototype.pause.call(this); }; @@ -611,7 +599,7 @@ Socket.prototype.resume = function() { !this._handle.reading) { tryReadStart(this); } - return FunctionPrototypeCall(stream.Duplex.prototype.resume, this); + return stream.Duplex.prototype.resume.call(this); }; @@ -620,7 +608,7 @@ Socket.prototype.read = function(n) { !this._handle.reading) { tryReadStart(this); } - return ReflectApply(stream.Duplex.prototype.read, this, [n]); + return stream.Duplex.prototype.read.call(this, n); }; @@ -808,7 +796,7 @@ protoGetter('bytesWritten', function bytesWritten() { Buffer.byteLength(el.chunk, el.encoding); } - if (ArrayIsArray(data)) { + if (Array.isArray(data)) { // Was a writev, iterate over chunks to get total length for (let i = 0; i < data.length; i++) { const chunk = data[i]; @@ -1169,7 +1157,7 @@ function Server(options, connectionListener) { if (!(this instanceof Server)) return new Server(options, connectionListener); - FunctionPrototypeCall(EventEmitter, this); + EventEmitter.call(this); if (typeof options === 'function') { connectionListener = options; @@ -1226,8 +1214,8 @@ function createServerHandle(address, port, addressType, fd, flags) { } else if (port === -1 && addressType === -1) { handle = new Pipe(PipeConstants.SERVER); if (isWindows) { - const instances = NumberParseInt(process.env.NODE_PENDING_PIPE_INSTANCES); - if (!NumberIsNaN(instances)) { + const instances = Number.parseInt(process.env.NODE_PENDING_PIPE_INSTANCES); + if (!Number.isNaN(instances)) { handle.setPendingInstances(instances); } } @@ -1681,10 +1669,10 @@ ObjectDefineProperty(Socket.prototype, '_handle', { Server.prototype._setupWorker = function(socketList) { this._usingWorkers = true; - ArrayPrototypePush(this._workers, socketList); + this._workers.push(socketList); socketList.once('exit', (socketList) => { - const index = ArrayPrototypeIndexOf(this._workers, socketList); - ArrayPrototypeSplice(this._workers, index, 1); + const index = this._workers.indexOf(socketList); + this._workers.splice(index, 1); }); }; From 590a5453562e1a95c6012714b2c6c34261324187 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 14 Apr 2021 23:42:39 +0200 Subject: [PATCH 5/8] fixup --- lib/events.js | 14 +++++++------- lib/internal/async_hooks.js | 29 +++++++++++------------------ lib/internal/buffer.js | 10 +++++----- lib/internal/timers.js | 18 ++++++------------ lib/net.js | 2 +- 5 files changed, 30 insertions(+), 43 deletions(-) diff --git a/lib/events.js b/lib/events.js index 88932ca33573f9..2612c13d7cfb76 100644 --- a/lib/events.js +++ b/lib/events.js @@ -146,7 +146,7 @@ ObjectDefineProperties(EventEmitter, { EventEmitter.setMaxListeners = function(n = defaultMaxListeners, ...eventTargets) { - if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) + if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); if (eventTargets.length === 0) { defaultMaxListeners = n; @@ -241,7 +241,7 @@ function emitUnhandledRejectionOrErr(ee, err, type, args) { // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { - if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) { throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); } this._maxListeners = n; @@ -392,7 +392,7 @@ function _addListener(target, type, listener, prepend) { events = target._events; if (events === undefined) { - events = target._events = ObjectCreate(null); + events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before @@ -504,7 +504,7 @@ EventEmitter.prototype.removeListener = if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) - this._events = ObjectCreate(null); + this._events = Object.create(null); else { delete events[type]; if (events.removeListener) @@ -552,11 +552,11 @@ EventEmitter.prototype.removeAllListeners = // Not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { - this._events = ObjectCreate(null); + this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) - this._events = ObjectCreate(null); + this._events = Object.create(null); else delete events[type]; } @@ -570,7 +570,7 @@ EventEmitter.prototype.removeAllListeners = this.removeAllListeners(key); } this.removeAllListeners('removeListener'); - this._events = ObjectCreate(null); + this._events = Object.create(null); this._eventsCount = 0; return this; } diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js index 69ca8d6db987ed..222d66a2ead5dc 100644 --- a/lib/internal/async_hooks.js +++ b/lib/internal/async_hooks.js @@ -1,15 +1,8 @@ 'use strict'; const { - ArrayPrototypePop, - ArrayPrototypeSlice, - ArrayPrototypeUnshift, - ErrorCaptureStackTrace, - FunctionPrototypeBind, - ObjectPrototypeHasOwnProperty, ObjectDefineProperty, Promise, - ReflectApply, Symbol, } = primordials; @@ -129,16 +122,16 @@ function callbackTrampoline(asyncId, resource, cb, ...args) { let result; if (asyncId === 0 && typeof domain_cb === 'function') { - ArrayPrototypeUnshift(args, cb); - result = ReflectApply(domain_cb, this, args); + args.unshift(cb); + result = Reflect.apply(domain_cb, this, args); } else { - result = ReflectApply(cb, this, args); + result = Reflect.apply(cb, this, args); } if (asyncId !== 0 && hasHooks(kAfter)) emitAfterNative(asyncId); - ArrayPrototypePop(execution_async_resources); + execution_async_resources.pop(); return result; } @@ -170,7 +163,7 @@ function fatalError(e) { process._rawDebug(e.stack); } else { const o = inspectExceptionValue(e); - ErrorCaptureStackTrace(o, fatalError); + Error.captureStackTrace(o, fatalError); process._rawDebug(o.stack); } @@ -256,7 +249,7 @@ function emitHook(symbol, asyncId) { } function emitHookFactory(symbol, name) { - const fn = FunctionPrototypeBind(emitHook, undefined, symbol); + const fn = emitHook.bind(undefined, symbol); // Set the name property of the function as it looks good in the stack trace. ObjectDefineProperty(fn, 'name', { @@ -281,7 +274,7 @@ function getHookArrays() { function storeActiveHooks() { - active_hooks.tmp_array = ArrayPrototypeSlice(active_hooks.array); + active_hooks.tmp_array = active_hooks.array.slice(); // Don't want to make the assumption that kInit to kDestroy are indexes 0 to // 4. So do this the long way. active_hooks.tmp_fields = []; @@ -402,7 +395,7 @@ function newAsyncId() { } function getOrSetAsyncId(object) { - if (ObjectPrototypeHasOwnProperty(object, async_id_symbol)) { + if (object.hasOwnProperty(async_id_symbol)) { return object[async_id_symbol]; } @@ -429,14 +422,14 @@ function clearDefaultTriggerAsyncId() { function defaultTriggerAsyncIdScope(triggerAsyncId, block, ...args) { if (triggerAsyncId === undefined) - return ReflectApply(block, null, args); + return Reflect.apply(block, null, args); // CHECK(NumberIsSafeInteger(triggerAsyncId)) // CHECK(triggerAsyncId > 0) const oldDefaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId]; async_id_fields[kDefaultTriggerAsyncId] = triggerAsyncId; try { - return ReflectApply(block, null, args); + return Reflect.apply(block, null, args); } finally { async_id_fields[kDefaultTriggerAsyncId] = oldDefaultTriggerAsyncId; } @@ -533,7 +526,7 @@ function popAsyncContext(asyncId) { const offset = stackLength - 1; async_id_fields[kExecutionAsyncId] = async_wrap.async_ids_stack[2 * offset]; async_id_fields[kTriggerAsyncId] = async_wrap.async_ids_stack[2 * offset + 1]; - ArrayPrototypePop(execution_async_resources); + execution_async_resources.pop(); async_hook_fields[kStackLength] = offset; return offset > 0; } diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 43c49fe8af89e8..6fcb5887812f8e 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -66,7 +66,7 @@ function checkInt(value, min, max, buf, offset, byteLength) { } function boundsError(value, length, type) { - if (MathFloor(value) !== value) { + if (Math.floor(value) !== value) { validateNumber(value, type); throw new ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value); } @@ -649,7 +649,7 @@ function writeU_Int48LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 5); - const newVal = MathFloor(value * 2 ** -32); + const newVal = Math.floor(value * 2 ** -32); buf[offset++] = value; value = value >>> 8; buf[offset++] = value; @@ -674,7 +674,7 @@ function writeU_Int40LE(buf, value, offset, min, max) { buf[offset++] = value; value = value >>> 8; buf[offset++] = value; - buf[offset++] = MathFloor(newVal * 2 ** -32); + buf[offset++] = Math.floor(newVal * 2 ** -32); return offset; } @@ -760,7 +760,7 @@ function writeU_Int48BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 5); - const newVal = MathFloor(value * 2 ** -32); + const newVal = Math.floor(value * 2 ** -32); buf[offset++] = (newVal >>> 8); buf[offset++] = newVal; buf[offset + 3] = value; @@ -777,7 +777,7 @@ function writeU_Int40BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 4); - buf[offset++] = MathFloor(value * 2 ** -32); + buf[offset++] = Math.floor(value * 2 ** -32); buf[offset + 3] = value; value = value >>> 8; buf[offset + 2] = value; diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 9521c343038b4f..bd7cfdf3bfe85f 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -73,13 +73,7 @@ // have shown to be trivial in comparison to other timers architectures. const { - MathMax, - MathTrunc, - NumberIsFinite, - NumberMIN_SAFE_INTEGER, - ObjectCreate, Symbol, - ReflectApply, } = primordials; const { @@ -132,7 +126,7 @@ const kHasOutstanding = 2; // Timeout values > TIMEOUT_MAX are set to 1. const TIMEOUT_MAX = 2 ** 31 - 1; -let timerListId = NumberMIN_SAFE_INTEGER; +let timerListId = Number.MIN_SAFE_INTEGER; const kRefed = Symbol('refed'); @@ -152,7 +146,7 @@ const timerListQueue = new PriorityQueue(compareTimersLists, setPosition); // // - key = time in milliseconds // - value = linked list -const timerListMap = ObjectCreate(null); +const timerListMap = Object.create(null); function initAsyncResource(resource, type) { const asyncId = resource[async_id_symbol] = newAsyncId(); @@ -349,7 +343,7 @@ function insertGuarded(item, refed, start) { function insert(item, msecs, start = getLibuvNow()) { // Truncate so that accuracy of sub-millisecond timers is not assumed. - msecs = MathTrunc(msecs); + msecs = Math.trunc(msecs); item._idleStart = start; // Use an existing list if there is one, otherwise we need to make a new one. @@ -382,7 +376,7 @@ function setUnrefTimeout(callback, after) { // Type checking used by timers.enroll() and Socket#setTimeout() function getTimerDuration(msecs, name) { validateNumber(msecs, name); - if (msecs < 0 || !NumberIsFinite(msecs)) { + if (msecs < 0 || !Number.isFinite(msecs)) { throw new ERR_OUT_OF_RANGE(name, 'a non-negative finite number', msecs); } @@ -515,7 +509,7 @@ function getTimerCallbacks(runNextTicks) { // Check if this loop iteration is too early for the next timer. // This happens if there are more timers scheduled for later in the list. if (diff < msecs) { - list.expiry = MathMax(timer._idleStart + msecs, now + 1); + list.expiry = Math.max(timer._idleStart + msecs, now + 1); list.id = timerListId++; timerListQueue.percolateDown(1); debug('%d list wait because diff is %d', msecs, diff); @@ -556,7 +550,7 @@ function getTimerCallbacks(runNextTicks) { if (args === undefined) timer._onTimeout(); else - ReflectApply(timer._onTimeout, timer, args); + Reflect.apply(timer._onTimeout, timer, args); } finally { if (timer._repeat && timer._idleTimeout !== -1) { timer._idleTimeout = timer._repeat; diff --git a/lib/net.js b/lib/net.js index f6dcaff899f934..64b6b6cd8ee2ba 100644 --- a/lib/net.js +++ b/lib/net.js @@ -907,7 +907,7 @@ Socket.prototype.connect = function(...args) { // already been normalized (so we don't normalize more than once). This has // been solved before in https://github.com/nodejs/node/pull/12342, but was // reverted as it had unintended side effects. - if (ArrayIsArray(args[0]) && args[0][normalizedArgsSymbol]) { + if (Array.isArray(args[0]) && args[0][normalizedArgsSymbol]) { normalized = args[0]; } else { normalized = normalizeArgs(args); From dbbdd596835b45eebfc07e58f2c11adca281d46e Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 15 Apr 2021 10:24:51 +0200 Subject: [PATCH 6/8] fixhup: less primordials in hot path --- lib/internal/fixed_queue.js | 4 ---- lib/internal/stream_base_commons.js | 1 - lib/internal/util.js | 20 +++++++++----------- lib/timers.js | 3 +-- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/internal/fixed_queue.js b/lib/internal/fixed_queue.js index f6f3110d8ec5d4..673edce6523cb3 100644 --- a/lib/internal/fixed_queue.js +++ b/lib/internal/fixed_queue.js @@ -1,9 +1,5 @@ 'use strict'; -const { - Array, -} = primordials; - // Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two. const kSize = 2048; const kMask = kSize - 1; diff --git a/lib/internal/stream_base_commons.js b/lib/internal/stream_base_commons.js index 5254fc1553dd77..49e7bd0ae6851d 100644 --- a/lib/internal/stream_base_commons.js +++ b/lib/internal/stream_base_commons.js @@ -1,7 +1,6 @@ 'use strict'; const { - Array, Symbol, } = primordials; diff --git a/lib/internal/util.js b/lib/internal/util.js index 46eabc6f08c092..0c8dc3d6cc5f89 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -3,7 +3,6 @@ const { ArrayFrom, ArrayIsArray, - ArrayPrototypePop, ArrayPrototypePush, ArrayPrototypeSlice, ArrayPrototypeSort, @@ -22,7 +21,6 @@ const { SafeMap, SafeSet, StringPrototypeReplace, - StringPrototypeToLowerCase, StringPrototypeToUpperCase, Symbol, SymbolFor, @@ -141,13 +139,13 @@ function slowCases(enc) { case 4: if (enc === 'UTF8') return 'utf8'; if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le'; - enc = StringPrototypeToLowerCase(`${enc}`); + enc = `${enc}`.toLowerCase(); if (enc === 'utf8') return 'utf8'; if (enc === 'ucs2') return 'utf16le'; break; case 3: if (enc === 'hex' || enc === 'HEX' || - StringPrototypeToLowerCase(`${enc}`) === 'hex') + `${enc}`.toLowerCase() === 'hex') return 'hex'; break; case 5: @@ -156,7 +154,7 @@ function slowCases(enc) { if (enc === 'UTF-8') return 'utf8'; if (enc === 'ASCII') return 'ascii'; if (enc === 'UCS-2') return 'utf16le'; - enc = StringPrototypeToLowerCase(`${enc}`); + enc = `${enc}`.toLowerCase(); if (enc === 'utf-8') return 'utf8'; if (enc === 'ascii') return 'ascii'; if (enc === 'ucs-2') return 'utf16le'; @@ -166,23 +164,23 @@ function slowCases(enc) { if (enc === 'latin1' || enc === 'binary') return 'latin1'; if (enc === 'BASE64') return 'base64'; if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1'; - enc = StringPrototypeToLowerCase(`${enc}`); + enc = `${enc}`.toLowerCase(); if (enc === 'base64') return 'base64'; if (enc === 'latin1' || enc === 'binary') return 'latin1'; break; case 7: if (enc === 'utf16le' || enc === 'UTF16LE' || - StringPrototypeToLowerCase(`${enc}`) === 'utf16le') + `${enc}`.toLowerCase() === 'utf16le') return 'utf16le'; break; case 8: if (enc === 'utf-16le' || enc === 'UTF-16LE' || - StringPrototypeToLowerCase(`${enc}`) === 'utf-16le') + `${enc}`.toLowerCase() === 'utf-16le') return 'utf16le'; break; case 9: if (enc === 'base64url' || enc === 'BASE64URL' || - StringPrototypeToLowerCase(`${enc}`) === 'base64url') + `${enc}`.toLowerCase() === 'base64url') return 'base64url'; break; default: @@ -202,7 +200,7 @@ function filterDuplicateStrings(items, low) { const map = new SafeMap(); for (let i = 0; i < items.length; i++) { const item = items[i]; - const key = StringPrototypeToLowerCase(item); + const key = item.toLowerCase(); if (low) { map.set(key, key); } else { @@ -359,7 +357,7 @@ function join(output, separator) { function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; - ArrayPrototypePop(list); + list.pop(); } const kNodeModulesRE = /^(.*)[\\/]node_modules[\\/]/; diff --git a/lib/timers.js b/lib/timers.js index 73844fdbcc7613..18e7da2a074582 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -22,7 +22,6 @@ 'use strict'; const { - MathTrunc, ObjectCreate, ObjectDefineProperty, SymbolToPrimitive @@ -97,7 +96,7 @@ function unenroll(item) { // That function could then be used by http and other similar modules. if (item[kRefed]) { // Compliment truncation during insert(). - const msecs = MathTrunc(item._idleTimeout); + const msecs = Math.trunc(item._idleTimeout); const list = timerListMap[msecs]; if (list !== undefined && L.isEmpty(list)) { debug('unenroll: list empty'); From 455352630771d93f2bc51ad24fa1f61869ea0128 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 15 Apr 2021 15:36:51 +0200 Subject: [PATCH 7/8] fixup --- lib/_http_server.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/_http_server.js b/lib/_http_server.js index d541229164a2db..fd5b1b9d492343 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -616,7 +616,7 @@ function socketOnData(server, socket, parser, state, d) { function onRequestTimeout(socket) { socket[kRequestTimeout] = undefined; // socketOnError has additional logic and will call socket.destroy(err). - Reflect.apply(socketOnError, socket, [new ERR_HTTP_REQUEST_TIMEOUT()]); + socketOnError.call(socket, new ERR_HTTP_REQUEST_TIMEOUT()); } function onParserExecute(server, socket, parser, state, ret) { @@ -961,8 +961,7 @@ function unconsume(parser, socket) { function generateSocketListenerWrapper(originalFnName) { return function socketListenerWrap(ev, fn) { - const res = Reflect.apply(net.Socket.prototype[originalFnName], this, - [ev, fn]); + const res = net.Socket.prototype[originalFnName].call(this, ev, fn); if (!this.parser) { this.on = net.Socket.prototype.on; this.addListener = net.Socket.prototype.addListener; From e51967c57c35cfce5589c7372f45e0b5942a391c Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 16 Apr 2021 09:04:17 +0200 Subject: [PATCH 8/8] fixup: remove an always-on primordial in debuglog. --- lib/internal/util/debuglog.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/internal/util/debuglog.js b/lib/internal/util/debuglog.js index 3dc7a5157d5e65..fc79853e2d4aba 100644 --- a/lib/internal/util/debuglog.js +++ b/lib/internal/util/debuglog.js @@ -45,7 +45,7 @@ function emitWarningIfNeeded(set) { } } -const noop = FunctionPrototype; +const noop = function() {}; function debuglogImpl(enabled, set) { if (debugImpls[set] === undefined) { @@ -89,7 +89,9 @@ function debuglog(set, cb) { test = () => enabled; return enabled; }; - const logger = (...args) => debug(...new SafeArrayIterator(args)); + // Do not use primordials here, as it will always be + // called anyway. + const logger = (...args) => debug(...args); ObjectDefineProperty(logger, 'enabled', { get() { return test();