1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-31 20:02:42 +00:00

Depessimize the handling of very large macros.

This commit is contained in:
Alan Mackenzie 2012-03-02 22:16:21 +00:00
parent 3e441275a8
commit 56d093a9c8
3 changed files with 203 additions and 56 deletions

View File

@ -1,3 +1,25 @@
2012-03-02 Alan Mackenzie <acm@muc.de>
Depessimize the handling of very large macros.
* progmodes/cc-engine.el (c-macro-cache, c-macro-cache-start-pos):
(c-macro-cache-syntactic): New variables to implement a one
element macro cache.
(c-invalidate-macro-cache): New function.
(c-beginning-of-macro, c-end-of-macro, c-syntactic-end-of-macro):
Adapt to use the new cache.
(c-state-safe-place): Use better the cache of safe positions.
(c-state-semi-nonlit-pos-cache)
(c-state-semi-nonlit-pos-cache-limit):
New variables for...
(c-state-semi-safe-place): New function. Here, in a macro is "safe".
(c-invalidate-state-cache-1): New stuff for c-state-semi-safe-place.
(c-in-literal, c-literal-limits, c-determine-limit-get-base): Use
c-state-semi-safe-place.
* progmodes/cc-langs.el (c-get-state-before-change-functions): Add
c-invalidate-macro-cache to the C, C++, Obj entries.
2012-03-02 Michael Albinus <michael.albinus@gmx.de>
* jka-compr.el (jka-compr-call-process): Apply

View File

@ -219,6 +219,38 @@
(point))))
c-macro-start))
;; One element macro cache to cope with continual movement within very large
;; CPP macros.
(defvar c-macro-cache nil)
(make-variable-buffer-local 'c-macro-cache)
;; Nil or cons of the bounds of the most recent CPP form probed by
;; `c-beginning-of-macro', `c-end-of-macro' or `c-syntactic-end-of-macro'.
;; The cdr will be nil if we know only the start of the CPP form.
(defvar c-macro-cache-start-pos nil)
(make-variable-buffer-local 'c-macro-cache-start-pos)
;; The starting position from where we determined `c-macro-cache'.
(defvar c-macro-cache-syntactic nil)
(make-variable-buffer-local 'c-macro-cache-syntactic)
;; non-nil iff `c-macro-cache' has both elements set AND the cdr is at a
;; syntactic end of macro, not merely an apparent one.
(defun c-invalidate-macro-cache (beg end)
;; Called from a before-change function. If the change region is before or
;; in the macro characterised by `c-macro-cache' etc., nullify it
;; appropriately. BEG and END are the standard before-change-functions
;; parameters. END isn't used.
(cond
((null c-macro-cache))
((< beg (car c-macro-cache))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil))
((and (cdr c-macro-cache)
(< beg (cdr c-macro-cache)))
(setcdr c-macro-cache nil)
(setq c-macro-cache-start-pos beg
c-macro-cache-syntactic nil))))
(defun c-beginning-of-macro (&optional lim)
"Go to the beginning of a preprocessor directive.
Leave point at the beginning of the directive and return t if in one,
@ -226,19 +258,36 @@ otherwise return nil and leave point unchanged.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
(when c-opt-cpp-prefix
(let ((here (point)))
(save-restriction
(if lim (narrow-to-region lim (point-max)))
(beginning-of-line)
(while (eq (char-before (1- (point))) ?\\)
(forward-line -1))
(back-to-indentation)
(if (and (<= (point) here)
(looking-at c-opt-cpp-start))
t
(goto-char here)
nil)))))
(let ((here (point)))
(when c-opt-cpp-prefix
(if (and (car c-macro-cache)
(>= (point) (car c-macro-cache))
(or (and (cdr c-macro-cache)
(<= (point) (cdr c-macro-cache)))
(<= (point) c-macro-cache-start-pos)))
(unless (< (car c-macro-cache) (or lim (point-min)))
(progn (goto-char (max (or lim (point-min)) (car c-macro-cache)))
(setq c-macro-cache-start-pos
(max c-macro-cache-start-pos here))
t))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil)
(save-restriction
(if lim (narrow-to-region lim (point-max)))
(beginning-of-line)
(while (eq (char-before (1- (point))) ?\\)
(forward-line -1))
(back-to-indentation)
(if (and (<= (point) here)
(looking-at c-opt-cpp-start))
(progn
(setq c-macro-cache (cons (point) nil)
c-macro-cache-start-pos here)
t)
(goto-char here)
nil))))))
(defun c-end-of-macro ()
"Go to the end of a preprocessor directive.
@ -248,12 +297,24 @@ done that the point is inside a cpp directive to begin with.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
(while (progn
(end-of-line)
(when (and (eq (char-before) ?\\)
(not (eobp)))
(forward-char)
t))))
(if (and (cdr c-macro-cache)
(<= (point) (cdr c-macro-cache))
(>= (point) (car c-macro-cache)))
(goto-char (cdr c-macro-cache))
(unless (and (car c-macro-cache)
(<= (point) c-macro-cache-start-pos)
(>= (point) (car c-macro-cache)))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil))
(while (progn
(end-of-line)
(when (and (eq (char-before) ?\\)
(not (eobp)))
(forward-char)
t)))
(when (car c-macro-cache)
(setcdr c-macro-cache (point)))))
(defun c-syntactic-end-of-macro ()
;; Go to the end of a CPP directive, or a "safe" pos just before.
@ -268,12 +329,15 @@ comment at the start of cc-engine.el for more info."
;; at the start of cc-engine.el for more info.
(let* ((here (point))
(there (progn (c-end-of-macro) (point)))
(s (parse-partial-sexp here there)))
(while (and (or (nth 3 s) ; in a string
(nth 4 s)) ; in a comment (maybe at end of line comment)
(> there here)) ; No infinite loops, please.
(setq there (1- (nth 8 s)))
(setq s (parse-partial-sexp here there)))
s)
(unless c-macro-cache-syntactic
(setq s (parse-partial-sexp here there))
(while (and (or (nth 3 s) ; in a string
(nth 4 s)) ; in a comment (maybe at end of line comment)
(> there here)) ; No infinite loops, please.
(setq there (1- (nth 8 s)))
(setq s (parse-partial-sexp here there)))
(setq c-macro-cache-syntactic (car c-macro-cache)))
(point)))
(defun c-forward-over-cpp-define-id ()
@ -2089,6 +2153,18 @@ comment at the start of cc-engine.el for more info."
;; reduced by buffer changes, and increased by invocations of
;; `c-state-literal-at'.
(defvar c-state-semi-nonlit-pos-cache nil)
(make-variable-buffer-local 'c-state-semi-nonlit-pos-cache)
;; A list of buffer positions which are known not to be in a literal. This is
;; ordered with higher positions at the front of the list. Only those which
;; are less than `c-state-semi-nonlit-pos-cache-limit' are valid.
(defvar c-state-semi-nonlit-pos-cache-limit 1)
(make-variable-buffer-local 'c-state-semi-nonlit-pos-cache-limit)
;; An upper limit on valid entries in `c-state-semi-nonlit-pos-cache'. This is
;; reduced by buffer changes, and increased by invocations of
;; `c-state-literal-at'. FIMXE!!!
(defsubst c-state-pp-to-literal (from to)
;; Do a parse-partial-sexp from FROM to TO, returning either
;; (STATE TYPE (BEG . END)) if TO is in a literal; or
@ -2129,48 +2205,93 @@ comment at the start of cc-engine.el for more info."
(widen)
(save-excursion
(let ((c c-state-nonlit-pos-cache)
pos npos lit macro-beg macro-end)
pos npos high-pos lit macro-beg macro-end)
;; Trim the cache to take account of buffer changes.
(while (and c (> (car c) c-state-nonlit-pos-cache-limit))
(setq c (cdr c)))
(setq c-state-nonlit-pos-cache c)
(while (and c (> (car c) here))
(setq high-pos (car c))
(setq c (cdr c)))
(setq pos (or (car c) (point-min)))
(while
;; Add an element to `c-state-nonlit-pos-cache' each iteration.
(and
(<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
(unless high-pos
(while
;; Add an element to `c-state-nonlit-pos-cache' each iteration.
(and
(<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
;; Test for being in a literal.
(progn
(setq lit (car (cddr (c-state-pp-to-literal pos npos))))
(or (null lit)
(prog1 (<= (cdr lit) here)
(setq npos (cdr lit)))))
;; Test for being in a literal. If so, go to after it.
(progn
(setq lit (car (cddr (c-state-pp-to-literal pos npos))))
(or (null lit)
(prog1 (<= (cdr lit) here)
(setq npos (cdr lit)))))
;; Test for being in a macro.
(progn
(goto-char npos)
(setq macro-beg
(and (c-beginning-of-macro) (/= (point) npos) (point)))
(when macro-beg
(c-syntactic-end-of-macro)
(or (eobp) (forward-char))
(setq macro-end (point)))
(or (null macro-beg)
(prog1 (<= macro-end here)
(setq npos macro-end)))))
;; Test for being in a macro. If so, go to after it.
(progn
(goto-char npos)
(setq macro-beg
(and (c-beginning-of-macro) (/= (point) npos) (point)))
(when macro-beg
(c-syntactic-end-of-macro)
(or (eobp) (forward-char))
(setq macro-end (point)))
(or (null macro-beg)
(prog1 (<= macro-end here)
(setq npos macro-end)))))
(setq pos npos)
(setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
(setq pos npos)
(setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
;; Add one extra element above HERE so as to to avoid the previous
;; expensive calculation when the next call is close to the current
;; one. This is especially useful when inside a large macro.
(setq c-state-nonlit-pos-cache (cons npos c-state-nonlit-pos-cache)))
(if (> pos c-state-nonlit-pos-cache-limit)
(setq c-state-nonlit-pos-cache-limit pos))
pos))))
(defun c-state-semi-safe-place (here)
;; Return a buffer position before HERE which is "safe", i.e. outside any
;; string or comment. It may be in a macro.
(save-restriction
(widen)
(save-excursion
(let ((c c-state-semi-nonlit-pos-cache)
pos npos high-pos lit macro-beg macro-end)
;; Trim the cache to take account of buffer changes.
(while (and c (> (car c) c-state-semi-nonlit-pos-cache-limit))
(setq c (cdr c)))
(setq c-state-semi-nonlit-pos-cache c)
(while (and c (> (car c) here))
(setq high-pos (car c))
(setq c (cdr c)))
(setq pos (or (car c) (point-min)))
(unless high-pos
(while
;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
(and
(<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
;; Test for being in a literal. If so, go to after it.
(progn
(setq lit (car (cddr (c-state-pp-to-literal pos npos))))
(or (null lit)
(prog1 (<= (cdr lit) here)
(setq npos (cdr lit))))))
(setq pos npos)
(setq c-state-semi-nonlit-pos-cache
(cons pos c-state-semi-nonlit-pos-cache))))
(if (> pos c-state-semi-nonlit-pos-cache-limit)
(setq c-state-semi-nonlit-pos-cache-limit pos))
pos))))
(defun c-state-literal-at (here)
;; If position HERE is inside a literal, return (START . END), the
;; boundaries of the literal (which may be outside the accessible bit of the
@ -2985,9 +3106,11 @@ comment at the start of cc-engine.el for more info."
;;
;; This function is called from c-after-change.
;; The cache of non-literals:
;; The caches of non-literals:
(if (< here c-state-nonlit-pos-cache-limit)
(setq c-state-nonlit-pos-cache-limit here))
(if (< here c-state-semi-nonlit-pos-cache-limit)
(setq c-state-semi-nonlit-pos-cache-limit here))
;; `c-state-cache':
;; Case 1: if `here' is in a literal containing point-min, everything
@ -4230,7 +4353,7 @@ Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
(save-restriction
(widen)
(let* ((safe-place (c-state-safe-place (point)))
(let* ((safe-place (c-state-semi-safe-place (point)))
(lit (c-state-pp-to-literal safe-place (point))))
(or (cadr lit)
(and detect-cpp
@ -4254,7 +4377,7 @@ comment at the start of cc-engine.el for more info."
(save-excursion
(let* ((pos (point))
(lim (or lim (c-state-safe-place pos)))
(lim (or lim (c-state-semi-safe-place pos)))
(pp-to-lit (save-restriction
(widen)
(c-state-pp-to-literal lim pos)))
@ -4372,7 +4495,7 @@ comment at the start of cc-engine.el for more info."
;; Get a "safe place" approximately TRY-SIZE characters before START.
;; This doesn't preserve point.
(let* ((pos (max (- start try-size) (point-min)))
(base (c-state-safe-place pos))
(base (c-state-semi-safe-place pos))
(s (parse-partial-sexp base pos)))
(if (or (nth 4 s) (nth 3 s)) ; comment or string
(nth 8 s)

View File

@ -459,8 +459,10 @@ so that all identifiers are recognized as words.")
;; For documentation see the following c-lang-defvar of the same name.
;; The value here may be a list of functions or a single function.
t nil
c++ '(c-extend-region-for-CPP c-before-change-check-<>-operators)
(c objc) 'c-extend-region-for-CPP
c++ '(c-extend-region-for-CPP
c-before-change-check-<>-operators
c-invalidate-macro-cache)
(c objc) '(c-extend-region-for-CPP c-invalidate-macro-cache)
;; java 'c-before-change-check-<>-operators
awk 'c-awk-record-region-clear-NL)
(c-lang-defvar c-get-state-before-change-functions