diff options
| author | Stefan Monnier | 2013-10-03 00:58:56 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-10-03 00:58:56 -0400 |
| commit | adf2aa61404305e58e71cde0193bb650aff2c4b3 (patch) | |
| tree | d6e6b4e5ab3b144a94daed2232cab798aadeb20a /lisp | |
| parent | 328a8179fec33f5a75e2cfe22e43f4ec0df770b7 (diff) | |
| download | emacs-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/ChangeLog | 24 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 32 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 104 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 63 |
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 @@ | |||
| 1 | 2013-10-03 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2013-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 | |||
| 25 | 2013-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 | ||