Skip to content

Commit 763eaa1

Browse files
committed
stream: use bit fields for construct/destroy
PR-URL: #50408
1 parent 4ddb263 commit 763eaa1

File tree

4 files changed

+118
-66
lines changed

4 files changed

+118
-66
lines changed

lib/internal/streams/destroy.js

+45-21
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ const {
1515
isDestroyed,
1616
isFinished,
1717
isServerRequest,
18+
kState,
19+
kErrorEmitted,
20+
kEmitClose,
21+
kClosed,
22+
kCloseEmitted,
23+
kConstructed,
24+
kDestroyed,
25+
kAutoDestroy,
26+
kErrored,
1827
} = require('internal/streams/utils');
1928

2029
const kDestroy = Symbol('kDestroy');
@@ -42,7 +51,10 @@ function destroy(err, cb) {
4251
// With duplex streams we use the writable side for state.
4352
const s = w || r;
4453

45-
if (w?.destroyed || r?.destroyed) {
54+
if (
55+
(w && (w[kState] & kDestroyed) !== 0) ||
56+
(r && (r[kState] & kDestroyed) !== 0)
57+
) {
4658
if (typeof cb === 'function') {
4759
cb();
4860
}
@@ -56,14 +68,14 @@ function destroy(err, cb) {
5668
checkError(err, w, r);
5769

5870
if (w) {
59-
w.destroyed = true;
71+
w[kState] |= kDestroyed;
6072
}
6173
if (r) {
62-
r.destroyed = true;
74+
r[kState] |= kDestroyed;
6375
}
6476

6577
// If still constructing then defer calling _destroy.
66-
if (!s.constructed) {
78+
if ((s[kState] & kConstructed) === 0) {
6779
this.once(kDestroy, function(er) {
6880
_destroy(this, aggregateTwoErrors(er, err), cb);
6981
});
@@ -89,10 +101,10 @@ function _destroy(self, err, cb) {
89101
checkError(err, w, r);
90102

91103
if (w) {
92-
w.closed = true;
104+
w[kState] |= kClosed;
93105
}
94106
if (r) {
95-
r.closed = true;
107+
r[kState] |= kClosed;
96108
}
97109

98110
if (typeof cb === 'function') {
@@ -122,13 +134,16 @@ function emitCloseNT(self) {
122134
const w = self._writableState;
123135

124136
if (w) {
125-
w.closeEmitted = true;
137+
w[kState] |= kCloseEmitted;
126138
}
127139
if (r) {
128-
r.closeEmitted = true;
140+
r[kState] |= kCloseEmitted;
129141
}
130142

131-
if (w?.emitClose || r?.emitClose) {
143+
if (
144+
(w && (w[kState] & kEmitClose) !== 0) ||
145+
(r && (r[kState] & kEmitClose) !== 0)
146+
) {
132147
self.emit('close');
133148
}
134149
}
@@ -137,15 +152,18 @@ function emitErrorNT(self, err) {
137152
const r = self._readableState;
138153
const w = self._writableState;
139154

140-
if (w?.errorEmitted || r?.errorEmitted) {
155+
if (
156+
(w && (w[kState] & kErrorEmitted) !== 0) ||
157+
(r && (r[kState] & kErrorEmitted) !== 0)
158+
) {
141159
return;
142160
}
143161

144162
if (w) {
145-
w.errorEmitted = true;
163+
w[kState] |= kErrorEmitted;
146164
}
147165
if (r) {
148-
r.errorEmitted = true;
166+
r[kState] |= kErrorEmitted;
149167
}
150168

151169
self.emit('error', err);
@@ -192,20 +210,26 @@ function errorOrDestroy(stream, err, sync) {
192210
const r = stream._readableState;
193211
const w = stream._writableState;
194212

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+
) {
196217
return this;
197218
}
198219

199-
if (r?.autoDestroy || w?.autoDestroy)
220+
if (
221+
(r && (r[kState] & kAutoDestroy) !== 0) ||
222+
(w && (w[kState] & kAutoDestroy) !== 0)
223+
) {
200224
stream.destroy(err);
201-
else if (err) {
225+
} else if (err) {
202226
// Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364
203227
err.stack; // eslint-disable-line no-unused-expressions
204228

205-
if (w && !w.errored) {
229+
if (w && (w[kState] & kErrored) === 0) {
206230
w.errored = err;
207231
}
208-
if (r && !r.errored) {
232+
if (r && (r[kState] & kErrored) === 0) {
209233
r.errored = err;
210234
}
211235
if (sync) {
@@ -225,10 +249,10 @@ function construct(stream, cb) {
225249
const w = stream._writableState;
226250

227251
if (r) {
228-
r.constructed = false;
252+
r[kState] &= ~kConstructed;
229253
}
230254
if (w) {
231-
w.constructed = false;
255+
w[kState] &= ~kConstructed;
232256
}
233257

234258
stream.once(kConstruct, cb);
@@ -256,10 +280,10 @@ function constructNT(stream) {
256280
const s = w || r;
257281

258282
if (r) {
259-
r.constructed = true;
283+
r[kState] |= kConstructed;
260284
}
261285
if (w) {
262-
w.constructed = true;
286+
w[kState] |= kConstructed;
263287
}
264288

265289
if (s.destroyed) {

lib/internal/streams/readable.js

+25-22
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ const {
5858
getHighWaterMark,
5959
getDefaultHighWaterMark,
6060
} = 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');
6175

6276
const {
6377
aggregateTwoErrors,
@@ -72,9 +86,7 @@ const {
7286
AbortError,
7387
} = require('internal/errors');
7488
const { validateObject } = require('internal/validators');
75-
const { kOnConstructed } = require('internal/streams/utils');
7689

77-
const kState = Symbol('kState');
7890
const FastBuffer = Buffer[SymbolSpecies];
7991

8092
const { StringDecoder } = require('string_decoder');
@@ -91,26 +103,17 @@ const kDefaultEncodingValue = Symbol('kDefaultEncodingValue');
91103
const kDecoderValue = Symbol('kDecoderValue');
92104
const kEncodingValue = Symbol('kEncodingValue');
93105

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;
114117
const kDefaultUTF8Encoding = 1 << 20;
115118
const kDecoder = 1 << 21;
116119
const kEncoding = 1 << 22;

lib/internal/streams/utils.js

+22
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ const kOnConstructed = Symbol('kOnConstructed');
2222
const kIsClosedPromise = SymbolFor('nodejs.webstream.isClosedPromise');
2323
const kControllerErrorFunction = SymbolFor('nodejs.webstream.controllerErrorFunction');
2424

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+
2536
function isReadableNodeStream(obj, strict = false) {
2637
return !!(
2738
obj &&
@@ -339,4 +350,15 @@ module.exports = {
339350
isServerResponse,
340351
willEmitClose,
341352
isTransformStream,
353+
kState,
354+
// bitfields
355+
kObjectMode,
356+
kErrorEmitted,
357+
kAutoDestroy,
358+
kEmitClose,
359+
kDestroyed,
360+
kClosed,
361+
kCloseEmitted,
362+
kErrored,
363+
kConstructed
342364
};

lib/internal/streams/writable.js

+26-23
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ const EE = require('events');
4444
const Stream = require('internal/streams/legacy').Stream;
4545
const { Buffer } = require('buffer');
4646
const destroyImpl = require('internal/streams/destroy');
47-
const { kOnConstructed } = require('internal/streams/utils');
4847

4948
const {
5049
addAbortSignal,
@@ -65,6 +64,20 @@ const {
6564
ERR_STREAM_WRITE_AFTER_END,
6665
ERR_UNKNOWN_ENCODING,
6766
} = 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');
6881

6982
const { errorOrDestroy } = destroyImpl;
7083

@@ -79,18 +92,8 @@ const kDefaultEncodingValue = Symbol('kDefaultEncodingValue');
7992
const kWriteCbValue = Symbol('kWriteCbValue');
8093
const kAfterWriteTickInfoValue = Symbol('kAfterWriteTickInfoValue');
8194
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;
9497
const kFinalCalled = 1 << 10;
9598
const kNeedDrain = 1 << 11;
9699
const kEnding = 1 << 12;
@@ -102,16 +105,16 @@ const kPrefinished = 1 << 17;
102105
const kAllBuffers = 1 << 18;
103106
const kAllNoop = 1 << 19;
104107
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;
115118

116119
// TODO(benjamingr) it is likely slower to do it this way than with free functions
117120
function makeBitMapDescriptor(bit) {

0 commit comments

Comments
 (0)