aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2016-03-14 21:44:11 +0000
committerAlan Mackenzie2016-03-14 21:48:45 +0000
commit5cc691930808ccf7afdbc53ed49ca24badd97013 (patch)
treef986652c247488eb6c2d09d2db388599e206256e
parent0ce37eac45f8b1279e89e854f71bb3f35fd43d29 (diff)
downloademacs-5cc691930808ccf7afdbc53ed49ca24badd97013.tar.gz
emacs-5cc691930808ccf7afdbc53ed49ca24badd97013.zip
Fix a cacheing bug, which led to inordinately slow c-beginning-of-defun.
* 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.
-rw-r--r--lisp/progmodes/cc-cmds.el245
-rw-r--r--lisp/progmodes/cc-defs.el23
-rw-r--r--lisp/progmodes/cc-engine.el200
3 files changed, 246 insertions, 222 deletions
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 6761de11700..764f44a8dd8 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -1594,69 +1594,70 @@ defun."
1594 (c-region-is-active-p) 1594 (c-region-is-active-p)
1595 (push-mark)) 1595 (push-mark))
1596 1596
1597 (c-save-buffer-state 1597 (c-self-bind-state-cache ; We must not share with other users of c-state-cache.
1598 (beginning-of-defun-function end-of-defun-function 1598 (c-save-buffer-state
1599 (start (point)) 1599 (beginning-of-defun-function
1600 (paren-state (copy-tree (c-parse-state))) ; This must not share list 1600 end-of-defun-function
1601 ; structure with other users of c-state-cache. 1601 (start (point))
1602 (orig-point-min (point-min)) (orig-point-max (point-max)) 1602 (paren-state (c-parse-state))
1603 lim ; Position of { which has been widened to. 1603 (orig-point-min (point-min)) (orig-point-max (point-max))
1604 where pos case-fold-search) 1604 lim ; Position of { which has been widened to.
1605 1605 where pos case-fold-search)
1606 (save-restriction 1606
1607 (if (eq c-defun-tactic 'go-outward) 1607 (save-restriction
1608 (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace. 1608 (if (eq c-defun-tactic 'go-outward)
1609 paren-state orig-point-min orig-point-max))) 1609 (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace.
1610 1610 paren-state orig-point-min orig-point-max)))
1611 ;; Move back out of any macro/comment/string we happen to be in. 1611
1612 (c-beginning-of-macro) 1612 ;; Move back out of any macro/comment/string we happen to be in.
1613 (setq pos (c-literal-limits)) 1613 (c-beginning-of-macro)
1614 (if pos (goto-char (car pos))) 1614 (setq pos (c-literal-limits))
1615 1615 (if pos (goto-char (car pos)))
1616 (setq where (c-where-wrt-brace-construct)) 1616
1617 1617 (setq where (c-where-wrt-brace-construct))
1618 (if (< arg 0) 1618
1619 ;; Move forward to the closing brace of a function. 1619 (if (< arg 0)
1620 (progn 1620 ;; Move forward to the closing brace of a function.
1621 (if (memq where '(at-function-end outwith-function)) 1621 (progn
1622 (setq arg (1+ arg))) 1622 (if (memq where '(at-function-end outwith-function))
1623 (if (< arg 0) 1623 (setq arg (1+ arg)))
1624 (c-while-widening-to-decl-block 1624 (if (< arg 0)
1625 (< (setq arg (- (c-forward-to-nth-EOF-} (- arg) where))) 0))) 1625 (c-while-widening-to-decl-block
1626 ;; Move forward to the next opening brace.... 1626 (< (setq arg (- (c-forward-to-nth-EOF-} (- arg) where))) 0)))
1627 (when (and (= arg 0) 1627 ;; Move forward to the next opening brace....
1628 (progn 1628 (when (and (= arg 0)
1629 (c-while-widening-to-decl-block 1629 (progn
1630 (not (c-syntactic-re-search-forward "{" nil 'eob))) 1630 (c-while-widening-to-decl-block
1631 (eq (char-before) ?{))) 1631 (not (c-syntactic-re-search-forward "{" nil 'eob)))
1632 (backward-char) 1632 (eq (char-before) ?{)))
1633 ;; ... and backward to the function header. 1633 (backward-char)
1634 (c-beginning-of-decl-1) 1634 ;; ... and backward to the function header.
1635 t)) 1635 (c-beginning-of-decl-1)
1636 1636 t))
1637 ;; Move backward to the opening brace of a function, making successively 1637
1638 ;; larger portions of the buffer visible as necessary. 1638 ;; Move backward to the opening brace of a function, making successively
1639 (when (> arg 0) 1639 ;; larger portions of the buffer visible as necessary.
1640 (c-while-widening-to-decl-block 1640 (when (> arg 0)
1641 (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))) 1641 (c-while-widening-to-decl-block
1642 1642 (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0)))
1643 (when (eq arg 0) 1643
1644 ;; Go backward to this function's header. 1644 (when (eq arg 0)
1645 (c-beginning-of-decl-1) 1645 ;; Go backward to this function's header.
1646 1646 (c-beginning-of-decl-1)
1647 (setq pos (point)) 1647
1648 ;; We're now there, modulo comments and whitespace. 1648 (setq pos (point))
1649 ;; Try to be line oriented; position point at the closest 1649 ;; We're now there, modulo comments and whitespace.
1650 ;; preceding boi that isn't inside a comment, but if we hit 1650 ;; Try to be line oriented; position point at the closest
1651 ;; the previous declaration then we use the current point 1651 ;; preceding boi that isn't inside a comment, but if we hit
1652 ;; instead. 1652 ;; the previous declaration then we use the current point
1653 (while (and (/= (point) (c-point 'boi)) 1653 ;; instead.
1654 (c-backward-single-comment))) 1654 (while (and (/= (point) (c-point 'boi))
1655 (if (/= (point) (c-point 'boi)) 1655 (c-backward-single-comment)))
1656 (goto-char pos))) 1656 (if (/= (point) (c-point 'boi))
1657 1657 (goto-char pos)))
1658 (c-keep-region-active) 1658
1659 (= arg 0))))) 1659 (c-keep-region-active)
1660 (= arg 0))))))
1660 1661
1661(defun c-forward-to-nth-EOF-} (n where) 1662(defun c-forward-to-nth-EOF-} (n where)
1662 ;; Skip to the closing brace of the Nth function after point. If 1663 ;; 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'."
1718 (c-region-is-active-p) 1719 (c-region-is-active-p)
1719 (push-mark)) 1720 (push-mark))
1720 1721
1721 (c-save-buffer-state 1722 (c-self-bind-state-cache ; c-state-cache's list structure must not be shared
1722 (beginning-of-defun-function end-of-defun-function 1723 ; with other users.
1723 (start (point)) 1724 (c-save-buffer-state
1724 (paren-state (copy-tree (c-parse-state))) ; This must not share list 1725 (beginning-of-defun-function
1725 ; structure with other users of c-state-cache. 1726 end-of-defun-function
1726 (orig-point-min (point-min)) (orig-point-max (point-max)) 1727 (start (point))
1727 lim 1728 (paren-state (c-parse-state))
1728 where pos case-fold-search) 1729 (orig-point-min (point-min)) (orig-point-max (point-max))
1729 1730 lim
1730 (save-restriction 1731 where pos case-fold-search)
1731 (if (eq c-defun-tactic 'go-outward) 1732
1732 (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace 1733 (save-restriction
1733 paren-state orig-point-min orig-point-max))) 1734 (if (eq c-defun-tactic 'go-outward)
1734 1735 (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace
1735 ;; Move back out of any macro/comment/string we happen to be in. 1736 paren-state orig-point-min orig-point-max)))
1736 (c-beginning-of-macro) 1737
1737 (setq pos (c-literal-limits)) 1738 ;; Move back out of any macro/comment/string we happen to be in.
1738 (if pos (goto-char (car pos))) 1739 (c-beginning-of-macro)
1739 1740 (setq pos (c-literal-limits))
1740 (setq where (c-where-wrt-brace-construct)) 1741 (if pos (goto-char (car pos)))
1742
1743 (setq where (c-where-wrt-brace-construct))
1744
1745 (if (< arg 0)
1746 ;; Move backwards to the } of a function
1747 (progn
1748 (if (memq where '(at-header outwith-function))
1749 (setq arg (1+ arg)))
1750 (if (< arg 0)
1751 (c-while-widening-to-decl-block
1752 (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0)))
1753 (if (= arg 0)
1754 (c-while-widening-to-decl-block
1755 (progn (c-syntactic-skip-backward "^}")
1756 (not (eq (char-before) ?}))))))
1757
1758 ;; Move forward to the } of a function
1759 (if (> arg 0)
1760 (c-while-widening-to-decl-block
1761 (> (setq arg (c-forward-to-nth-EOF-} arg where)) 0))))
1762
1763 ;; Do we need to move forward from the brace to the semicolon?
1764 (when (eq arg 0)
1765 (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc.
1766 (c-syntactic-re-search-forward ";"))
1741 1767
1742 (if (< arg 0) 1768 (setq pos (point))
1743 ;; Move backwards to the } of a function 1769 ;; We're there now, modulo comments and whitespace.
1744 (progn 1770 ;; Try to be line oriented; position point after the next
1745 (if (memq where '(at-header outwith-function)) 1771 ;; newline that isn't inside a comment, but if we hit the
1746 (setq arg (1+ arg))) 1772 ;; next declaration then we use the current point instead.
1747 (if (< arg 0) 1773 (while (and (not (bolp))
1748 (c-while-widening-to-decl-block 1774 (not (looking-at "\\s *$"))
1749 (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0))) 1775 (c-forward-single-comment)))
1750 (if (= arg 0) 1776 (cond ((bolp))
1751 (c-while-widening-to-decl-block 1777 ((looking-at "\\s *$")
1752 (progn (c-syntactic-skip-backward "^}") 1778 (forward-line 1))
1753 (not (eq (char-before) ?})))))) 1779 (t
1754 1780 (goto-char pos))))
1755 ;; Move forward to the } of a function
1756 (if (> arg 0)
1757 (c-while-widening-to-decl-block
1758 (> (setq arg (c-forward-to-nth-EOF-} arg where)) 0))))
1759
1760 ;; Do we need to move forward from the brace to the semicolon?
1761 (when (eq arg 0)
1762 (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc.
1763 (c-syntactic-re-search-forward ";"))
1764 1781
1765 (setq pos (point)) 1782 (c-keep-region-active)
1766 ;; We're there now, modulo comments and whitespace. 1783 (= arg 0)))))
1767 ;; Try to be line oriented; position point after the next
1768 ;; newline that isn't inside a comment, but if we hit the
1769 ;; next declaration then we use the current point instead.
1770 (while (and (not (bolp))
1771 (not (looking-at "\\s *$"))
1772 (c-forward-single-comment)))
1773 (cond ((bolp))
1774 ((looking-at "\\s *$")
1775 (forward-line 1))
1776 (t
1777 (goto-char pos))))
1778
1779 (c-keep-region-active)
1780 (= arg 0))))
1781 1784
1782(defun c-defun-name () 1785(defun c-defun-name ()
1783 "Return the name of the current defun, or NIL if there isn't one. 1786 "Return the name of the current defun, or NIL if there isn't one.
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el
index 000995c5b53..3b9f44e55a0 100644
--- a/lisp/progmodes/cc-defs.el
+++ b/lisp/progmodes/cc-defs.el
@@ -1258,7 +1258,8 @@ been put there by c-put-char-property. POINT remains unchanged."
1258(def-edebug-spec c-clear-char-property t) 1258(def-edebug-spec c-clear-char-property t)
1259(def-edebug-spec c-clear-char-properties t) 1259(def-edebug-spec c-clear-char-properties t)
1260(def-edebug-spec c-put-overlay t) 1260(def-edebug-spec c-put-overlay t)
1261(def-edebug-spec c-delete-overlay t) ;)) 1261(def-edebug-spec c-delete-overlay t)
1262(def-edebug-spec c-self-bind-state-cache t);))
1262 1263
1263 1264
1264;;; Functions. 1265;;; Functions.
@@ -1397,6 +1398,26 @@ been put there by c-put-char-property. POINT remains unchanged."
1397 (save-restriction 1398 (save-restriction
1398 (widen) 1399 (widen)
1399 (c-set-cpp-delimiters ,beg ,end))))) 1400 (c-set-cpp-delimiters ,beg ,end)))))
1401
1402(defmacro c-self-bind-state-cache (&rest forms)
1403 ;; Bind the state cache to itself and execute the FORMS. It is assumed that no
1404 ;; buffer changes will happen in FORMS, and no hidden buffer changes which could
1405 ;; affect the parsing will be made by FORMS.
1406 `(let ((c-state-cache (copy-tree c-state-cache))
1407 (c-state-cache-good-pos c-state-cache-good-pos)
1408 ;(c-state-nonlit-pos-cache (copy-tree c-state-nonlit-pos-cache))
1409 ;(c-state-nonlit-pos-cache-limit c-state-nonlit-pos-cache-limit)
1410 ;(c-state-semi-nonlit-pos-cache (copy-treec c-state-semi-nonlit-pos-cache))
1411 ;(c-state-semi-nonlit-pos-cache-limit c-state-semi-nonlit-pos-cache)
1412 (c-state-brace-pair-desert (copy-tree c-state-brace-pair-desert))
1413 (c-state-point-min c-state-point-min)
1414 (c-state-point-min-lit-type c-state-point-min-lit-type)
1415 (c-state-point-min-lit-start c-state-point-min-lit-start)
1416 (c-state-min-scan-pos c-state-min-scan-pos)
1417 (c-state-old-cpp-beg c-state-old-cpp-beg)
1418 (c-state-old-cpp-end c-state-old-cpp-end))
1419 ,@forms))
1420
1400 1421
1401;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1422;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1402;; The following macros are to be used only in `c-parse-state' and its 1423;; The following macros are to be used only in `c-parse-state' and its
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 69a2a53d5c9..afe87c5ee6a 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -4259,8 +4259,7 @@ comment at the start of cc-engine.el for more info."
4259 (setq safe-pos-list (cdr safe-pos-list))) 4259 (setq safe-pos-list (cdr safe-pos-list)))
4260 (unless (setq safe-pos (car-safe safe-pos-list)) 4260 (unless (setq safe-pos (car-safe safe-pos-list))
4261 (setq safe-pos (max (or (c-safe-position 4261 (setq safe-pos (max (or (c-safe-position
4262 (point) (or c-state-cache 4262 (point) (c-parse-state))
4263 (c-parse-state)))
4264 0) 4263 0)
4265 (point-min)) 4264 (point-min))
4266 safe-pos-list (list safe-pos))) 4265 safe-pos-list (list safe-pos)))
@@ -4308,107 +4307,108 @@ Non-nil is returned if the point moved, nil otherwise.
4308Note that this function might do hidden buffer changes. See the 4307Note that this function might do hidden buffer changes. See the
4309comment at the start of cc-engine.el for more info." 4308comment at the start of cc-engine.el for more info."
4310 4309
4311 (let ((start (point)) 4310 (c-self-bind-state-cache
4312 state-2 4311 (let ((start (point))
4313 ;; A list of syntactically relevant positions in descending 4312 state-2
4314 ;; order. It's used to avoid scanning repeatedly over 4313 ;; A list of syntactically relevant positions in descending
4315 ;; potentially large regions with `parse-partial-sexp' to verify 4314 ;; order. It's used to avoid scanning repeatedly over
4316 ;; each position. Used in `c-ssb-lit-begin' 4315 ;; potentially large regions with `parse-partial-sexp' to verify
4317 safe-pos-list 4316 ;; each position. Used in `c-ssb-lit-begin'
4318 ;; The result from `c-beginning-of-macro' at the start position or the 4317 safe-pos-list
4319 ;; start position itself if it isn't within a macro. Evaluated on 4318 ;; The result from `c-beginning-of-macro' at the start position or the
4320 ;; demand. 4319 ;; start position itself if it isn't within a macro. Evaluated on
4321 start-macro-beg 4320 ;; demand.
4322 ;; The earliest position after the current one with the same paren 4321 start-macro-beg
4323 ;; level. Used only when `paren-level' is set. 4322 ;; The earliest position after the current one with the same paren
4324 lit-beg 4323 ;; level. Used only when `paren-level' is set.
4325 (paren-level-pos (point))) 4324 lit-beg
4326 4325 (paren-level-pos (point)))
4327 (while 4326
4328 (progn 4327 (while
4329 ;; The next loop "tries" to find the end point each time round, 4328 (progn
4330 ;; loops when it hasn't succeeded. 4329 ;; The next loop "tries" to find the end point each time round,
4331 (while 4330 ;; loops when it hasn't succeeded.
4332 (and 4331 (while
4333 (let ((pos (point))) 4332 (and
4334 (while (and 4333 (let ((pos (point)))
4335 (< (skip-chars-backward skip-chars limit) 0) 4334 (while (and
4336 ;; Don't stop inside a literal. 4335 (< (skip-chars-backward skip-chars limit) 0)
4337 (when (setq lit-beg (c-ssb-lit-begin)) 4336 ;; Don't stop inside a literal.
4338 (goto-char lit-beg) 4337 (when (setq lit-beg (c-ssb-lit-begin))
4339 t))) 4338 (goto-char lit-beg)
4340 (< (point) pos)) 4339 t)))
4340 (< (point) pos))
4341
4342 (let ((pos (point)) state-2 pps-end-pos)
4341 4343
4342 (let ((pos (point)) state-2 pps-end-pos) 4344 (cond
4345 ((and paren-level
4346 (save-excursion
4347 (setq state-2 (parse-partial-sexp
4348 pos paren-level-pos -1)
4349 pps-end-pos (point))
4350 (/= (car state-2) 0)))
4351 ;; Not at the right level.
4352
4353 (if (and (< (car state-2) 0)
4354 ;; We stop above if we go out of a paren.
4355 ;; Now check whether it precedes or is
4356 ;; nested in the starting sexp.
4357 (save-excursion
4358 (setq state-2
4359 (parse-partial-sexp
4360 pps-end-pos paren-level-pos
4361 nil nil state-2))
4362 (< (car state-2) 0)))
4363
4364 ;; We've stopped short of the starting position
4365 ;; so the hit was inside a nested list. Go up
4366 ;; until we are at the right level.
4367 (condition-case nil
4368 (progn
4369 (goto-char (scan-lists pos -1
4370 (- (car state-2))))
4371 (setq paren-level-pos (point))
4372 (if (and limit (>= limit paren-level-pos))
4373 (progn
4374 (goto-char limit)
4375 nil)
4376 t))
4377 (error
4378 (goto-char (or limit (point-min)))
4379 nil))
4380
4381 ;; The hit was outside the list at the start
4382 ;; position. Go to the start of the list and exit.
4383 (goto-char (1+ (elt state-2 1)))
4384 nil))
4385
4386 ((c-beginning-of-macro limit)
4387 ;; Inside a macro.
4388 (if (< (point)
4389 (or start-macro-beg
4390 (setq start-macro-beg
4391 (save-excursion
4392 (goto-char start)
4393 (c-beginning-of-macro limit)
4394 (point)))))
4395 t
4396
4397 ;; It's inside the same macro we started in so it's
4398 ;; a relevant match.
4399 (goto-char pos)
4400 nil))))))
4343 4401
4344 (cond 4402 (> (point)
4345 ((and paren-level 4403 (progn
4346 (save-excursion 4404 ;; Skip syntactic ws afterwards so that we don't stop at the
4347 (setq state-2 (parse-partial-sexp 4405 ;; end of a comment if `skip-chars' is something like "^/".
4348 pos paren-level-pos -1) 4406 (c-backward-syntactic-ws)
4349 pps-end-pos (point)) 4407 (point)))))
4350 (/= (car state-2) 0)))
4351 ;; Not at the right level.
4352
4353 (if (and (< (car state-2) 0)
4354 ;; We stop above if we go out of a paren.
4355 ;; Now check whether it precedes or is
4356 ;; nested in the starting sexp.
4357 (save-excursion
4358 (setq state-2
4359 (parse-partial-sexp
4360 pps-end-pos paren-level-pos
4361 nil nil state-2))
4362 (< (car state-2) 0)))
4363
4364 ;; We've stopped short of the starting position
4365 ;; so the hit was inside a nested list. Go up
4366 ;; until we are at the right level.
4367 (condition-case nil
4368 (progn
4369 (goto-char (scan-lists pos -1
4370 (- (car state-2))))
4371 (setq paren-level-pos (point))
4372 (if (and limit (>= limit paren-level-pos))
4373 (progn
4374 (goto-char limit)
4375 nil)
4376 t))
4377 (error
4378 (goto-char (or limit (point-min)))
4379 nil))
4380
4381 ;; The hit was outside the list at the start
4382 ;; position. Go to the start of the list and exit.
4383 (goto-char (1+ (elt state-2 1)))
4384 nil))
4385
4386 ((c-beginning-of-macro limit)
4387 ;; Inside a macro.
4388 (if (< (point)
4389 (or start-macro-beg
4390 (setq start-macro-beg
4391 (save-excursion
4392 (goto-char start)
4393 (c-beginning-of-macro limit)
4394 (point)))))
4395 t
4396
4397 ;; It's inside the same macro we started in so it's
4398 ;; a relevant match.
4399 (goto-char pos)
4400 nil))))))
4401
4402 (> (point)
4403 (progn
4404 ;; Skip syntactic ws afterwards so that we don't stop at the
4405 ;; end of a comment if `skip-chars' is something like "^/".
4406 (c-backward-syntactic-ws)
4407 (point)))))
4408 4408
4409 ;; We might want to extend this with more useful return values in 4409 ;; We might want to extend this with more useful return values in
4410 ;; the future. 4410 ;; the future.
4411 (/= (point) start))) 4411 (/= (point) start))))
4412 4412
4413;; The following is an alternative implementation of 4413;; The following is an alternative implementation of
4414;; `c-syntactic-skip-backward' that uses backward movement to keep 4414;; `c-syntactic-skip-backward' that uses backward movement to keep