From 29a03a9dcaaaa819db6260e0adfcc0a533d5c41a Mon Sep 17 00:00:00 2001
From: Antoine du Hamel <duhamelantoine1995@gmail.com>
Date: Mon, 1 Feb 2021 15:36:48 +0100
Subject: [PATCH 1/2] Revert "stream: refactor to avoid unsafe array iteration"

This reverts commit 4ad46e2fefba1b3b4d02a978bdd7e65338854960.
---
 lib/internal/streams/readable.js |  9 ++++-----
 lib/internal/streams/writable.js | 13 ++++++-------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/lib/internal/streams/readable.js b/lib/internal/streams/readable.js
index 6667c919c086a7..3479dd970b5543 100644
--- a/lib/internal/streams/readable.js
+++ b/lib/internal/streams/readable.js
@@ -22,7 +22,6 @@
 'use strict';
 
 const {
-  ArrayPrototypeForEach,
   ArrayPrototypeIndexOf,
   ArrayPrototypePush,
   ArrayPrototypeSplice,
@@ -855,8 +854,8 @@ 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;
   }
 
@@ -1057,11 +1056,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);
     }
-  });
+  }
 
   return this;
 };
diff --git a/lib/internal/streams/writable.js b/lib/internal/streams/writable.js
index 2fe811236a27e8..2324dc579dc514 100644
--- a/lib/internal/streams/writable.js
+++ b/lib/internal/streams/writable.js
@@ -26,7 +26,6 @@
 'use strict';
 
 const {
-  ArrayPrototypeForEach,
   ArrayPrototypePush,
   ArrayPrototypeSlice,
   ArrayPrototypeSplice,
@@ -522,10 +521,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 ArrayPrototypeSplice(state[kOnFinished], 0)) {
+    callback(new ERR_STREAM_DESTROYED('end'));
+  }
 
   resetBuffer(state);
 }
@@ -745,8 +743,9 @@ function finish(stream, state) {
 
   state.finished = true;
 
-  ArrayPrototypeForEach(ArrayPrototypeSplice(state[kOnFinished], 0),
-                        (callback) => callback());
+  for (const callback of ArrayPrototypeSplice(state[kOnFinished], 0)) {
+    callback();
+  }
 
   stream.emit('finish');
 

From 873876285e06ce144cf763616bf43434515b7723 Mon Sep 17 00:00:00 2001
From: Antoine du Hamel <duhamelantoine1995@gmail.com>
Date: Mon, 1 Feb 2021 15:37:07 +0100
Subject: [PATCH 2/2] Revert "stream: refactor to use more primordials"

This reverts commit 419686cdfbb3429c512f18bc10c06a8cf5f32cf7.
---
 lib/internal/streams/buffer_list.js           | 16 ++---
 lib/internal/streams/destroy.js               | 11 +--
 lib/internal/streams/end-of-stream.js         | 20 ++----
 lib/internal/streams/from.js                  |  4 +-
 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              | 37 ++++------
 lib/internal/streams/transform.js             |  9 +--
 lib/internal/streams/writable.js              | 67 ++++++++++---------
 test/parallel/test-stream-pipe-await-drain.js |  2 +-
 12 files changed, 80 insertions(+), 112 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 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 3479dd970b5543..d0424edc1fa32b 100644
--- a/lib/internal/streams/readable.js
+++ b/lib/internal/streams/readable.js
@@ -22,12 +22,6 @@
 'use strict';
 
 const {
-  ArrayPrototypeIndexOf,
-  ArrayPrototypePush,
-  ArrayPrototypeSplice,
-  FunctionPrototype,
-  FunctionPrototypeBind,
-  FunctionPrototypeCall,
   NumberIsInteger,
   NumberIsNaN,
   NumberParseInt,
@@ -35,8 +29,7 @@ const {
   ObjectKeys,
   ObjectSetPrototypeOf,
   Promise,
-  ReflectApply,
-  SafeSet,
+  Set,
   SymbolAsyncIterator,
   Symbol
 } = primordials;
@@ -77,7 +70,7 @@ let from;
 
 ObjectSetPrototypeOf(Readable.prototype, Stream.prototype);
 ObjectSetPrototypeOf(Readable, Stream);
-const nop = FunctionPrototype;
+function nop() {}
 
 const { errorOrDestroy } = destroyImpl;
 
@@ -207,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) {
@@ -661,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) &&
@@ -860,11 +853,11 @@ Readable.prototype.unpipe = function(dest) {
   }
 
   // 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();
 
@@ -876,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') {
@@ -906,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
@@ -924,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
@@ -1058,7 +1049,7 @@ Readable.prototype.wrap = function(stream) {
   // Proxy all the other methods. Important when wrapping filters and duplexes.
   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);
     }
   }
 
@@ -1109,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 2324dc579dc514..2510398d999fe1 100644
--- a/lib/internal/streams/writable.js
+++ b/lib/internal/streams/writable.js
@@ -26,16 +26,11 @@
 'use strict';
 
 const {
-  ArrayPrototypePush,
-  ArrayPrototypeSlice,
-  ArrayPrototypeSplice,
+  FunctionPrototype,
   Error,
-  FunctionPrototypeCall,
-  FunctionPrototypeSymbolHasInstance,
   ObjectDefineProperty,
   ObjectDefineProperties,
   ObjectSetPrototypeOf,
-  StringPrototypeToLowerCase,
   Symbol,
   SymbolHasInstance,
 } = primordials;
@@ -211,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', {
@@ -220,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`
@@ -233,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);
@@ -257,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;
@@ -270,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());
@@ -356,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;
@@ -521,7 +528,7 @@ function errorBuffer(state) {
     callback(new ERR_STREAM_DESTROYED('write'));
   }
 
-  for (const callback of ArrayPrototypeSplice(state[kOnFinished], 0)) {
+  for (const callback of state[kOnFinished].splice(0)) {
     callback(new ERR_STREAM_DESTROYED('end'));
   }
 
@@ -557,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);
@@ -575,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;
@@ -643,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);
     }
   }
 
@@ -666,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);
@@ -684,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)
@@ -696,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);
           });
@@ -743,7 +748,7 @@ function finish(stream, state) {
 
   state.finished = true;
 
-  for (const callback of ArrayPrototypeSplice(state[kOnFinished], 0)) {
+  for (const callback of state[kOnFinished].splice(0)) {
     callback();
   }
 
@@ -861,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