From 0d4e587a5fe782f8baddecbaf7138f39d96ef446 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Mon, 23 Feb 2026 18:49:54 +0100 Subject: [PATCH] Reduce allocations when using `Map.prototype.getOrInsert()` with `Array`s Change all these cases to use `Map.prototype.getOrInsertComputed()` instead, in combination with a helper function for creating the `Array`s (similar to the previous patch). --- src/core/core_utils.js | 5 ++++- src/core/document.js | 3 ++- src/core/struct_tree.js | 3 ++- src/core/xfa/builder.js | 6 ++++-- src/display/annotation_layer.js | 5 ++++- src/pdf.js | 3 +++ src/shared/util.js | 2 ++ test/unit/pdf_spec.js | 2 ++ web/pdf_viewer.js | 3 ++- web/pdfjs.js | 2 ++ 10 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/core/core_utils.js b/src/core/core_utils.js index 85aedf03b..b1490c581 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -18,6 +18,7 @@ import { assert, BaseException, hexNumbers, + makeArr, objectSize, stringToPDFString, Util, @@ -669,7 +670,9 @@ function getNewAnnotationsMap(annotationStorage) { if (!key.startsWith(AnnotationEditorPrefix)) { continue; } - newAnnotationsByPage.getOrInsert(value.pageIndex, []).push(value); + newAnnotationsByPage + .getOrInsertComputed(value.pageIndex, makeArr) + .push(value); } return newAnnotationsByPage.size > 0 ? newAnnotationsByPage : null; } diff --git a/src/core/document.js b/src/core/document.js index 8c1696d8b..573f56d2c 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -20,6 +20,7 @@ import { info, InvalidPDFException, isArrayEqual, + makeArr, objectSize, PageActionEventType, RenderingIntentFlag, @@ -1892,7 +1893,7 @@ class PDFDocument { orphanFields.put(fieldRef, parentRef); } - promises.getOrInsert(name, []).push( + promises.getOrInsertComputed(name, makeArr).push( AnnotationFactory.create( xref, fieldRef, diff --git a/src/core/struct_tree.js b/src/core/struct_tree.js index 437d35b9a..f6e6a8422 100644 --- a/src/core/struct_tree.js +++ b/src/core/struct_tree.js @@ -15,6 +15,7 @@ import { AnnotationPrefix, + makeArr, stringToPDFString, stringToUTF8String, warn, @@ -450,7 +451,7 @@ class StructTreeRoot { for (const element of elements) { if (element.structTreeParentId) { const id = parseInt(element.structTreeParentId.split("_mc")[1], 10); - idToElements.getOrInsert(id, []).push(element); + idToElements.getOrInsertComputed(id, makeArr).push(element); } } diff --git a/src/core/xfa/builder.js b/src/core/xfa/builder.js index 80d3719f4..55660fe58 100644 --- a/src/core/xfa/builder.js +++ b/src/core/xfa/builder.js @@ -24,10 +24,10 @@ import { $resolvePrototypes, $root, } from "./symbol_utils.js"; +import { makeArr, warn } from "../../shared/util.js"; import { NamespaceSetUp } from "./setup.js"; import { Template } from "./template.js"; import { UnknownNamespace } from "./unknown.js"; -import { warn } from "../../shared/util.js"; import { XFAObject } from "./xfa_object.js"; class Root extends XFAObject { @@ -166,7 +166,9 @@ class Builder { _addNamespacePrefix(prefixes) { for (const { prefix, value } of prefixes) { const namespace = this._searchNamespace(value); - this._namespacePrefixes.getOrInsert(prefix, []).push(namespace); + this._namespacePrefixes + .getOrInsertComputed(prefix, makeArr) + .push(namespace); } } diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index dc8be6e8d..7a9924846 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -36,6 +36,7 @@ import { AnnotationType, FeatureTest, LINE_FACTOR, + makeArr, shadow, unreachable, Util, @@ -3877,7 +3878,9 @@ class AnnotationLayer { this.#elements.push(element); if (data.popupRef) { - popupToElements.getOrInsert(data.popupRef, []).push(element); + popupToElements + .getOrInsertComputed(data.popupRef, makeArr) + .push(element); } } diff --git a/src/pdf.js b/src/pdf.js index 8551c08ee..6f8309e68 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -33,6 +33,7 @@ import { getUuid, ImageKind, InvalidPDFException, + makeArr, makeMap, makeObj, MathClamp, @@ -125,6 +126,7 @@ globalThis.pdfjsLib = { isDataScheme, isPdfFile, isValidExplicitDest, + makeArr, makeMap, makeObj, MathClamp, @@ -186,6 +188,7 @@ export { isDataScheme, isPdfFile, isValidExplicitDest, + makeArr, makeMap, makeObj, MathClamp, diff --git a/src/shared/util.js b/src/shared/util.js index f0aa24d29..ace389d50 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -1236,6 +1236,7 @@ function _isValidExplicitDest(validRef, validName, dest) { // Helpers for simple `Map.prototype.getOrInsertComputed()` invocations, // to avoid duplicate function creation. +const makeArr = () => []; const makeMap = () => new Map(); const makeObj = () => Object.create(null); @@ -1336,6 +1337,7 @@ export { isNodeJS, LINE_DESCENT_FACTOR, LINE_FACTOR, + makeArr, makeMap, makeObj, MathClamp, diff --git a/test/unit/pdf_spec.js b/test/unit/pdf_spec.js index a0ddca083..cde18561a 100644 --- a/test/unit/pdf_spec.js +++ b/test/unit/pdf_spec.js @@ -24,6 +24,7 @@ import { getUuid, ImageKind, InvalidPDFException, + makeArr, makeMap, makeObj, MathClamp, @@ -109,6 +110,7 @@ const expectedAPI = Object.freeze({ isDataScheme, isPdfFile, isValidExplicitDest, + makeArr, makeMap, makeObj, MathClamp, diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index a3b28220a..3980829b1 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -33,6 +33,7 @@ import { AnnotationEditorType, AnnotationEditorUIManager, AnnotationMode, + makeArr, MathClamp, PermissionFlag, PixelsPerInch, @@ -2281,7 +2282,7 @@ class PDFViewer { if (percent === 0 || widthPercent < 100) { continue; } - pageLayout.getOrInsert(y, []).push(id); + pageLayout.getOrInsertComputed(y, makeArr).push(id); } // Find the row of the current page. for (const yArray of pageLayout.values()) { diff --git a/web/pdfjs.js b/web/pdfjs.js index a7a54f5d5..1482c33df 100644 --- a/web/pdfjs.js +++ b/web/pdfjs.js @@ -44,6 +44,7 @@ const { isDataScheme, isPdfFile, isValidExplicitDest, + makeArr, makeMap, makeObj, MathClamp, @@ -105,6 +106,7 @@ export { isDataScheme, isPdfFile, isValidExplicitDest, + makeArr, makeMap, makeObj, MathClamp,