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).
78 lines
3.4 KiB
Diff
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
|
|
|