Repository: nodejs/node
Pull request: util: reduce TextEncoder.encodeInto function size

```
<SharedFunctionInfo encodeInto>}: big function, size (117) >= max-size (100)
```

It seems encodeInto function is too big to inline with v8. This is an attempt to reduce the size of the function by eliminating validateEncoder() calls, and replacing them with private attribute calls.

This is a semver-major because it changes the errors thrown if `this` is different.

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1743/

Changed files:
filename: lib/internal/encoding.js
patch: @@ -26,7 +26,6 @@ const kHandle = Symbol('handle');
 const kFlags = Symbol('flags');
 const kEncoding = Symbol('encoding');
 const kDecoder = Symbol('decoder');
-const kEncoder = Symbol('encoder');
 const kFatal = Symbol('kFatal');
 const kUTF8FastPath = Symbol('kUTF8FastPath');
 const kLatin1FastPath = Symbol('kLatin1FastPath');
@@ -61,11 +60,6 @@ const {
 
 const { Buffer } = require('buffer');
 
-function validateEncoder(obj) {
-  if (obj == null || obj[kEncoder] !== true)
-    throw new ERR_INVALID_THIS('TextEncoder');
-}
-
 function validateDecoder(obj) {
   if (obj == null || obj[kDecoder] !== true)
     throw new ERR_INVALID_THIS('TextDecoder');
@@ -338,45 +332,50 @@ function getEncodingFromLabel(label) {
   return encodings.get(trimAsciiWhitespace(label.toLowerCase()));
 }
 
+let lazyInspect;
+
 class TextEncoder {
-  constructor() {
-    this[kEncoder] = true;
+  #encoding = 'utf-8';
+
+  #encode(input) {
+    return encodeUtf8String(`${input}`);
+  }
+
+  #encodeInto(input, dest) {
+    encodeInto(input, dest);
+    // We need to read from the binding here since the buffer gets refreshed
+    // from the snapshot.
+    const { 0: read, 1: written } = encodeIntoResults;
+    return { read, written };
   }
 
   get encoding() {
-    validateEncoder(this);
-    return 'utf-8';
+    return this.#encoding;
   }
 
   encode(input = '') {
-    validateEncoder(this);
-    return encodeUtf8String(`${input}`);
+    return this.#encode(input);
   }
 
   encodeInto(src, dest) {
-    validateEncoder(this);
     validateString(src, 'src');
     if (!dest || !isUint8Array(dest))
       throw new ERR_INVALID_ARG_TYPE('dest', 'Uint8Array', dest);
 
-    encodeInto(src, dest);
-    // We need to read from the binding here since the buffer gets refreshed
-    // from the snapshot.
-    const { 0: read, 1: written } = encodeIntoResults;
-    return { read, written };
+    return this.#encodeInto(src, dest);
   }
 
   [inspect](depth, opts) {
-    validateEncoder(this);
     if (typeof depth === 'number' && depth < 0)
       return this;
     const ctor = getConstructorOf(this);
     const obj = { __proto__: {
       constructor: ctor === null ? TextEncoder : ctor,
     } };
-    obj.encoding = this.encoding;
+    obj.encoding = this.#encoding;
     // Lazy to avoid circular dependency
-    return require('internal/util/inspect').inspect(obj, opts);
+    lazyInspect ??= require('internal/util/inspect').inspect;
+    return lazyInspect(obj, opts);
   }
 }
 

filename: test/parallel/test-whatwg-encoding-custom-interop.js
patch: @@ -46,9 +46,8 @@ assert(TextEncoder);
   const instance = new TextEncoder();
 
   const expectedError = {
-    code: 'ERR_INVALID_THIS',
     name: 'TypeError',
-    message: 'Value of "this" must be of type TextEncoder'
+    message: /from an object whose class did not declare it/,
   };
 
   inspectFn.call(instance, Infinity, {});
@@ -58,7 +57,12 @@ assert(TextEncoder);
   const invalidThisArgs = [{}, [], true, 1, '', new TextDecoder()];
   for (const i of invalidThisArgs) {
     assert.throws(() => inspectFn.call(i, Infinity, {}), expectedError);
-    assert.throws(() => encodeFn.call(i), expectedError);
     assert.throws(() => encodingGetter.call(i), expectedError);
   }
+  for (const i of invalidThisArgs) {
+    assert.throws(() => encodeFn.call(i), {
+      name: 'TypeError',
+      message: 'Receiver must be an instance of class TextEncoder',
+    });
+  }
 }