From 4b3cc3ce1821a1d828453b5545d46c5ec872972f Mon Sep 17 00:00:00 2001 From: Mudit Date: Sat, 2 Dec 2023 14:53:05 +0100 Subject: [PATCH] loader: speed up line length calc used by moduleProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using a loader, for say TypeScript, the esm loader invokes the `lineLengths` function via `maybeCacheSourceMap` when sourcemaps are enabled. Therefore, `lineLengths` ends up getting called quite often when running large servers written in TypeScript for example. Making `lineLengths` faster should therefore speed up server startup times for anyone using a loader with node with sourcemaps enabled. The change itself is fairly simple and is all about removing creation of unnecessary memory and iterating the whole source content only once with the hope of making the function cache friendly. PR-URL: https://github.com/nodejs/node/pull/50969 Reviewed-By: Yagiz Nizipli Reviewed-By: Geoffrey Booth Reviewed-By: Antoine du Hamel Reviewed-By: Vinícius Lourenço Claro Cardoso Reviewed-By: Jacob Smith --- lib/internal/source_map/source_map_cache.js | 28 +++++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 2813da21dfdc63..963b34ebcd241e 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -1,12 +1,12 @@ 'use strict'; const { - ArrayPrototypeMap, + ArrayPrototypePush, JSONParse, ObjectKeys, RegExpPrototypeExec, - RegExpPrototypeSymbolSplit, SafeMap, + StringPrototypeCodePointAt, StringPrototypeSplit, } = primordials; @@ -205,14 +205,26 @@ function dataFromUrl(sourceURL, sourceMappingURL) { // from. This allows translation from byte offset V8 coverage reports, // to line/column offset Source Map V3. function lineLengths(content) { - // We purposefully keep \r as part of the line-length calculation, in - // cases where there is a \r\n separator, so that this can be taken into - // account in coverage calculations. - return ArrayPrototypeMap(RegExpPrototypeSymbolSplit(/\n|\u2028|\u2029/, content), (line) => { - return line.length; - }); + const contentLength = content.length; + const output = []; + let lineLength = 0; + for (let i = 0; i < contentLength; i++, lineLength++) { + const codePoint = StringPrototypeCodePointAt(content, i); + + // We purposefully keep \r as part of the line-length calculation, in + // cases where there is a \r\n separator, so that this can be taken into + // account in coverage calculations. + // codepoints for \n (new line), \u2028 (line separator) and \u2029 (paragraph separator) + if (codePoint === 10 || codePoint === 0x2028 || codePoint === 0x2029) { + ArrayPrototypePush(output, lineLength); + lineLength = -1; // To not count the matched codePoint such as \n character + } + } + ArrayPrototypePush(output, lineLength); + return output; } + function sourceMapFromFile(mapURL) { try { const fs = require('fs');