GeezerVison is showing github.com — stream: use bit fields for construct/destroy · nodejs/node@98ae1b4
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/streams/destroy.js +45-21Lines changed: 45 additions & 21 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -15,6 +15,15 @@ const { | 15 | 15 | isDestroyed, | 16 | 16 | isFinished, | 17 | 17 | isServerRequest, | | 18 | + kState, | | 19 | + kErrorEmitted, | | 20 | + kEmitClose, | | 21 | + kClosed, | | 22 | + kCloseEmitted, | | 23 | + kConstructed, | | 24 | + kDestroyed, | | 25 | + kAutoDestroy, | | 26 | + kErrored, | 18 | 27 | } = require('internal/streams/utils'); | 19 | 28 |
| 20 | 29 | const kDestroy = Symbol('kDestroy'); | @@ -42,7 +51,10 @@ function destroy(err, cb) { | 42 | 51 | // With duplex streams we use the writable side for state. | 43 | 52 | const s = w || r; | 44 | 53 |
| 45 | | - if (w?.destroyed || r?.destroyed) { | | 54 | + if ( | | 55 | + (w && (w[kState] & kDestroyed) !== 0) || | | 56 | + (r && (r[kState] & kDestroyed) !== 0) | | 57 | + ) { | 46 | 58 | if (typeof cb === 'function') { | 47 | 59 | cb(); | 48 | 60 | } | @@ -56,14 +68,14 @@ function destroy(err, cb) { | 56 | 68 | checkError(err, w, r); | 57 | 69 |
| 58 | 70 | if (w) { | 59 | | - w.destroyed = true; | | 71 | + w[kState] |= kDestroyed; | 60 | 72 | } | 61 | 73 | if (r) { | 62 | | - r.destroyed = true; | | 74 | + r[kState] |= kDestroyed; | 63 | 75 | } | 64 | 76 |
| 65 | 77 | // If still constructing then defer calling _destroy. | 66 | | - if (!s.constructed) { | | 78 | + if ((s[kState] & kConstructed) === 0) { | 67 | 79 | this.once(kDestroy, function(er) { | 68 | 80 | _destroy(this, aggregateTwoErrors(er, err), cb); | 69 | 81 | }); | @@ -89,10 +101,10 @@ function _destroy(self, err, cb) { | 89 | 101 | checkError(err, w, r); | 90 | 102 |
| 91 | 103 | if (w) { | 92 | | - w.closed = true; | | 104 | + w[kState] |= kClosed; | 93 | 105 | } | 94 | 106 | if (r) { | 95 | | - r.closed = true; | | 107 | + r[kState] |= kClosed; | 96 | 108 | } | 97 | 109 |
| 98 | 110 | if (typeof cb === 'function') { | @@ -122,13 +134,16 @@ function emitCloseNT(self) { | 122 | 134 | const w = self._writableState; | 123 | 135 |
| 124 | 136 | if (w) { | 125 | | - w.closeEmitted = true; | | 137 | + w[kState] |= kCloseEmitted; | 126 | 138 | } | 127 | 139 | if (r) { | 128 | | - r.closeEmitted = true; | | 140 | + r[kState] |= kCloseEmitted; | 129 | 141 | } | 130 | 142 |
| 131 | | - if (w?.emitClose || r?.emitClose) { | | 143 | + if ( | | 144 | + (w && (w[kState] & kEmitClose) !== 0) || | | 145 | + (r && (r[kState] & kEmitClose) !== 0) | | 146 | + ) { | 132 | 147 | self.emit('close'); | 133 | 148 | } | 134 | 149 | } | @@ -137,15 +152,18 @@ function emitErrorNT(self, err) { | 137 | 152 | const r = self._readableState; | 138 | 153 | const w = self._writableState; | 139 | 154 |
| 140 | | - if (w?.errorEmitted || r?.errorEmitted) { | | 155 | + if ( | | 156 | + (w && (w[kState] & kErrorEmitted) !== 0) || | | 157 | + (r && (r[kState] & kErrorEmitted) !== 0) | | 158 | + ) { | 141 | 159 | return; | 142 | 160 | } | 143 | 161 |
| 144 | 162 | if (w) { | 145 | | - w.errorEmitted = true; | | 163 | + w[kState] |= kErrorEmitted; | 146 | 164 | } | 147 | 165 | if (r) { | 148 | | - r.errorEmitted = true; | | 166 | + r[kState] |= kErrorEmitted; | 149 | 167 | } | 150 | 168 |
| 151 | 169 | self.emit('error', err); | @@ -192,20 +210,26 @@ function errorOrDestroy(stream, err, sync) { | 192 | 210 | const r = stream._readableState; | 193 | 211 | const w = stream._writableState; | 194 | 212 |
| 195 | | - if (w?.destroyed || r?.destroyed) { | | 213 | + if ( | | 214 | + (w && (w[kState] ? (w[kState] & kDestroyed) !== 0 : w.destroyed)) || | | 215 | + (r && (r[kState] ? (r[kState] & kDestroyed) !== 0 : r.destroyed)) | | 216 | + ) { | 196 | 217 | return this; | 197 | 218 | } | 198 | 219 |
| 199 | | - if (r?.autoDestroy || w?.autoDestroy) | | 220 | + if ( | | 221 | + (r && (r[kState] & kAutoDestroy) !== 0) || | | 222 | + (w && (w[kState] & kAutoDestroy) !== 0) | | 223 | + ) { | 200 | 224 | stream.destroy(err); | 201 | | - else if (err) { | | 225 | + } else if (err) { | 202 | 226 | // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 | 203 | 227 | err.stack; // eslint-disable-line no-unused-expressions | 204 | 228 |
| 205 | | - if (w && !w.errored) { | | 229 | + if (w && (w[kState] & kErrored) === 0) { | 206 | 230 | w.errored = err; | 207 | 231 | } | 208 | | - if (r && !r.errored) { | | 232 | + if (r && (r[kState] & kErrored) === 0) { | 209 | 233 | r.errored = err; | 210 | 234 | } | 211 | 235 | if (sync) { | @@ -225,10 +249,10 @@ function construct(stream, cb) { | 225 | 249 | const w = stream._writableState; | 226 | 250 |
| 227 | 251 | if (r) { | 228 | | - r.constructed = false; | | 252 | + r[kState] &= ~kConstructed; | 229 | 253 | } | 230 | 254 | if (w) { | 231 | | - w.constructed = false; | | 255 | + w[kState] &= ~kConstructed; | 232 | 256 | } | 233 | 257 |
| 234 | 258 | stream.once(kConstruct, cb); | @@ -256,10 +280,10 @@ function constructNT(stream) { | 256 | 280 | const s = w || r; | 257 | 281 |
| 258 | 282 | if (r) { | 259 | | - r.constructed = true; | | 283 | + r[kState] |= kConstructed; | 260 | 284 | } | 261 | 285 | if (w) { | 262 | | - w.constructed = true; | | 286 | + w[kState] |= kConstructed; | 263 | 287 | } | 264 | 288 |
| 265 | 289 | if (s.destroyed) { | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/streams/readable.js +25-22Lines changed: 25 additions & 22 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -58,6 +58,20 @@ const { | 58 | 58 | getHighWaterMark, | 59 | 59 | getDefaultHighWaterMark, | 60 | 60 | } = require('internal/streams/state'); | | 61 | +const { | | 62 | + kState, | | 63 | + // bitfields | | 64 | + kObjectMode, | | 65 | + kErrorEmitted, | | 66 | + kAutoDestroy, | | 67 | + kEmitClose, | | 68 | + kDestroyed, | | 69 | + kClosed, | | 70 | + kCloseEmitted, | | 71 | + kErrored, | | 72 | + kConstructed, | | 73 | + kOnConstructed, | | 74 | +} = require('internal/streams/utils'); | 61 | 75 |
| 62 | 76 | const { | 63 | 77 | aggregateTwoErrors, | @@ -72,9 +86,7 @@ const { | 72 | 86 | AbortError, | 73 | 87 | } = require('internal/errors'); | 74 | 88 | const { validateObject } = require('internal/validators'); | 75 | | -const { kOnConstructed } = require('internal/streams/utils'); | 76 | 89 |
| 77 | | -const kState = Symbol('kState'); | 78 | 90 | const FastBuffer = Buffer[SymbolSpecies]; | 79 | 91 |
| 80 | 92 | const { StringDecoder } = require('string_decoder'); | @@ -91,26 +103,17 @@ const kDefaultEncodingValue = Symbol('kDefaultEncodingValue'); | 91 | 103 | const kDecoderValue = Symbol('kDecoderValue'); | 92 | 104 | const kEncodingValue = Symbol('kEncodingValue'); | 93 | 105 |
| 94 | | -const kObjectMode = 1 << 0; | 95 | | -const kEnded = 1 << 1; | 96 | | -const kEndEmitted = 1 << 2; | 97 | | -const kReading = 1 << 3; | 98 | | -const kConstructed = 1 << 4; | 99 | | -const kSync = 1 << 5; | 100 | | -const kNeedReadable = 1 << 6; | 101 | | -const kEmittedReadable = 1 << 7; | 102 | | -const kReadableListening = 1 << 8; | 103 | | -const kResumeScheduled = 1 << 9; | 104 | | -const kErrorEmitted = 1 << 10; | 105 | | -const kEmitClose = 1 << 11; | 106 | | -const kAutoDestroy = 1 << 12; | 107 | | -const kDestroyed = 1 << 13; | 108 | | -const kClosed = 1 << 14; | 109 | | -const kCloseEmitted = 1 << 15; | 110 | | -const kMultiAwaitDrain = 1 << 16; | 111 | | -const kReadingMore = 1 << 17; | 112 | | -const kDataEmitted = 1 << 18; | 113 | | -const kErrored = 1 << 19; | | 106 | +const kEnded = 1 << 9; | | 107 | +const kEndEmitted = 1 << 10; | | 108 | +const kReading = 1 << 11; | | 109 | +const kSync = 1 << 12; | | 110 | +const kNeedReadable = 1 << 13; | | 111 | +const kEmittedReadable = 1 << 14; | | 112 | +const kReadableListening = 1 << 15; | | 113 | +const kResumeScheduled = 1 << 16; | | 114 | +const kMultiAwaitDrain = 1 << 17; | | 115 | +const kReadingMore = 1 << 18; | | 116 | +const kDataEmitted = 1 << 19; | 114 | 117 | const kDefaultUTF8Encoding = 1 << 20; | 115 | 118 | const kDecoder = 1 << 21; | 116 | 119 | const kEncoding = 1 << 22; | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/streams/utils.js +22Lines changed: 22 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -22,6 +22,17 @@ const kOnConstructed = Symbol('kOnConstructed'); | 22 | 22 | const kIsClosedPromise = SymbolFor('nodejs.webstream.isClosedPromise'); | 23 | 23 | const kControllerErrorFunction = SymbolFor('nodejs.webstream.controllerErrorFunction'); | 24 | 24 |
| | 25 | +const kState = Symbol('kState'); | | 26 | +const kObjectMode = 1 << 0; | | 27 | +const kErrorEmitted = 1 << 1; | | 28 | +const kAutoDestroy = 1 << 2; | | 29 | +const kEmitClose = 1 << 3; | | 30 | +const kDestroyed = 1 << 4; | | 31 | +const kClosed = 1 << 5; | | 32 | +const kCloseEmitted = 1 << 6; | | 33 | +const kErrored = 1 << 7; | | 34 | +const kConstructed = 1 << 8; | | 35 | + | 25 | 36 | function isReadableNodeStream(obj, strict = false) { | 26 | 37 | return !!( | 27 | 38 | obj && | @@ -339,4 +350,15 @@ module.exports = { | 339 | 350 | isServerResponse, | 340 | 351 | willEmitClose, | 341 | 352 | isTransformStream, | | 353 | + kState, | | 354 | + // bitfields | | 355 | + kObjectMode, | | 356 | + kErrorEmitted, | | 357 | + kAutoDestroy, | | 358 | + kEmitClose, | | 359 | + kDestroyed, | | 360 | + kClosed, | | 361 | + kCloseEmitted, | | 362 | + kErrored, | | 363 | + kConstructed, | 342 | 364 | }; |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/streams/writable.js +26-23Lines changed: 26 additions & 23 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -44,7 +44,6 @@ const EE = require('events'); | 44 | 44 | const Stream = require('internal/streams/legacy').Stream; | 45 | 45 | const { Buffer } = require('buffer'); | 46 | 46 | const destroyImpl = require('internal/streams/destroy'); | 47 | | -const { kOnConstructed } = require('internal/streams/utils'); | 48 | 47 |
| 49 | 48 | const { | 50 | 49 | addAbortSignal, | @@ -65,6 +64,20 @@ const { | 65 | 64 | ERR_STREAM_WRITE_AFTER_END, | 66 | 65 | ERR_UNKNOWN_ENCODING, | 67 | 66 | } = require('internal/errors').codes; | | 67 | +const { | | 68 | + kState, | | 69 | + // bitfields | | 70 | + kObjectMode, | | 71 | + kErrorEmitted, | | 72 | + kAutoDestroy, | | 73 | + kEmitClose, | | 74 | + kDestroyed, | | 75 | + kClosed, | | 76 | + kCloseEmitted, | | 77 | + kErrored, | | 78 | + kConstructed, | | 79 | + kOnConstructed, | | 80 | +} = require('internal/streams/utils'); | 68 | 81 |
| 69 | 82 | const { errorOrDestroy } = destroyImpl; | 70 | 83 |
| @@ -79,18 +92,8 @@ const kDefaultEncodingValue = Symbol('kDefaultEncodingValue'); | 79 | 92 | const kWriteCbValue = Symbol('kWriteCbValue'); | 80 | 93 | const kAfterWriteTickInfoValue = Symbol('kAfterWriteTickInfoValue'); | 81 | 94 | const kBufferedValue = Symbol('kBufferedValue'); | 82 | | -const kState = Symbol('kState'); | 83 | | - | 84 | | -const kObjectMode = 1 << 0; | 85 | | -const kEnded = 1 << 1; | 86 | | -const kConstructed = 1 << 2; | 87 | | -const kSync = 1 << 3; | 88 | | -const kErrorEmitted = 1 << 4; | 89 | | -const kEmitClose = 1 << 5; | 90 | | -const kAutoDestroy = 1 << 6; | 91 | | -const kDestroyed = 1 << 7; | 92 | | -const kClosed = 1 << 8; | 93 | | -const kCloseEmitted = 1 << 9; | | 95 | + | | 96 | +const kSync = 1 << 9; | 94 | 97 | const kFinalCalled = 1 << 10; | 95 | 98 | const kNeedDrain = 1 << 11; | 96 | 99 | const kEnding = 1 << 12; | @@ -102,16 +105,16 @@ const kPrefinished = 1 << 17; | 102 | 105 | const kAllBuffers = 1 << 18; | 103 | 106 | const kAllNoop = 1 << 19; | 104 | 107 | const kOnFinished = 1 << 20; | 105 | | -const kErrored = 1 << 21; | 106 | | -const kHasWritable = 1 << 22; | 107 | | -const kWritable = 1 << 23; | 108 | | -const kCorked = 1 << 24; | 109 | | -const kDefaultUTF8Encoding = 1 << 25; | 110 | | -const kWriteCb = 1 << 26; | 111 | | -const kExpectWriteCb = 1 << 27; | 112 | | -const kAfterWriteTickInfo = 1 << 28; | 113 | | -const kAfterWritePending = 1 << 29; | 114 | | -const kBuffered = 1 << 30; | | 108 | +const kHasWritable = 1 << 21; | | 109 | +const kWritable = 1 << 22; | | 110 | +const kCorked = 1 << 23; | | 111 | +const kDefaultUTF8Encoding = 1 << 24; | | 112 | +const kWriteCb = 1 << 25; | | 113 | +const kExpectWriteCb = 1 << 26; | | 114 | +const kAfterWriteTickInfo = 1 << 27; | | 115 | +const kAfterWritePending = 1 << 28; | | 116 | +const kBuffered = 1 << 29; | | 117 | +const kEnded = 1 << 30; | 115 | 118 |
| 116 | 119 | // TODO(benjamingr) it is likely slower to do it this way than with free functions | 117 | 120 | function makeBitMapDescriptor(bit) { | |
|