From d37d55de77f082c31fc7d69fe712354e0ed101d1 Mon Sep 17 00:00:00 2001 From: Rafael Gonzaga Date: Fri, 13 Jan 2023 03:33:29 +0000 Subject: [PATCH] lib: reuse invalid state errors on webstreams Signed-off-by: RafaelGSS PR-URL: https://github.com/nodejs/node/pull/46086 Reviewed-By: Robert Nagy Reviewed-By: Yagiz Nizipli Reviewed-By: Matteo Collina --- lib/internal/webstreams/readablestream.js | 38 +++++++++++++++++++---- lib/internal/webstreams/writablestream.js | 22 ++++++++++--- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index 5344785b90cd3e..6686af777d8775 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -54,6 +54,7 @@ const { isArrayBufferDetached, kEmptyObject, kEnumerableProperty, + SideEffectFreeRegExpPrototypeSymbolReplace, } = require('internal/util'); const { @@ -140,6 +141,32 @@ const kError = Symbol('kError'); const kPull = Symbol('kPull'); const kRelease = Symbol('kRelease'); +let releasedError; +let releasingError; + +const userModuleRegExp = /^ {4}at (?:[^/\\(]+ \()(?!node:(.+):\d+:\d+\)$).*/gm; + +function lazyReadableReleasedError() { + if (releasedError) { + return releasedError; + } + + releasedError = new ERR_INVALID_STATE.TypeError('Reader released'); + // Avoid V8 leak and remove userland stackstrace + releasedError.stack = SideEffectFreeRegExpPrototypeSymbolReplace(userModuleRegExp, releasedError.stack, ''); + return releasedError; +} + +function lazyReadableReleasingError() { + if (releasingError) { + return releasingError; + } + releasingError = new ERR_INVALID_STATE.TypeError('Releasing reader'); + // Avoid V8 leak and remove userland stackstrace + releasingError.stack = SideEffectFreeRegExpPrototypeSymbolReplace(userModuleRegExp, releasingError.stack, ''); + return releasingError; +} + const getNonWritablePropertyDescriptor = (value) => { return { __proto__: null, @@ -2029,7 +2056,7 @@ function readableStreamDefaultReaderRelease(reader) { readableStreamReaderGenericRelease(reader); readableStreamDefaultReaderErrorReadRequests( reader, - new ERR_INVALID_STATE.TypeError('Releasing reader') + lazyReadableReleasingError(), ); } @@ -2044,7 +2071,7 @@ function readableStreamBYOBReaderRelease(reader) { readableStreamReaderGenericRelease(reader); readableStreamBYOBReaderErrorReadIntoRequests( reader, - new ERR_INVALID_STATE.TypeError('Releasing reader') + lazyReadableReleasingError(), ); } @@ -2062,13 +2089,12 @@ function readableStreamReaderGenericRelease(reader) { assert(stream !== undefined); assert(stream[kState].reader === reader); + const releasedStateError = lazyReadableReleasedError(); if (stream[kState].state === 'readable') { - reader[kState].close.reject?.( - new ERR_INVALID_STATE.TypeError('Reader released')); + reader[kState].close.reject?.(releasedStateError); } else { reader[kState].close = { - promise: PromiseReject( - new ERR_INVALID_STATE.TypeError('Reader released')), + promise: PromiseReject(releasedStateError), resolve: undefined, reject: undefined, }; diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js index ba66cea7a4850d..b9b1dfedd04659 100644 --- a/lib/internal/webstreams/writablestream.js +++ b/lib/internal/webstreams/writablestream.js @@ -34,6 +34,7 @@ const { createDeferredPromise, customInspectSymbol: kInspect, kEnumerableProperty, + SideEffectFreeRegExpPrototypeSymbolReplace, } = require('internal/util'); const { @@ -77,6 +78,20 @@ const kAbort = Symbol('kAbort'); const kCloseSentinel = Symbol('kCloseSentinel'); const kError = Symbol('kError'); +let releasedError; + +function lazyWritableReleasedError() { + if (releasedError) { + return releasedError; + } + const userModuleRegExp = /^ {4}at (?:[^/\\(]+ \()(?!node:(.+):\d+:\d+\)$).*/gm; + + releasedError = new ERR_INVALID_STATE.TypeError('Writer has been released'); + // Avoid V8 leak and remove userland stackstrace + releasedError.stack = SideEffectFreeRegExpPrototypeSymbolReplace(userModuleRegExp, releasedError.stack, ''); + return releasedError; +} + const getNonWritablePropertyDescriptor = (value) => { return { __proto__: null, @@ -970,10 +985,9 @@ function writableStreamDefaultWriterRelease(writer) { } = writer[kState]; assert(stream !== undefined); assert(stream[kState].writer === writer); - const releasedError = - new ERR_INVALID_STATE.TypeError('Writer has been released'); - writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); - writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); + const releasedStateError = lazyWritableReleasedError(); + writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedStateError); + writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedStateError); stream[kState].writer = undefined; writer[kState].stream = undefined; }