aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2013-10-03 00:58:56 -0400
committerStefan Monnier2013-10-03 00:58:56 -0400
commitadf2aa61404305e58e71cde0193bb650aff2c4b3 (patch)
treed6e6b4e5ab3b144a94daed2232cab798aadeb20a /lisp
parent328a8179fec33f5a75e2cfe22e43f4ec0df770b7 (diff)
downloademacs-adf2aa61404305e58e71cde0193bb650aff2c4b3.tar.gz
emacs-adf2aa61404305e58e71cde0193bb650aff2c4b3.zip
Introduce new bytecodes for efficient catch/condition-case in lexbind.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker): Optimize under `condition-case' and `catch' if byte-compile--use-old-handlers is nil. (disassemble-offset): Handle new bytecodes. * lisp/emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase) (byte-pophandler): New byte codes. (byte-goto-ops): Adjust accordingly. (byte-compile--use-old-handlers): New var. (byte-compile-catch): Use new byte codes depending on byte-compile--use-old-handlers. (byte-compile-condition-case--old): Rename from byte-compile-condition-case. (byte-compile-condition-case--new): New function. (byte-compile-condition-case): New function that dispatches depending on byte-compile--use-old-handlers. (byte-compile-unwind-protect): Pass a function to byte-unwind-protect when we can. * lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for the new compilation scheme using the new byte-codes. * src/alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist, and make them unconditional now that they're heap-allocated. * src/bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase and Bpophandler. (bcall0): New function. (exec_byte_code): Add corresponding cases. Improve error message when encountering an invalid byte-code. Let Bunwind_protect accept a function (rather than a list of expressions) as argument. * src/eval.c (catchlist): Remove (merge with handlerlist). (handlerlist, lisp_eval_depth): Not static any more. (internal_catch, internal_condition_case, internal_condition_case_1) (internal_condition_case_2, internal_condition_case_n): Use PUSH_HANDLER. (unwind_to_catch, Fthrow, Fsignal): Adjust to merged handlerlist/catchlist. (internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new handlerlist which can only handle a single condition-case handler at a time. (find_handler_clause): Simplify since we only a single branch here any more. * src/lisp.h (struct handler): Merge struct handler and struct catchtag. (PUSH_HANDLER): New macro. (catchlist): Remove. (handlerlist): Always declare.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog24
-rw-r--r--lisp/emacs-lisp/byte-opt.el32
-rw-r--r--lisp/emacs-lisp/bytecomp.el104
-rw-r--r--lisp/emacs-lisp/cconv.el63
4 files changed, 190 insertions, 33 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a0eeb4a47bd..90158b85b4d 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,29 @@
12013-10-03 Stefan Monnier <monnier@iro.umontreal.ca> 12013-10-03 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for
4 the new compilation scheme using the new byte-codes.
5
6 * emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase)
7 (byte-pophandler): New byte codes.
8 (byte-goto-ops): Adjust accordingly.
9 (byte-compile--use-old-handlers): New var.
10 (byte-compile-catch): Use new byte codes depending on
11 byte-compile--use-old-handlers.
12 (byte-compile-condition-case--old): Rename from
13 byte-compile-condition-case.
14 (byte-compile-condition-case--new): New function.
15 (byte-compile-condition-case): New function that dispatches depending
16 on byte-compile--use-old-handlers.
17 (byte-compile-unwind-protect): Pass a function to byte-unwind-protect
18 when we can.
19
20 * emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
21 Optimize under `condition-case' and `catch' if
22 byte-compile--use-old-handlers is nil.
23 (disassemble-offset): Handle new bytecodes.
24
252013-10-03 Stefan Monnier <monnier@iro.umontreal.ca>
26
3 * subr.el (error): Use `declare'. 27 * subr.el (error): Use `declare'.
4 (decode-char, encode-char): Use advertised-calling-convention instead 28 (decode-char, encode-char): Use advertised-calling-convention instead
5 of the docstring to discourage use of the `restriction' arg. 29 of the docstring to discourage use of the `restriction' arg.
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 9da1a4d1f38..14293e3c0df 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -488,11 +488,22 @@
488 (prin1-to-string form)) 488 (prin1-to-string form))
489 nil) 489 nil)
490 490
491 ((memq fn '(function condition-case)) 491 ((eq fn 'function)
492 ;; These forms are compiled as constants or by breaking out 492 ;; This forms is compiled as constant or by breaking out
493 ;; all the subexpressions and compiling them separately. 493 ;; all the subexpressions and compiling them separately.
494 form) 494 form)
495 495
496 ((eq fn 'condition-case)
497 (if byte-compile--use-old-handlers
498 ;; Will be optimized later.
499 form
500 `(condition-case ,(nth 1 form) ;Not evaluated.
501 ,(byte-optimize-form (nth 2 form) for-effect)
502 ,@(mapcar (lambda (clause)
503 `(,(car clause)
504 ,@(byte-optimize-body (cdr clause) for-effect)))
505 (nthcdr 3 form)))))
506
496 ((eq fn 'unwind-protect) 507 ((eq fn 'unwind-protect)
497 ;; the "protected" part of an unwind-protect is compiled (and thus 508 ;; the "protected" part of an unwind-protect is compiled (and thus
498 ;; optimized) as a top-level form, so don't do it here. But the 509 ;; optimized) as a top-level form, so don't do it here. But the
@@ -504,13 +515,14 @@
504 (cdr (cdr form))))) 515 (cdr (cdr form)))))
505 516
506 ((eq fn 'catch) 517 ((eq fn 'catch)
507 ;; the body of a catch is compiled (and thus optimized) as a
508 ;; top-level form, so don't do it here. The tag is never
509 ;; for-effect. The body should have the same for-effect status
510 ;; as the catch form itself, but that isn't handled properly yet.
511 (cons fn 518 (cons fn
512 (cons (byte-optimize-form (nth 1 form) nil) 519 (cons (byte-optimize-form (nth 1 form) nil)
513 (cdr (cdr form))))) 520 (if byte-compile--use-old-handlers
521 ;; The body of a catch is compiled (and thus
522 ;; optimized) as a top-level form, so don't do it
523 ;; here.
524 (cdr (cdr form))
525 (byte-optimize-body (cdr form) for-effect)))))
514 526
515 ((eq fn 'ignore) 527 ((eq fn 'ignore)
516 ;; Don't treat the args to `ignore' as being 528 ;; Don't treat the args to `ignore' as being
@@ -1292,7 +1304,7 @@
1292 "Don't call this!" 1304 "Don't call this!"
1293 ;; Fetch and return the offset for the current opcode. 1305 ;; Fetch and return the offset for the current opcode.
1294 ;; Return nil if this opcode has no offset. 1306 ;; Return nil if this opcode has no offset.
1295 (cond ((< bytedecomp-op byte-nth) 1307 (cond ((< bytedecomp-op byte-pophandler)
1296 (let ((tem (logand bytedecomp-op 7))) 1308 (let ((tem (logand bytedecomp-op 7)))
1297 (setq bytedecomp-op (logand bytedecomp-op 248)) 1309 (setq bytedecomp-op (logand bytedecomp-op 248))
1298 (cond ((eq tem 6) 1310 (cond ((eq tem 6)
@@ -1311,7 +1323,9 @@
1311 (setq bytedecomp-op byte-constant))) 1323 (setq bytedecomp-op byte-constant)))
1312 ((or (and (>= bytedecomp-op byte-constant2) 1324 ((or (and (>= bytedecomp-op byte-constant2)
1313 (<= bytedecomp-op byte-goto-if-not-nil-else-pop)) 1325 (<= bytedecomp-op byte-goto-if-not-nil-else-pop))
1314 (= bytedecomp-op byte-stack-set2)) 1326 (memq bytedecomp-op (eval-when-compile
1327 (list byte-stack-set2 byte-pushcatch
1328 byte-pushconditioncase))))
1315 ;; Offset in next 2 bytes. 1329 ;; Offset in next 2 bytes.
1316 (setq bytedecomp-ptr (1+ bytedecomp-ptr)) 1330 (setq bytedecomp-ptr (1+ bytedecomp-ptr))
1317 (+ (aref bytes bytedecomp-ptr) 1331 (+ (aref bytes bytedecomp-ptr)
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 164cdb12952..35c7c391870 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -535,7 +535,13 @@ Each element is (INDEX . VALUE)")
535(byte-defop 40 0 byte-unbind "for unbinding special bindings") 535(byte-defop 40 0 byte-unbind "for unbinding special bindings")
536;; codes 8-47 are consumed by the preceding opcodes 536;; codes 8-47 are consumed by the preceding opcodes
537 537
538;; unused: 48-55 538;; New (in Emacs-24.4) bytecodes for more efficient handling of non-local exits
539;; (especially useful in lexical-binding code).
540(byte-defop 48 0 byte-pophandler)
541(byte-defop 50 -1 byte-pushcatch)
542(byte-defop 49 -1 byte-pushconditioncase)
543
544;; unused: 51-55
539 545
540(byte-defop 56 -1 byte-nth) 546(byte-defop 56 -1 byte-nth)
541(byte-defop 57 0 byte-symbolp) 547(byte-defop 57 0 byte-symbolp)
@@ -707,7 +713,8 @@ otherwise pop it")
707 713
708(defconst byte-goto-ops '(byte-goto byte-goto-if-nil byte-goto-if-not-nil 714(defconst byte-goto-ops '(byte-goto byte-goto-if-nil byte-goto-if-not-nil
709 byte-goto-if-nil-else-pop 715 byte-goto-if-nil-else-pop
710 byte-goto-if-not-nil-else-pop) 716 byte-goto-if-not-nil-else-pop
717 byte-pushcatch byte-pushconditioncase)
711 "List of byte-codes whose offset is a pc.") 718 "List of byte-codes whose offset is a pc.")
712 719
713(defconst byte-goto-always-pop-ops '(byte-goto-if-nil byte-goto-if-not-nil)) 720(defconst byte-goto-always-pop-ops '(byte-goto-if-nil byte-goto-if-not-nil))
@@ -4028,23 +4035,35 @@ binding slots have been popped."
4028;; (byte-defop-compiler-1 with-output-to-temp-buffer) ;Obsolete: now a macro. 4035;; (byte-defop-compiler-1 with-output-to-temp-buffer) ;Obsolete: now a macro.
4029(byte-defop-compiler-1 track-mouse) 4036(byte-defop-compiler-1 track-mouse)
4030 4037
4038(defvar byte-compile--use-old-handlers t
4039 "If nil, use new byte codes introduced in Emacs-24.4.")
4040
4031(defun byte-compile-catch (form) 4041(defun byte-compile-catch (form)
4032 (byte-compile-form (car (cdr form))) 4042 (byte-compile-form (car (cdr form)))
4033 (pcase (cddr form) 4043 (if (not byte-compile--use-old-handlers)
4034 (`(:fun-body ,f) 4044 (let ((endtag (byte-compile-make-tag)))
4035 (byte-compile-form `(list 'funcall ,f))) 4045 (byte-compile-goto 'byte-pushcatch endtag)
4036 (body 4046 (byte-compile-body (cddr form) nil)
4037 (byte-compile-push-constant 4047 (byte-compile-out 'byte-pophandler)
4038 (byte-compile-top-level (cons 'progn body) byte-compile--for-effect)))) 4048 (byte-compile-out-tag endtag))
4039 (byte-compile-out 'byte-catch 0)) 4049 (pcase (cddr form)
4050 (`(:fun-body ,f)
4051 (byte-compile-form `(list 'funcall ,f)))
4052 (body
4053 (byte-compile-push-constant
4054 (byte-compile-top-level (cons 'progn body) byte-compile--for-effect))))
4055 (byte-compile-out 'byte-catch 0)))
4040 4056
4041(defun byte-compile-unwind-protect (form) 4057(defun byte-compile-unwind-protect (form)
4042 (pcase (cddr form) 4058 (pcase (cddr form)
4043 (`(:fun-body ,f) 4059 (`(:fun-body ,f)
4044 (byte-compile-form `(list (list 'funcall ,f)))) 4060 (byte-compile-form
4061 (if byte-compile--use-old-handlers `(list (list 'funcall ,f)) f)))
4045 (handlers 4062 (handlers
4046 (byte-compile-push-constant 4063 (if byte-compile--use-old-handlers
4047 (byte-compile-top-level-body handlers t)))) 4064 (byte-compile-push-constant
4065 (byte-compile-top-level-body handlers t))
4066 (byte-compile-form `#'(lambda () ,@handlers)))))
4048 (byte-compile-out 'byte-unwind-protect 0) 4067 (byte-compile-out 'byte-unwind-protect 0)
4049 (byte-compile-form-do-effect (car (cdr form))) 4068 (byte-compile-form-do-effect (car (cdr form)))
4050 (byte-compile-out 'byte-unbind 1)) 4069 (byte-compile-out 'byte-unbind 1))
@@ -4056,6 +4075,11 @@ binding slots have been popped."
4056 (_ `(eval '(track-mouse ,@(byte-compile-top-level-body (cdr form)))))))) 4075 (_ `(eval '(track-mouse ,@(byte-compile-top-level-body (cdr form))))))))
4057 4076
4058(defun byte-compile-condition-case (form) 4077(defun byte-compile-condition-case (form)
4078 (if byte-compile--use-old-handlers
4079 (byte-compile-condition-case--old form)
4080 (byte-compile-condition-case--new form)))
4081
4082(defun byte-compile-condition-case--old (form)
4059 (let* ((var (nth 1 form)) 4083 (let* ((var (nth 1 form))
4060 (fun-bodies (eq var :fun-body)) 4084 (fun-bodies (eq var :fun-body))
4061 (byte-compile-bound-variables 4085 (byte-compile-bound-variables
@@ -4106,6 +4130,62 @@ binding slots have been popped."
4106 (byte-compile-push-constant compiled-clauses))) 4130 (byte-compile-push-constant compiled-clauses)))
4107 (byte-compile-out 'byte-condition-case 0))) 4131 (byte-compile-out 'byte-condition-case 0)))
4108 4132
4133(defun byte-compile-condition-case--new (form)
4134 (let* ((var (nth 1 form))
4135 (body (nth 2 form))
4136 (depth byte-compile-depth)
4137 (clauses (mapcar (lambda (clause)
4138 (cons (byte-compile-make-tag) clause))
4139 (nthcdr 3 form)))
4140 (endtag (byte-compile-make-tag)))
4141 (byte-compile-set-symbol-position 'condition-case)
4142 (unless (symbolp var)
4143 (byte-compile-warn
4144 "`%s' is not a variable-name or nil (in condition-case)" var))
4145
4146 (dolist (clause (reverse clauses))
4147 (let ((condition (nth 1 clause)))
4148 (unless (consp condition) (setq condition (list condition)))
4149 (dolist (c condition)
4150 (unless (and c (symbolp c))
4151 (byte-compile-warn
4152 "`%S' is not a condition name (in condition-case)" c))
4153 ;; In reality, the `error-conditions' property is only required
4154 ;; for the argument to `signal', not to `condition-case'.
4155 ;;(unless (consp (get c 'error-conditions))
4156 ;; (byte-compile-warn
4157 ;; "`%s' is not a known condition name (in condition-case)"
4158 ;; c))
4159 )
4160 (byte-compile-push-constant condition))
4161 (byte-compile-goto 'byte-pushconditioncase (car clause)))
4162
4163 (byte-compile-form body) ;; byte-compile--for-effect
4164 (dolist (_ clauses) (byte-compile-out 'byte-pophandler))
4165 (byte-compile-goto 'byte-goto endtag)
4166
4167 (while clauses
4168 (let ((clause (pop clauses))
4169 (byte-compile-bound-variables byte-compile-bound-variables)
4170 (byte-compile--lexical-environment
4171 byte-compile--lexical-environment))
4172 (setq byte-compile-depth (1+ depth))
4173 (byte-compile-out-tag (pop clause))
4174 (dolist (_ clauses) (byte-compile-out 'byte-pophandler))
4175 (cond
4176 ((null var) (byte-compile-discard))
4177 (lexical-binding
4178 (push (cons var (1- byte-compile-depth))
4179 byte-compile--lexical-environment))
4180 (t (byte-compile-dynamic-variable-bind var)))
4181 (byte-compile-body (cdr clause)) ;; byte-compile--for-effect
4182 (cond
4183 ((null var) nil)
4184 (lexical-binding (byte-compile-discard 1 'preserve-tos))
4185 (t (byte-compile-out 'byte-unbind 1)))
4186 (byte-compile-goto 'byte-goto endtag)))
4187
4188 (byte-compile-out-tag endtag)))
4109 4189
4110(defun byte-compile-save-excursion (form) 4190(defun byte-compile-save-excursion (form)
4111 (if (and (eq 'set-buffer (car-safe (car-safe (cdr form)))) 4191 (if (and (eq 'set-buffer (car-safe (car-safe (cdr form))))
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index c655c2fff84..f24e503fd6d 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -79,8 +79,7 @@
79;; command-history). 79;; command-history).
80;; - canonize code in macro-expand so we don't have to handle (let (var) body) 80;; - canonize code in macro-expand so we don't have to handle (let (var) body)
81;; and other oddities. 81;; and other oddities.
82;; - new byte codes for unwind-protect, catch, and condition-case so that 82;; - new byte codes for unwind-protect so that closures aren't needed at all.
83;; closures aren't needed at all.
84;; - a reference to a var that is known statically to always hold a constant 83;; - a reference to a var that is known statically to always hold a constant
85;; should be turned into a byte-constant rather than a byte-stack-ref. 84;; should be turned into a byte-constant rather than a byte-stack-ref.
86;; Hmm... right, that's called constant propagation and could be done here, 85;; Hmm... right, that's called constant propagation and could be done here,
@@ -421,18 +420,42 @@ places where they originally did not directly appear."
421 forms))) 420 forms)))
422 421
423 ;condition-case 422 ;condition-case
424 (`(condition-case ,var ,protected-form . ,handlers) 423 ((and `(condition-case ,var ,protected-form . ,handlers)
424 (guard byte-compile--use-old-handlers))
425 (let ((newform (cconv--convert-function 425 (let ((newform (cconv--convert-function
426 () (list protected-form) env form))) 426 () (list protected-form) env form)))
427 `(condition-case :fun-body ,newform 427 `(condition-case :fun-body ,newform
428 ,@(mapcar (lambda (handler) 428 ,@(mapcar (lambda (handler)
429 (list (car handler) 429 (list (car handler)
430 (cconv--convert-function 430 (cconv--convert-function
431 (list (or var cconv--dummy-var)) 431 (list (or var cconv--dummy-var))
432 (cdr handler) env form))) 432 (cdr handler) env form)))
433 handlers)))) 433 handlers))))
434 434
435 (`(,(and head (or `catch `unwind-protect)) ,form . ,body) 435 ; condition-case with new byte-codes.
436 (`(condition-case ,var ,protected-form . ,handlers)
437 `(condition-case ,var
438 ,(cconv-convert protected-form env extend)
439 ,@(let* ((cm (and var (member (cons (list var) form)
440 cconv-captured+mutated)))
441 (newenv
442 (cond (cm (cons `(,var . (car-save ,var)) env))
443 ((assq var env) (cons `(,var) env))
444 (t env))))
445 (mapcar
446 (lambda (handler)
447 `(,(car handler)
448 ,@(let ((body
449 (mapcar (lambda (form)
450 (cconv-convert form newenv extend))
451 (cdr handler))))
452 (if (not cm) body
453 `((let ((,var (list ,var))) ,@body))))))
454 handlers))))
455
456 (`(,(and head (or (and `catch (guard byte-compile--use-old-handlers))
457 `unwind-protect))
458 ,form . ,body)
436 `(,head ,(cconv-convert form env extend) 459 `(,head ,(cconv-convert form env extend)
437 :fun-body ,(cconv--convert-function () body env form))) 460 :fun-body ,(cconv--convert-function () body env form)))
438 461
@@ -491,7 +514,7 @@ places where they originally did not directly appear."
491 514
492 (`(,func . ,forms) 515 (`(,func . ,forms)
493 ;; First element is function or whatever function-like forms are: or, and, 516 ;; First element is function or whatever function-like forms are: or, and,
494 ;; if, progn, prog1, prog2, while, until 517 ;; if, catch, progn, prog1, prog2, while, until
495 `(,func . ,(mapcar (lambda (form) 518 `(,func . ,(mapcar (lambda (form)
496 (cconv-convert form env extend)) 519 (cconv-convert form env extend))
497 forms))) 520 forms)))
@@ -646,16 +669,32 @@ and updates the data stored in ENV."
646 (`(quote . ,_) nil) ; quote form 669 (`(quote . ,_) nil) ; quote form
647 (`(function . ,_) nil) ; same as quote 670 (`(function . ,_) nil) ; same as quote
648 671
649 (`(condition-case ,var ,protected-form . ,handlers) 672 ((and `(condition-case ,var ,protected-form . ,handlers)
673 (guard byte-compile--use-old-handlers))
650 ;; FIXME: The bytecode for condition-case forces us to wrap the 674 ;; FIXME: The bytecode for condition-case forces us to wrap the
651 ;; form and handlers in closures (for handlers, it's understandable 675 ;; form and handlers in closures.
652 ;; but not for the protected form).
653 (cconv--analyse-function () (list protected-form) env form) 676 (cconv--analyse-function () (list protected-form) env form)
654 (dolist (handler handlers) 677 (dolist (handler handlers)
655 (cconv--analyse-function (if var (list var)) (cdr handler) env form))) 678 (cconv--analyse-function (if var (list var)) (cdr handler)
679 env form)))
656 680
657 ;; FIXME: The bytecode for catch forces us to wrap the body. 681 (`(condition-case ,var ,protected-form . ,handlers)
658 (`(,(or `catch `unwind-protect) ,form . ,body) 682 (cconv-analyse-form protected-form env)
683 (when (and var (symbolp var) (byte-compile-not-lexical-var-p var))
684 (byte-compile-log-warning
685 (format "Lexical variable shadows the dynamic variable %S" var)))
686 (let* ((varstruct (list var nil nil nil nil)))
687 (if var (push varstruct env))
688 (dolist (handler handlers)
689 (dolist (form (cdr handler))
690 (cconv-analyse-form form env)))
691 (if var (cconv--analyse-use (cons (list var) (cdr varstruct))
692 form "variable"))))
693
694 ;; FIXME: The bytecode for unwind-protect forces us to wrap the unwind.
695 (`(,(or (and `catch (guard byte-compile--use-old-handlers))
696 `unwind-protect)
697 ,form . ,body)
659 (cconv-analyse-form form env) 698 (cconv-analyse-form form env)
660 (cconv--analyse-function () body env form)) 699 (cconv--analyse-function () body env form))
661 700