Files
emacs-doom/patches/0009-perf-use-BUF_CHARS_MODIFF-for-AX-text-cache-validity.patch
Daneel cd16d45584 patches: fix O(buffer) cache invalidation caused by font-lock
BUF_CHARS_MODIFF fix — the core performance regression:
ensureTextCache checked BUF_MODIFF which font-lock bumps on every
redisplay. Each cursor movement in a large file triggered full buffer
rebuild. Now uses BUF_CHARS_MODIFF (changes only on char insert/delete).
2026-03-01 04:56:37 +01:00

78 lines
3.4 KiB
Diff

From 4b739781a019fd1ad5b6ac1c9c12dc62e2c82ec3 Mon Sep 17 00:00:00 2001
From: Daneel <daneel@sukany.cz>
Date: Sun, 1 Mar 2026 04:56:16 +0100
Subject: [PATCH 10/10] perf: use BUF_CHARS_MODIFF for AX text cache validity
in ensureTextCache
The cache validity check in -[EmacsAccessibilityBuffer ensureTextCache]
used BUF_MODIFF, which is bumped by every text-property change ---
including face applications by font-lock on each redisplay cycle.
Since the AX text value contains only characters (no face or property
data), property-only changes do not affect it. Rebuilding the full
buffer text on each font-lock pass is O(buffer-size) per redisplay,
causing progressive slowdown proportional to how far the cursor is
from the beginning of the file.
Switch to BUF_CHARS_MODIFF, which is bumped only when characters are
actually inserted or deleted. This matches the semantic of 'did the
text change' and is the approach used by WebKit and NSTextView.
BUF_OVERLAY_MODIFF is intentionally not tracked here (unchanged):
overlay content is handled by separate announcements in
postAccessibilityNotificationsForFrame, and including it in this
check would prevent those announcements from firing.
---
src/nsterm.m | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/nsterm.m b/src/nsterm.m
index 12c451b..e3f9466 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -8148,16 +8148,25 @@ - (void)ensureTextCache
if (!b)
return;
- ptrdiff_t modiff = BUF_MODIFF (b);
- ptrdiff_t pt = BUF_PT (b);
- NSUInteger textLen = cachedText ? [cachedText length] : 0;
- /* Cache validity: track BUF_MODIFF and buffer narrowing.
+ /* Use BUF_CHARS_MODIFF, not BUF_MODIFF, for cache validity.
+ BUF_MODIFF is bumped by every text-property change, including
+ font-lock face applications on every redisplay. AX text contains
+ only characters, not face data, so property-only changes do not
+ affect the cached value. Rebuilding the full buffer text on
+ each font-lock pass is O(buffer-size) per redisplay --- this
+ causes progressive slowdown when scrolling through large files.
+ BUF_CHARS_MODIFF is bumped only on actual character insertions
+ and deletions, matching the semantic of "did the text change".
+ This is the pattern used by WebKit and NSTextView.
Do NOT track BUF_OVERLAY_MODIFF here --- overlay text is not
included in the cached AX text (it is handled separately via
- explicit announcements). Including overlay_modiff would
- silently update cachedOverlayModiff and prevent the
- notification dispatch from detecting overlay changes. */
- if (cachedText && cachedTextModiff == modiff
+ explicit announcements in postAccessibilityNotificationsForFrame).
+ Including overlay_modiff would silently update cachedOverlayModiff
+ and prevent the notification dispatch from detecting changes. */
+ ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b);
+ ptrdiff_t pt = BUF_PT (b);
+ NSUInteger textLen = cachedText ? [cachedText length] : 0;
+ if (cachedText && cachedTextModiff == chars_modiff
&& cachedTextStart == BUF_BEGV (b)
&& pt >= cachedTextStart
&& (textLen == 0
@@ -8173,7 +8182,7 @@ included in the cached AX text (it is handled separately via
{
[cachedText release];
cachedText = [text retain];
- cachedTextModiff = modiff;
+ cachedTextModiff = chars_modiff;
cachedTextStart = start;
if (visibleRuns)
--
2.43.0