Skip to content

Commit 4d32b91

Browse files
committed
perf: fast-path JSON.stringify for CachedSource cache keys
CachedSource.map(), sourceAndMap() and streamChunks() key their map-entry cache with `JSON.stringify(options)`. That call is 60-100 ns on the common `{}` / `{columns: false}` shapes and dominates the entire method body once the cache is warm. Both MapOptions and the streamChunks Options type only contain boolean fields, so we can short-circuit the stringify for the three shapes that account for essentially all real traffic (undefined, empty object, columns-only) using interned string constants. Any other shape still falls through to JSON.stringify, so keys stay byte-identical to the on-disk BufferedMaps produced by previous CachedSource versions. Measured on the benchmark fixtures with JIT enabled (best of 5, ns/op): before after warmed.map({}) 79.1 4.3 (18x) warmed.map({columns:false})139.8 9.6 (14x) warmed.sourceAndMap({}) 89.6 9.8 (9x) warmed.map() / undefined 10.6 6.7 (1.6x) warmed.sourceAndMap() 12.4 7.7 (1.6x) Full --no-opt benchmark run shows +53% on `cached-source: map() (cached)`, +37.6% on `cached-source: sourceAndMap() (cached)`, +34.5% on `realistic-source-map-pipeline: warm sourceAndMap()`, and +17-21% on `replace-source: map()` / `sourceAndMap()`. 89813 tests still pass. https://claude.ai/code/session_01LZbaaPrnDTu6y7s4nK4cJz
1 parent c5795b8 commit 4d32b91

1 file changed

Lines changed: 31 additions & 3 deletions

File tree

lib/CachedSource.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ const bufferedMapToMap = (bufferedMap) => {
7878
/** @typedef {{ map?: null | RawSourceMap, bufferedMap?: null | BufferedMap }} BufferEntry */
7979
/** @typedef {Map<string, BufferEntry>} BufferedMaps */
8080

81+
const CACHE_KEY_EMPTY = "{}";
82+
const CACHE_KEY_COLUMNS_FALSE = '{"columns":false}';
83+
const CACHE_KEY_COLUMNS_TRUE = '{"columns":true}';
84+
85+
/**
86+
* Fast-path replacement for `JSON.stringify(options)` when used as a cache
87+
* key. MapOptions / streamChunks Options are both small boolean-only shapes
88+
* and the overwhelmingly common shapes (`undefined`, `{}`, `{columns}`) can
89+
* be keyed without calling `JSON.stringify`, which dominates short-circuit
90+
* cache lookups. Falls back to `JSON.stringify` for any other shape so keys
91+
* remain compatible with previously cached `BufferedMaps` entries.
92+
* @param {undefined | MapOptions | Options} options options
93+
* @returns {string} cache key
94+
*/
95+
const getCacheKey = (options) => {
96+
if (!options) return CACHE_KEY_EMPTY;
97+
const columns = options.columns;
98+
if (
99+
/** @type {Options} */ (options).source === undefined &&
100+
/** @type {Options} */ (options).finalSource === undefined &&
101+
/** @type {MapOptions} */ (options).module === undefined
102+
) {
103+
if (columns === undefined) return CACHE_KEY_EMPTY;
104+
return columns ? CACHE_KEY_COLUMNS_TRUE : CACHE_KEY_COLUMNS_FALSE;
105+
}
106+
return JSON.stringify(options);
107+
};
108+
81109
/**
82110
* @typedef {object} CachedData
83111
* @property {boolean=} source source
@@ -294,7 +322,7 @@ class CachedSource extends Source {
294322
* @returns {SourceAndMap} source and map
295323
*/
296324
sourceAndMap(options) {
297-
const key = options ? JSON.stringify(options) : "{}";
325+
const key = getCacheKey(options);
298326
const cacheEntry = this._cachedMaps.get(key);
299327
// Look for a cached map
300328
if (cacheEntry !== undefined) {
@@ -332,7 +360,7 @@ class CachedSource extends Source {
332360
* @returns {GeneratedSourceInfo} generated source info
333361
*/
334362
streamChunks(options, onChunk, onSource, onName) {
335-
const key = options ? JSON.stringify(options) : "{}";
363+
const key = getCacheKey(options);
336364
if (
337365
this._cachedMaps.has(key) &&
338366
(this._cachedBuffer !== undefined || this._cachedSource !== undefined)
@@ -379,7 +407,7 @@ class CachedSource extends Source {
379407
* @returns {RawSourceMap | null} map
380408
*/
381409
map(options) {
382-
const key = options ? JSON.stringify(options) : "{}";
410+
const key = getCacheKey(options);
383411
const cacheEntry = this._cachedMaps.get(key);
384412
if (cacheEntry !== undefined) {
385413
return this._getMapFromCacheEntry(cacheEntry);

0 commit comments

Comments
 (0)