-
Notifications
You must be signed in to change notification settings - Fork 30.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib: revert primordials in a hot path #38246
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f49ba49
Revert "stream: refactor to use more primordials"
mcollina f9763d8
stream: removed number primordials
mcollina 1e0d89c
http: remove primordials from hot path
mcollina 74d2497
lib: revert more primordials in the hot path
mcollina 590a545
fixup
mcollina dbbdd59
fixhup: less primordials in hot path
mcollina 4553526
fixup
mcollina e51967c
fixup: remove an always-on primordial in debuglog.
mcollina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -22,25 +22,9 @@ | |||||
'use strict'; | ||||||
|
||||||
const { | ||||||
Array, | ||||||
ArrayIsArray, | ||||||
ArrayPrototypeForEach, | ||||||
ArrayPrototypeJoin, | ||||||
ArrayPrototypePush, | ||||||
ArrayPrototypeUnshift, | ||||||
FunctionPrototype, | ||||||
FunctionPrototypeBind, | ||||||
FunctionPrototypeCall, | ||||||
MathFloor, | ||||||
NumberPrototypeToString, | ||||||
ObjectCreate, | ||||||
ObjectDefineProperty, | ||||||
ObjectKeys, | ||||||
ObjectValues, | ||||||
ObjectPrototypeHasOwnProperty, | ||||||
ObjectSetPrototypeOf, | ||||||
RegExpPrototypeTest, | ||||||
StringPrototypeToLowerCase, | ||||||
Symbol, | ||||||
} = primordials; | ||||||
|
||||||
|
@@ -88,7 +72,7 @@ const { CRLF } = common; | |||||
|
||||||
const kCorked = Symbol('corked'); | ||||||
|
||||||
const nop = FunctionPrototype; | ||||||
const nop = function () {}; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
const RE_CONN_CLOSE = /(?:^|\W)close(?:$|\W)/i; | ||||||
const RE_TE_CHUNKED = common.chunkExpression; | ||||||
|
@@ -97,11 +81,11 @@ const RE_TE_CHUNKED = common.chunkExpression; | |||||
// against the word "cookie." As of V8 6.6 this is faster than handrolling or | ||||||
// using a case-insensitive RegExp. | ||||||
function isCookieField(s) { | ||||||
return s.length === 6 && StringPrototypeToLowerCase(s) === 'cookie'; | ||||||
return s.length === 6 && s.toLowerCase() === 'cookie'; | ||||||
} | ||||||
|
||||||
function OutgoingMessage() { | ||||||
FunctionPrototypeCall(Stream, this); | ||||||
Stream.call(this); | ||||||
|
||||||
// Queue that holds all currently pending data, until the response will be | ||||||
// assigned to the socket (until it will its turn in the HTTP pipeline). | ||||||
|
@@ -190,13 +174,13 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headers', { | |||||
if (val == null) { | ||||||
this[kOutHeaders] = null; | ||||||
} else if (typeof val === 'object') { | ||||||
const headers = this[kOutHeaders] = ObjectCreate(null); | ||||||
const keys = ObjectKeys(val); | ||||||
const headers = this[kOutHeaders] = Object.create(null); | ||||||
const keys = Object.keys(val); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0; i < keys.length; ++i) { | ||||||
const name = keys[i]; | ||||||
headers[StringPrototypeToLowerCase(name)] = [name, val[name]]; | ||||||
headers[name.toLowerCase()] = [name, val[name]]; | ||||||
} | ||||||
} | ||||||
}, 'OutgoingMessage.prototype._headers is deprecated', 'DEP0066') | ||||||
|
@@ -215,8 +199,8 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headerNames', { | |||||
get: internalUtil.deprecate(function() { | ||||||
const headers = this[kOutHeaders]; | ||||||
if (headers !== null) { | ||||||
const out = ObjectCreate(null); | ||||||
const keys = ObjectKeys(headers); | ||||||
const out = Object.create(null); | ||||||
const keys = Object.keys(headers); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0; i < keys.length; ++i) { | ||||||
|
@@ -233,7 +217,7 @@ ObjectDefineProperty(OutgoingMessage.prototype, '_headerNames', { | |||||
const headers = this[kOutHeaders]; | ||||||
if (!headers) | ||||||
return; | ||||||
const keys = ObjectKeys(val); | ||||||
const keys = Object.keys(val); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0; i < keys.length; ++i) { | ||||||
|
@@ -255,7 +239,7 @@ OutgoingMessage.prototype._renderHeaders = function _renderHeaders() { | |||||
const headers = {}; | ||||||
|
||||||
if (headersMap !== null) { | ||||||
const keys = ObjectKeys(headersMap); | ||||||
const keys = Object.keys(headersMap); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0, l = keys.length; i < l; i++) { | ||||||
|
@@ -331,7 +315,7 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) { | |||||
data = this._header + data; | ||||||
} else { | ||||||
const header = this._header; | ||||||
ArrayPrototypeUnshift(this.outputData, { | ||||||
this.outputData.unshift({ | ||||||
data: header, | ||||||
encoding: 'latin1', | ||||||
callback: null | ||||||
|
@@ -368,7 +352,7 @@ function _writeRaw(data, encoding, callback) { | |||||
return conn.write(data, encoding, callback); | ||||||
} | ||||||
// Buffer, as long as we're not destroyed. | ||||||
ArrayPrototypePush(this.outputData, { data, encoding, callback }); | ||||||
this.outputData.push({ data, encoding, callback }); | ||||||
this.outputSize += data.length; | ||||||
this._onPendingData(data.length); | ||||||
return this.outputSize < HIGH_WATER_MARK; | ||||||
|
@@ -395,11 +379,12 @@ function _storeHeader(firstLine, headers) { | |||||
const entry = headers[key]; | ||||||
processHeader(this, state, entry[0], entry[1], false); | ||||||
} | ||||||
} else if (ArrayIsArray(headers)) { | ||||||
if (headers.length && ArrayIsArray(headers[0])) { | ||||||
ArrayPrototypeForEach(headers, (entry) => | ||||||
} else if (Array.isArray(headers)) { | ||||||
if (headers.length && Array.isArray(headers[0])) { | ||||||
for (let n = 0; n < headers.length; n++) { | ||||||
const entry = headers[n] | ||||||
processHeader(this, state, entry[0], entry[1], true) | ||||||
); | ||||||
} | ||||||
} else { | ||||||
if (headers.length % 2 !== 0) { | ||||||
throw new ERR_INVALID_ARG_VALUE('headers', headers); | ||||||
|
@@ -454,7 +439,7 @@ function _storeHeader(firstLine, headers) { | |||||
if (shouldSendKeepAlive) { | ||||||
header += 'Connection: keep-alive' + CRLF; | ||||||
if (this._keepAliveTimeout && this._defaultKeepAlive) { | ||||||
const timeoutSeconds = MathFloor(this._keepAliveTimeout / 1000); | ||||||
const timeoutSeconds = Math.floor(this._keepAliveTimeout / 1000); | ||||||
header += `Keep-Alive: timeout=${timeoutSeconds}${CRLF}`; | ||||||
} | ||||||
} else { | ||||||
|
@@ -504,15 +489,15 @@ function _storeHeader(firstLine, headers) { | |||||
function processHeader(self, state, key, value, validate) { | ||||||
if (validate) | ||||||
validateHeaderName(key); | ||||||
if (ArrayIsArray(value)) { | ||||||
if (Array.isArray(value)) { | ||||||
if (value.length < 2 || !isCookieField(key)) { | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0; i < value.length; i++) | ||||||
storeHeader(self, state, key, value[i], validate); | ||||||
return; | ||||||
} | ||||||
value = ArrayPrototypeJoin(value, '; '); | ||||||
value = value.join('; '); | ||||||
} | ||||||
storeHeader(self, state, key, value, validate); | ||||||
} | ||||||
|
@@ -527,20 +512,20 @@ function storeHeader(self, state, key, value, validate) { | |||||
function matchHeader(self, state, field, value) { | ||||||
if (field.length < 4 || field.length > 17) | ||||||
return; | ||||||
field = StringPrototypeToLowerCase(field); | ||||||
field = field.toLowerCase(); | ||||||
switch (field) { | ||||||
case 'connection': | ||||||
state.connection = true; | ||||||
self._removedConnection = false; | ||||||
if (RegExpPrototypeTest(RE_CONN_CLOSE, value)) | ||||||
if (RE_CONN_CLOSE.test(value)) | ||||||
self._last = true; | ||||||
else | ||||||
self.shouldKeepAlive = true; | ||||||
break; | ||||||
case 'transfer-encoding': | ||||||
state.te = true; | ||||||
self._removedTE = false; | ||||||
if (RegExpPrototypeTest(RE_TE_CHUNKED, value)) | ||||||
if (RE_TE_CHUNKED.test(value)) | ||||||
self.chunkedEncoding = true; | ||||||
break; | ||||||
case 'content-length': | ||||||
|
@@ -583,9 +568,9 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) { | |||||
|
||||||
let headers = this[kOutHeaders]; | ||||||
if (headers === null) | ||||||
this[kOutHeaders] = headers = ObjectCreate(null); | ||||||
this[kOutHeaders] = headers = Object.create(null); | ||||||
|
||||||
headers[StringPrototypeToLowerCase(name)] = [name, value]; | ||||||
headers[name.toLowerCase()] = [name, value]; | ||||||
return this; | ||||||
}; | ||||||
|
||||||
|
@@ -597,14 +582,14 @@ OutgoingMessage.prototype.getHeader = function getHeader(name) { | |||||
if (headers === null) | ||||||
return; | ||||||
|
||||||
const entry = headers[StringPrototypeToLowerCase(name)]; | ||||||
const entry = headers[name.toLowerCase()]; | ||||||
return entry && entry[1]; | ||||||
}; | ||||||
|
||||||
|
||||||
// Returns an array of the names of the current outgoing headers. | ||||||
OutgoingMessage.prototype.getHeaderNames = function getHeaderNames() { | ||||||
return this[kOutHeaders] !== null ? ObjectKeys(this[kOutHeaders]) : []; | ||||||
return this[kOutHeaders] !== null ? Object.keys(this[kOutHeaders]) : []; | ||||||
}; | ||||||
|
||||||
|
||||||
|
@@ -613,7 +598,7 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { | |||||
const headersMap = this[kOutHeaders]; | ||||||
if (headersMap === null) return []; | ||||||
|
||||||
const values = ObjectValues(headersMap); | ||||||
const values = Object.values(headersMap); | ||||||
const headers = Array(values.length); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
|
@@ -628,9 +613,9 @@ OutgoingMessage.prototype.getRawHeaderNames = function getRawHeaderNames() { | |||||
// Returns a shallow copy of the current outgoing headers. | ||||||
OutgoingMessage.prototype.getHeaders = function getHeaders() { | ||||||
const headers = this[kOutHeaders]; | ||||||
const ret = ObjectCreate(null); | ||||||
const ret = Object.create(null); | ||||||
if (headers) { | ||||||
const keys = ObjectKeys(headers); | ||||||
const keys = Object.keys(headers); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0; i < keys.length; ++i) { | ||||||
|
@@ -646,7 +631,7 @@ OutgoingMessage.prototype.getHeaders = function getHeaders() { | |||||
OutgoingMessage.prototype.hasHeader = function hasHeader(name) { | ||||||
validateString(name, 'name'); | ||||||
return this[kOutHeaders] !== null && | ||||||
!!this[kOutHeaders][StringPrototypeToLowerCase(name)]; | ||||||
!!this[kOutHeaders][name.toLowerCase()]; | ||||||
}; | ||||||
|
||||||
|
||||||
|
@@ -657,7 +642,7 @@ OutgoingMessage.prototype.removeHeader = function removeHeader(name) { | |||||
throw new ERR_HTTP_HEADERS_SENT('remove'); | ||||||
} | ||||||
|
||||||
const key = StringPrototypeToLowerCase(name); | ||||||
const key = name.toLowerCase(); | ||||||
|
||||||
switch (key) { | ||||||
case 'connection': | ||||||
|
@@ -783,7 +768,7 @@ function write_(msg, chunk, encoding, callback, fromEnd) { | |||||
|
||||||
let ret; | ||||||
if (msg.chunkedEncoding && chunk.length !== 0) { | ||||||
msg._send(NumberPrototypeToString(len, 16), 'latin1', null); | ||||||
msg._send(len.toString(16), 'latin1', null); | ||||||
msg._send(crlf_buf, null, null); | ||||||
msg._send(chunk, encoding, null); | ||||||
ret = msg._send(crlf_buf, null, callback); | ||||||
|
@@ -803,8 +788,8 @@ function connectionCorkNT(conn) { | |||||
|
||||||
OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { | ||||||
this._trailer = ''; | ||||||
const keys = ObjectKeys(headers); | ||||||
const isArray = ArrayIsArray(headers); | ||||||
const keys = Object.keys(headers); | ||||||
const isArray = Array.isArray(headers); | ||||||
// Retain for(;;) loop for performance reasons | ||||||
// Refs: https://github.com/nodejs/node/pull/30958 | ||||||
for (let i = 0, l = keys.length; i < l; i++) { | ||||||
|
@@ -877,7 +862,7 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) { | |||||
if (typeof callback === 'function') | ||||||
this.once('finish', callback); | ||||||
|
||||||
const finish = FunctionPrototypeBind(onFinish, undefined, this); | ||||||
const finish = onFinish.bind(undefined, this); | ||||||
|
||||||
if (this._hasBody && this.chunkedEncoding) { | ||||||
this._send('0\r\n' + this._trailer + '\r\n', 'latin1', finish); | ||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the ArrayPrototype operations where clearly problematic in my analysis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised that all of them would be, but I guess if that's the case it's OK to remove them all and try to add them back later if V8 optimize this away.