Skip to content

Commit 98ae1b4

Browse files
ronagUlisesGascon
authored andcommitted
stream: use bit fields for construct/destroy
PR-URL: #50408 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Raz Luvaton <rluvaton@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent e7551d5 commit 98ae1b4

4 files changed

Lines changed: 118 additions & 66 deletions

File tree

‎lib/internal/streams/destroy.js‎

Lines changed: 45 additions & 21 deletions
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
constkDestroy=Symbol('kDestroy');
@@ -42,7 +51,10 @@ function destroy(err, cb) {
4251
// With duplex streams we use the writable side for state.
4352
consts=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(typeofcb==='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(typeofcb==='function'){
@@ -122,13 +134,16 @@ function emitCloseNT(self) {
122134
constw=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
constr=self._readableState;
138153
constw=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
constr=stream._readableState;
193211
constw=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
returnthis;
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-
elseif(err){
225+
}elseif(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
constw=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
consts=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‎

Lines changed: 25 additions & 22 deletions
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-
constkState=Symbol('kState');
7890
constFastBuffer=Buffer[SymbolSpecies];
7991

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

94-
constkObjectMode=1<<0;
95-
constkEnded=1<<1;
96-
constkEndEmitted=1<<2;
97-
constkReading=1<<3;
98-
constkConstructed=1<<4;
99-
constkSync=1<<5;
100-
constkNeedReadable=1<<6;
101-
constkEmittedReadable=1<<7;
102-
constkReadableListening=1<<8;
103-
constkResumeScheduled=1<<9;
104-
constkErrorEmitted=1<<10;
105-
constkEmitClose=1<<11;
106-
constkAutoDestroy=1<<12;
107-
constkDestroyed=1<<13;
108-
constkClosed=1<<14;
109-
constkCloseEmitted=1<<15;
110-
constkMultiAwaitDrain=1<<16;
111-
constkReadingMore=1<<17;
112-
constkDataEmitted=1<<18;
113-
constkErrored=1<<19;
106+
constkEnded=1<<9;
107+
constkEndEmitted=1<<10;
108+
constkReading=1<<11;
109+
constkSync=1<<12;
110+
constkNeedReadable=1<<13;
111+
constkEmittedReadable=1<<14;
112+
constkReadableListening=1<<15;
113+
constkResumeScheduled=1<<16;
114+
constkMultiAwaitDrain=1<<17;
115+
constkReadingMore=1<<18;
116+
constkDataEmitted=1<<19;
114117
constkDefaultUTF8Encoding=1<<20;
115118
constkDecoder=1<<21;
116119
constkEncoding=1<<22;

‎lib/internal/streams/utils.js‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ const kOnConstructed = Symbol('kOnConstructed');
2222
constkIsClosedPromise=SymbolFor('nodejs.webstream.isClosedPromise');
2323
constkControllerErrorFunction=SymbolFor('nodejs.webstream.controllerErrorFunction');
2424

25+
constkState=Symbol('kState');
26+
constkObjectMode=1<<0;
27+
constkErrorEmitted=1<<1;
28+
constkAutoDestroy=1<<2;
29+
constkEmitClose=1<<3;
30+
constkDestroyed=1<<4;
31+
constkClosed=1<<5;
32+
constkCloseEmitted=1<<6;
33+
constkErrored=1<<7;
34+
constkConstructed=1<<8;
35+
2536
functionisReadableNodeStream(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‎

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ const EE = require('events');
4444
constStream=require('internal/streams/legacy').Stream;
4545
const{ Buffer }=require('buffer');
4646
constdestroyImpl=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
constkWriteCbValue=Symbol('kWriteCbValue');
8093
constkAfterWriteTickInfoValue=Symbol('kAfterWriteTickInfoValue');
8194
constkBufferedValue=Symbol('kBufferedValue');
82-
constkState=Symbol('kState');
83-
84-
constkObjectMode=1<<0;
85-
constkEnded=1<<1;
86-
constkConstructed=1<<2;
87-
constkSync=1<<3;
88-
constkErrorEmitted=1<<4;
89-
constkEmitClose=1<<5;
90-
constkAutoDestroy=1<<6;
91-
constkDestroyed=1<<7;
92-
constkClosed=1<<8;
93-
constkCloseEmitted=1<<9;
95+
96+
constkSync=1<<9;
9497
constkFinalCalled=1<<10;
9598
constkNeedDrain=1<<11;
9699
constkEnding=1<<12;
@@ -102,16 +105,16 @@ const kPrefinished = 1 << 17;
102105
constkAllBuffers=1<<18;
103106
constkAllNoop=1<<19;
104107
constkOnFinished=1<<20;
105-
constkErrored=1<<21;
106-
constkHasWritable=1<<22;
107-
constkWritable=1<<23;
108-
constkCorked=1<<24;
109-
constkDefaultUTF8Encoding=1<<25;
110-
constkWriteCb=1<<26;
111-
constkExpectWriteCb=1<<27;
112-
constkAfterWriteTickInfo=1<<28;
113-
constkAfterWritePending=1<<29;
114-
constkBuffered=1<<30;
108+
constkHasWritable=1<<21;
109+
constkWritable=1<<22;
110+
constkCorked=1<<23;
111+
constkDefaultUTF8Encoding=1<<24;
112+
constkWriteCb=1<<25;
113+
constkExpectWriteCb=1<<26;
114+
constkAfterWriteTickInfo=1<<27;
115+
constkAfterWritePending=1<<28;
116+
constkBuffered=1<<29;
117+
constkEnded=1<<30;
115118

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

0 commit comments

Comments
 (0)