1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 00:29:09 -05:00

perf: optimize RegExp usage in JS (#19364)

Towards https://github.com/denoland/deno/issues/19330

Shows about 1% improvement in the HTTP benchmark.
This commit is contained in:
Bartek Iwańczuk 2023-06-05 10:52:40 +02:00
parent 2d60600724
commit ca625dcd1d
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
6 changed files with 19 additions and 16 deletions

View file

@ -30,7 +30,7 @@ const {
ArrayPrototypeFilter, ArrayPrototypeFilter,
ObjectEntries, ObjectEntries,
ObjectHasOwn, ObjectHasOwn,
RegExpPrototypeTest, RegExpPrototypeExec,
SafeArrayIterator, SafeArrayIterator,
SafeRegExp, SafeRegExp,
Symbol, Symbol,
@ -102,10 +102,10 @@ function appendHeader(headers, name, value) {
value = normalizeHeaderValue(value); value = normalizeHeaderValue(value);
// 2. // 2.
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
throw new TypeError("Header name is not valid."); throw new TypeError("Header name is not valid.");
} }
if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) { if (RegExpPrototypeExec(ILLEGAL_VALUE_CHARS, value) !== null) {
throw new TypeError("Header value is not valid."); throw new TypeError("Header value is not valid.");
} }
@ -282,7 +282,7 @@ class Headers {
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
name = webidl.converters["ByteString"](name, prefix, "Argument 1"); name = webidl.converters["ByteString"](name, prefix, "Argument 1");
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
throw new TypeError("Header name is not valid."); throw new TypeError("Header name is not valid.");
} }
if (this[_guard] == "immutable") { if (this[_guard] == "immutable") {
@ -307,7 +307,7 @@ class Headers {
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
name = webidl.converters["ByteString"](name, prefix, "Argument 1"); name = webidl.converters["ByteString"](name, prefix, "Argument 1");
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
throw new TypeError("Header name is not valid."); throw new TypeError("Header name is not valid.");
} }
@ -323,7 +323,7 @@ class Headers {
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
name = webidl.converters["ByteString"](name, prefix, "Argument 1"); name = webidl.converters["ByteString"](name, prefix, "Argument 1");
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
throw new TypeError("Header name is not valid."); throw new TypeError("Header name is not valid.");
} }
@ -351,10 +351,10 @@ class Headers {
value = normalizeHeaderValue(value); value = normalizeHeaderValue(value);
// 2. // 2.
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
throw new TypeError("Header name is not valid."); throw new TypeError("Header name is not valid.");
} }
if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) { if (RegExpPrototypeExec(ILLEGAL_VALUE_CHARS, value) !== null) {
throw new TypeError("Header value is not valid."); throw new TypeError("Header value is not valid.");
} }

View file

@ -36,7 +36,7 @@ const {
ArrayPrototypeSplice, ArrayPrototypeSplice,
ObjectKeys, ObjectKeys,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
RegExpPrototypeTest, RegExpPrototypeExec,
StringPrototypeStartsWith, StringPrototypeStartsWith,
Symbol, Symbol,
SymbolFor, SymbolFor,
@ -227,7 +227,7 @@ function validateAndNormalizeMethod(m) {
} }
// Regular path // Regular path
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, m)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, m) === null) {
throw new TypeError("Method is not valid."); throw new TypeError("Method is not valid.");
} }
const upperCase = byteUpperCase(m); const upperCase = byteUpperCase(m);

View file

@ -37,7 +37,7 @@ const {
ObjectDefineProperties, ObjectDefineProperties,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
RangeError, RangeError,
RegExpPrototypeTest, RegExpPrototypeExec,
SafeArrayIterator, SafeArrayIterator,
SafeRegExp, SafeRegExp,
Symbol, Symbol,
@ -179,7 +179,7 @@ function initializeAResponse(response, init, bodyWithType) {
// 2. // 2.
if ( if (
init.statusText && init.statusText &&
!RegExpPrototypeTest(REASON_PHRASE_RE, init.statusText) RegExpPrototypeExec(REASON_PHRASE_RE, init.statusText) === null
) { ) {
throw new TypeError("Status text is not valid."); throw new TypeError("Status text is not valid.");
} }

View file

@ -13,6 +13,7 @@ const {
MapPrototypeHas, MapPrototypeHas,
MapPrototypeSet, MapPrototypeSet,
RegExpPrototypeTest, RegExpPrototypeTest,
RegExpPrototypeExec,
SafeMap, SafeMap,
SafeMapIterator, SafeMapIterator,
StringPrototypeReplaceAll, StringPrototypeReplaceAll,
@ -197,7 +198,7 @@ function serializeMimeType(mimeType) {
for (const param of new SafeMapIterator(mimeType.parameters)) { for (const param of new SafeMapIterator(mimeType.parameters)) {
serialization += `;${param[0]}=`; serialization += `;${param[0]}=`;
let value = param[1]; let value = param[1];
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, value)) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, value) === null) {
value = StringPrototypeReplaceAll(value, "\\", "\\\\"); value = StringPrototypeReplaceAll(value, "\\", "\\\\");
value = StringPrototypeReplaceAll(value, '"', '\\"'); value = StringPrototypeReplaceAll(value, '"', '\\"');
value = `"${value}"`; value = `"${value}"`;

View file

@ -59,6 +59,7 @@ const {
ReflectHas, ReflectHas,
ReflectOwnKeys, ReflectOwnKeys,
RegExpPrototypeTest, RegExpPrototypeTest,
RegExpPrototypeExec,
SafeRegExp, SafeRegExp,
SafeSet, SafeSet,
SetPrototypeEntries, SetPrototypeEntries,
@ -406,7 +407,7 @@ converters.DOMString = function (V, prefix, context, opts = {}) {
const IS_BYTE_STRING = new SafeRegExp(/^[\x00-\xFF]*$/); const IS_BYTE_STRING = new SafeRegExp(/^[\x00-\xFF]*$/);
converters.ByteString = (V, prefix, context, opts) => { converters.ByteString = (V, prefix, context, opts) => {
const x = converters.DOMString(V, prefix, context, opts); const x = converters.DOMString(V, prefix, context, opts);
if (!RegExpPrototypeTest(IS_BYTE_STRING, x)) { if (RegExpPrototypeExec(IS_BYTE_STRING, x) === null) {
throw makeException( throw makeException(
TypeError, TypeError,
"is not a valid ByteString", "is not a valid ByteString",

View file

@ -33,7 +33,7 @@ const {
ObjectDefineProperties, ObjectDefineProperties,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
PromisePrototypeThen, PromisePrototypeThen,
RegExpPrototypeTest, RegExpPrototypeExec,
SafeSet, SafeSet,
SetPrototypeGetSize, SetPrototypeGetSize,
// TODO(lucacasonato): add SharedArrayBuffer to primordials // TODO(lucacasonato): add SharedArrayBuffer to primordials
@ -256,7 +256,8 @@ class WebSocket extends EventTarget {
if ( if (
ArrayPrototypeSome( ArrayPrototypeSome(
protocols, protocols,
(protocol) => !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol), (protocol) =>
RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, protocol) === null,
) )
) { ) {
throw new DOMException( throw new DOMException(