]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix a cacheing bug, which led to inordinately slow c-beginning-of-defun.
authorAlan Mackenzie <acm@muc.de>
Mon, 14 Mar 2016 21:44:11 +0000 (21:44 +0000)
committerAlan Mackenzie <acm@muc.de>
Mon, 14 Mar 2016 21:48:45 +0000 (21:48 +0000)
* lisp/progmodes/cc-defs.el (c-self-bind-state-cache): New macro.

* lisp/progmodes/cc-engine.el (c-ssb-lit-begin): Always call c-parse-state
rather than just using the cache variable c-state-cache.
(c-syntactic-skip-backward): Invoke c-self-bind-state-cache to isolate calls
to c-parse-state from other uses of the parse state cache.

* lisp/progmodes/cc-cmds.el (c-beginning-of-defun, c-end-of-defun): Invoke
c-self-bind-state-cache around the processing, replacing flawed bindings of
c-state-cache.

lisp/progmodes/cc-cmds.el
lisp/progmodes/cc-defs.el
lisp/progmodes/cc-engine.el

index 6761de1170003e5c3c39704ebfaad2631fa8f3e4..764f44a8dd819fcc322cbae62e3c0f35b50dc568 100644 (file)
@@ -1594,69 +1594,70 @@ defun."
       (c-region-is-active-p)
       (push-mark))
 
-  (c-save-buffer-state
-      (beginning-of-defun-function end-of-defun-function
-       (start (point))
-       (paren-state (copy-tree (c-parse-state))) ; This must not share list
-                                       ; structure with other users of c-state-cache.
-       (orig-point-min (point-min)) (orig-point-max (point-max))
-       lim                         ; Position of { which has been widened to.
-       where pos case-fold-search)
-
-    (save-restriction
-      (if (eq c-defun-tactic 'go-outward)
-         (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace.
-                    paren-state orig-point-min orig-point-max)))
-
-      ;; Move back out of any macro/comment/string we happen to be in.
-      (c-beginning-of-macro)
-      (setq pos (c-literal-limits))
-      (if pos (goto-char (car pos)))
-
-      (setq where (c-where-wrt-brace-construct))
-
-      (if (< arg 0)
-         ;; Move forward to the closing brace of a function.
-         (progn
-           (if (memq where '(at-function-end outwith-function))
-               (setq arg (1+ arg)))
-           (if (< arg 0)
-               (c-while-widening-to-decl-block
-                (< (setq arg (- (c-forward-to-nth-EOF-} (- arg) where))) 0)))
-           ;; Move forward to the next opening brace....
-           (when (and (= arg 0)
-                      (progn
-                        (c-while-widening-to-decl-block
-                         (not (c-syntactic-re-search-forward "{" nil 'eob)))
-                        (eq (char-before) ?{)))
-             (backward-char)
-             ;; ... and backward to the function header.
-             (c-beginning-of-decl-1)
-             t))
-
-       ;; Move backward to the opening brace of a function, making successively
-       ;; larger portions of the buffer visible as necessary.
-       (when (> arg 0)
-         (c-while-widening-to-decl-block
-          (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0)))
-
-       (when (eq arg 0)
-         ;; Go backward to this function's header.
-         (c-beginning-of-decl-1)
-
-         (setq pos (point))
-         ;; We're now there, modulo comments and whitespace.
-         ;; Try to be line oriented; position point at the closest
-         ;; preceding boi that isn't inside a comment, but if we hit
-         ;; the previous declaration then we use the current point
-         ;; instead.
-         (while (and (/= (point) (c-point 'boi))
-                     (c-backward-single-comment)))
-         (if (/= (point) (c-point 'boi))
-             (goto-char pos)))
-
-       (c-keep-region-active)
-       (= arg 0)))))
+  (c-self-bind-state-cache ; We must not share with other users of c-state-cache.
+   (c-save-buffer-state
+       (beginning-of-defun-function
+       end-of-defun-function
+       (start (point))
+       (paren-state (c-parse-state))
+       (orig-point-min (point-min)) (orig-point-max (point-max))
+       lim                 ; Position of { which has been widened to.
+       where pos case-fold-search)
+
+     (save-restriction
+       (if (eq c-defun-tactic 'go-outward)
+          (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace.
+                     paren-state orig-point-min orig-point-max)))
+
+       ;; Move back out of any macro/comment/string we happen to be in.
+       (c-beginning-of-macro)
+       (setq pos (c-literal-limits))
+       (if pos (goto-char (car pos)))
+
+       (setq where (c-where-wrt-brace-construct))
+
+       (if (< arg 0)
+          ;; Move forward to the closing brace of a function.
+          (progn
+            (if (memq where '(at-function-end outwith-function))
+                (setq arg (1+ arg)))
+            (if (< arg 0)
+                (c-while-widening-to-decl-block
+                 (< (setq arg (- (c-forward-to-nth-EOF-} (- arg) where))) 0)))
+            ;; Move forward to the next opening brace....
+            (when (and (= arg 0)
+                       (progn
+                         (c-while-widening-to-decl-block
+                          (not (c-syntactic-re-search-forward "{" nil 'eob)))
+                         (eq (char-before) ?{)))
+              (backward-char)
+              ;; ... and backward to the function header.
+              (c-beginning-of-decl-1)
+              t))
+
+        ;; Move backward to the opening brace of a function, making successively
+        ;; larger portions of the buffer visible as necessary.
+        (when (> arg 0)
+          (c-while-widening-to-decl-block
+           (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0)))
+
+        (when (eq arg 0)
+          ;; Go backward to this function's header.
+          (c-beginning-of-decl-1)
+
+          (setq pos (point))
+          ;; We're now there, modulo comments and whitespace.
+          ;; Try to be line oriented; position point at the closest
+          ;; preceding boi that isn't inside a comment, but if we hit
+          ;; the previous declaration then we use the current point
+          ;; instead.
+          (while (and (/= (point) (c-point 'boi))
+                      (c-backward-single-comment)))
+          (if (/= (point) (c-point 'boi))
+              (goto-char pos)))
+
+        (c-keep-region-active)
+        (= arg 0))))))
 
 (defun c-forward-to-nth-EOF-} (n where)
   ;; Skip to the closing brace of the Nth function after point.  If
@@ -1718,66 +1719,68 @@ the open-parenthesis that starts a defun; see `beginning-of-defun'."
       (c-region-is-active-p)
       (push-mark))
 
-  (c-save-buffer-state
-      (beginning-of-defun-function end-of-defun-function
-       (start (point))
-       (paren-state (copy-tree (c-parse-state))) ; This must not share list
-                                 ; structure with other users of c-state-cache.
-       (orig-point-min (point-min)) (orig-point-max (point-max))
-       lim
-       where pos case-fold-search)
-
-    (save-restriction
-      (if (eq c-defun-tactic 'go-outward)
-         (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace
-                    paren-state orig-point-min orig-point-max)))
-
-      ;; Move back out of any macro/comment/string we happen to be in.
-      (c-beginning-of-macro)
-      (setq pos (c-literal-limits))
-      (if pos (goto-char (car pos)))
-
-      (setq where (c-where-wrt-brace-construct))
+  (c-self-bind-state-cache ; c-state-cache's list structure must not be shared
+                          ; with other users.
+   (c-save-buffer-state
+       (beginning-of-defun-function
+       end-of-defun-function
+       (start (point))
+       (paren-state (c-parse-state))
+       (orig-point-min (point-min)) (orig-point-max (point-max))
+       lim
+       where pos case-fold-search)
+
+     (save-restriction
+       (if (eq c-defun-tactic 'go-outward)
+          (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace
+                     paren-state orig-point-min orig-point-max)))
+
+       ;; Move back out of any macro/comment/string we happen to be in.
+       (c-beginning-of-macro)
+       (setq pos (c-literal-limits))
+       (if pos (goto-char (car pos)))
+
+       (setq where (c-where-wrt-brace-construct))
+
+       (if (< arg 0)
+          ;; Move backwards to the } of a function
+          (progn
+            (if (memq where '(at-header outwith-function))
+                (setq arg (1+ arg)))
+            (if (< arg 0)
+                (c-while-widening-to-decl-block
+                 (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0)))
+            (if (= arg 0)
+                (c-while-widening-to-decl-block
+                 (progn (c-syntactic-skip-backward "^}")
+                        (not (eq (char-before) ?}))))))
+
+        ;; Move forward to the } of a function
+        (if (> arg 0)
+            (c-while-widening-to-decl-block
+             (> (setq arg (c-forward-to-nth-EOF-} arg where)) 0))))
+
+       ;; Do we need to move forward from the brace to the semicolon?
+       (when (eq arg 0)
+        (if (c-in-function-trailer-p)  ; after "}" of struct/enum, etc.
+            (c-syntactic-re-search-forward ";"))
 
-      (if (< arg 0)
-         ;; Move backwards to the } of a function
-         (progn
-           (if (memq where '(at-header outwith-function))
-               (setq arg (1+ arg)))
-           (if (< arg 0)
-               (c-while-widening-to-decl-block
-                (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0)))
-           (if (= arg 0)
-               (c-while-widening-to-decl-block
-                (progn (c-syntactic-skip-backward "^}")
-                       (not (eq (char-before) ?}))))))
-
-       ;; Move forward to the } of a function
-       (if (> arg 0)
-           (c-while-widening-to-decl-block
-            (> (setq arg (c-forward-to-nth-EOF-} arg where)) 0))))
-
-      ;; Do we need to move forward from the brace to the semicolon?
-      (when (eq arg 0)
-       (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc.
-           (c-syntactic-re-search-forward ";"))
+        (setq pos (point))
+        ;; We're there now, modulo comments and whitespace.
+        ;; Try to be line oriented; position point after the next
+        ;; newline that isn't inside a comment, but if we hit the
+        ;; next declaration then we use the current point instead.
+        (while (and (not (bolp))
+                    (not (looking-at "\\s *$"))
+                    (c-forward-single-comment)))
+        (cond ((bolp))
+              ((looking-at "\\s *$")
+               (forward-line 1))
+              (t
+               (goto-char pos))))
 
-       (setq pos (point))
-       ;; We're there now, modulo comments and whitespace.
-       ;; Try to be line oriented; position point after the next
-       ;; newline that isn't inside a comment, but if we hit the
-       ;; next declaration then we use the current point instead.
-       (while (and (not (bolp))
-                   (not (looking-at "\\s *$"))
-                   (c-forward-single-comment)))
-       (cond ((bolp))
-             ((looking-at "\\s *$")
-              (forward-line 1))
-             (t
-              (goto-char pos))))
-
-      (c-keep-region-active)
-      (= arg 0))))
+       (c-keep-region-active)
+       (= arg 0)))))
 
 (defun c-defun-name ()
   "Return the name of the current defun, or NIL if there isn't one.
index 000995c5b5332cea6b0850fad53a96c88d2110a2..3b9f44e55a0187fb3be969d00a77cb543c7bc7f7 100644 (file)
@@ -1258,7 +1258,8 @@ been put there by c-put-char-property.  POINT remains unchanged."
 (def-edebug-spec c-clear-char-property t)
 (def-edebug-spec c-clear-char-properties t)
 (def-edebug-spec c-put-overlay t)
-(def-edebug-spec c-delete-overlay t) ;))
+(def-edebug-spec c-delete-overlay t)
+(def-edebug-spec c-self-bind-state-cache t);))
 
 \f
 ;;; Functions.
@@ -1397,6 +1398,26 @@ been put there by c-put-char-property.  POINT remains unchanged."
        (save-restriction
         (widen)
         (c-set-cpp-delimiters ,beg ,end)))))
+
+(defmacro c-self-bind-state-cache (&rest forms)
+  ;; Bind the state cache to itself and execute the FORMS.  It is assumed that no
+  ;; buffer changes will happen in FORMS, and no hidden buffer changes which could
+  ;; affect the parsing will be made by FORMS.
+  `(let ((c-state-cache (copy-tree c-state-cache))
+        (c-state-cache-good-pos c-state-cache-good-pos)
+        ;(c-state-nonlit-pos-cache (copy-tree c-state-nonlit-pos-cache))
+        ;(c-state-nonlit-pos-cache-limit c-state-nonlit-pos-cache-limit)
+        ;(c-state-semi-nonlit-pos-cache (copy-treec c-state-semi-nonlit-pos-cache))
+        ;(c-state-semi-nonlit-pos-cache-limit c-state-semi-nonlit-pos-cache)
+        (c-state-brace-pair-desert (copy-tree c-state-brace-pair-desert))
+        (c-state-point-min c-state-point-min)
+        (c-state-point-min-lit-type c-state-point-min-lit-type)
+        (c-state-point-min-lit-start c-state-point-min-lit-start)
+        (c-state-min-scan-pos c-state-min-scan-pos)
+        (c-state-old-cpp-beg c-state-old-cpp-beg)
+        (c-state-old-cpp-end c-state-old-cpp-end))
+     ,@forms))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; The following macros are to be used only in `c-parse-state' and its
index 69a2a53d5c926fc2b9e76744cd063cfa2c260652..afe87c5ee6a9dd560b86b0d7604a180f278bb7a0 100644 (file)
@@ -4259,8 +4259,7 @@ comment at the start of cc-engine.el for more info."
        (setq safe-pos-list (cdr safe-pos-list)))
       (unless (setq safe-pos (car-safe safe-pos-list))
        (setq safe-pos (max (or (c-safe-position
-                                (point) (or c-state-cache
-                                            (c-parse-state)))
+                                (point) (c-parse-state))
                                0)
                            (point-min))
              safe-pos-list (list safe-pos)))
@@ -4308,107 +4307,108 @@ Non-nil is returned if the point moved, nil otherwise.
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
 
-  (let ((start (point))
-       state-2
-       ;; A list of syntactically relevant positions in descending
-       ;; order.  It's used to avoid scanning repeatedly over
-       ;; potentially large regions with `parse-partial-sexp' to verify
-       ;; each position.  Used in `c-ssb-lit-begin'
-       safe-pos-list
-       ;; The result from `c-beginning-of-macro' at the start position or the
-       ;; start position itself if it isn't within a macro.  Evaluated on
-       ;; demand.
-       start-macro-beg
-       ;; The earliest position after the current one with the same paren
-       ;; level.  Used only when `paren-level' is set.
-       lit-beg
-       (paren-level-pos (point)))
-
-    (while
-       (progn
-         ;; The next loop "tries" to find the end point each time round,
-         ;; loops when it hasn't succeeded.
-         (while
-             (and
-              (let ((pos (point)))
-                (while (and
-                        (< (skip-chars-backward skip-chars limit) 0)
-                        ;; Don't stop inside a literal.
-                        (when (setq lit-beg (c-ssb-lit-begin))
-                          (goto-char lit-beg)
-                          t)))
-                (< (point) pos))
+  (c-self-bind-state-cache
+   (let ((start (point))
+        state-2
+        ;; A list of syntactically relevant positions in descending
+        ;; order.  It's used to avoid scanning repeatedly over
+        ;; potentially large regions with `parse-partial-sexp' to verify
+        ;; each position.  Used in `c-ssb-lit-begin'
+        safe-pos-list
+        ;; The result from `c-beginning-of-macro' at the start position or the
+        ;; start position itself if it isn't within a macro.  Evaluated on
+        ;; demand.
+        start-macro-beg
+        ;; The earliest position after the current one with the same paren
+        ;; level.  Used only when `paren-level' is set.
+        lit-beg
+        (paren-level-pos (point)))
+
+     (while
+        (progn
+          ;; The next loop "tries" to find the end point each time round,
+          ;; loops when it hasn't succeeded.
+          (while
+              (and
+               (let ((pos (point)))
+                 (while (and
+                         (< (skip-chars-backward skip-chars limit) 0)
+                         ;; Don't stop inside a literal.
+                         (when (setq lit-beg (c-ssb-lit-begin))
+                           (goto-char lit-beg)
+                           t)))
+                 (< (point) pos))
+
+               (let ((pos (point)) state-2 pps-end-pos)
 
-              (let ((pos (point)) state-2 pps-end-pos)
+                 (cond
+                  ((and paren-level
+                        (save-excursion
+                          (setq state-2 (parse-partial-sexp
+                                         pos paren-level-pos -1)
+                                pps-end-pos (point))
+                          (/= (car state-2) 0)))
+                   ;; Not at the right level.
+
+                   (if (and (< (car state-2) 0)
+                            ;; We stop above if we go out of a paren.
+                            ;; Now check whether it precedes or is
+                            ;; nested in the starting sexp.
+                            (save-excursion
+                              (setq state-2
+                                    (parse-partial-sexp
+                                     pps-end-pos paren-level-pos
+                                     nil nil state-2))
+                              (< (car state-2) 0)))
+
+                       ;; We've stopped short of the starting position
+                       ;; so the hit was inside a nested list.  Go up
+                       ;; until we are at the right level.
+                       (condition-case nil
+                           (progn
+                             (goto-char (scan-lists pos -1
+                                                    (- (car state-2))))
+                             (setq paren-level-pos (point))
+                             (if (and limit (>= limit paren-level-pos))
+                                 (progn
+                                   (goto-char limit)
+                                   nil)
+                               t))
+                         (error
+                          (goto-char (or limit (point-min)))
+                          nil))
+
+                     ;; The hit was outside the list at the start
+                     ;; position.  Go to the start of the list and exit.
+                     (goto-char (1+ (elt state-2 1)))
+                     nil))
+
+                  ((c-beginning-of-macro limit)
+                   ;; Inside a macro.
+                   (if (< (point)
+                          (or start-macro-beg
+                              (setq start-macro-beg
+                                    (save-excursion
+                                      (goto-char start)
+                                      (c-beginning-of-macro limit)
+                                      (point)))))
+                       t
+
+                     ;; It's inside the same macro we started in so it's
+                     ;; a relevant match.
+                     (goto-char pos)
+                     nil))))))
 
-                (cond
-                 ((and paren-level
-                       (save-excursion
-                         (setq state-2 (parse-partial-sexp
-                                        pos paren-level-pos -1)
-                               pps-end-pos (point))
-                         (/= (car state-2) 0)))
-                  ;; Not at the right level.
-
-                  (if (and (< (car state-2) 0)
-                           ;; We stop above if we go out of a paren.
-                           ;; Now check whether it precedes or is
-                           ;; nested in the starting sexp.
-                           (save-excursion
-                             (setq state-2
-                                   (parse-partial-sexp
-                                    pps-end-pos paren-level-pos
-                                    nil nil state-2))
-                             (< (car state-2) 0)))
-
-                      ;; We've stopped short of the starting position
-                      ;; so the hit was inside a nested list.  Go up
-                      ;; until we are at the right level.
-                      (condition-case nil
-                          (progn
-                            (goto-char (scan-lists pos -1
-                                                   (- (car state-2))))
-                            (setq paren-level-pos (point))
-                            (if (and limit (>= limit paren-level-pos))
-                                (progn
-                                  (goto-char limit)
-                                  nil)
-                              t))
-                        (error
-                         (goto-char (or limit (point-min)))
-                         nil))
-
-                    ;; The hit was outside the list at the start
-                    ;; position.  Go to the start of the list and exit.
-                    (goto-char (1+ (elt state-2 1)))
-                    nil))
-
-                 ((c-beginning-of-macro limit)
-                  ;; Inside a macro.
-                  (if (< (point)
-                         (or start-macro-beg
-                             (setq start-macro-beg
-                                   (save-excursion
-                                     (goto-char start)
-                                     (c-beginning-of-macro limit)
-                                     (point)))))
-                      t
-
-                    ;; It's inside the same macro we started in so it's
-                    ;; a relevant match.
-                    (goto-char pos)
-                    nil))))))
-
-         (> (point)
-            (progn
-              ;; Skip syntactic ws afterwards so that we don't stop at the
-              ;; end of a comment if `skip-chars' is something like "^/".
-              (c-backward-syntactic-ws)
-              (point)))))
+          (> (point)
+             (progn
+               ;; Skip syntactic ws afterwards so that we don't stop at the
+               ;; end of a comment if `skip-chars' is something like "^/".
+               (c-backward-syntactic-ws)
+               (point)))))
 
-    ;; We might want to extend this with more useful return values in
-    ;; the future.
-    (/= (point) start)))
+     ;; We might want to extend this with more useful return values in
+     ;; the future.
+     (/= (point) start))))
 
 ;; The following is an alternative implementation of
 ;; `c-syntactic-skip-backward' that uses backward movement to keep